2 #include <console/console.h>
3 #include <device/device.h>
4 #include <device/pci.h>
5 #include <device/pci_ids.h>
6 #include <device/pci_ops.h>
8 #include <x86emu/x86emu.h>
10 #include "pcbios/pcibios.h"
12 #define MEM_WB(where, what) wrb(where, what)
13 #define MEM_WW(where, what) wrw(where, what)
14 #define MEM_WL(where, what) wrl(where, what)
16 #define MEM_RB(where) rdb(where)
17 #define MEM_RW(where) rdw(where)
18 #define MEM_RL(where) rdl(where)
22 void x_outb(u16 port, u8 val);
23 void x_outw(u16 port, u16 val);
25 void x_outl(u16 port, u32 val);
29 void X86EMU_setMemBase(void *base, size_t size);
31 /* general software interrupt handler */
32 u32 getIntVect(int num)
34 return MEM_RW(num << 2) + (MEM_RW((num << 2) + 2) << 4);
37 /* FixME: There is already a push_word() in the emulator */
41 MEM_WW(((u32) X86_SS << 4) + X86_SP, val);
44 int run_bios_int(int num)
52 X86_CS = MEM_RW((num << 2) + 2);
53 X86_IP = MEM_RW(num << 2);
65 // printk_debug("inb(0x%04x) = 0x%02x\n", port, val);
76 //printk_debug("inw(0x%04x) = 0x%04x\n", port, val);
86 //printk_debug("inl(0x%04x) = 0x%08x\n", port, val);
90 void x_outb(u16 port, u8 val)
93 // printk_debug("outb(0x%02x, 0x%04x)\n", val, port);
97 void x_outw(u16 port, u16 val)
99 //printk_debug("outw(0x%04x, 0x%04x)\n", val, port);
103 void x_outl(u16 port, u32 val)
105 //printk_debug("outl(0x%08x, 0x%04x)\n", val, port);
109 X86EMU_pioFuncs myfuncs = {
111 x_outb, x_outw, x_outl
116 /* Interrupt multiplexer */
122 // printk_debug("int%x vector at %x\n", num, getIntVect(num));
129 if (getIntVect(num) == 0x0000) {
130 printk_debug("un-inited int vector\n");
133 if (getIntVect(num) == 0xFF065) {
134 //ret = int42_handler();
140 //ret = int15_handler();
144 //ret = int16_handler();
148 ret = pcibios_handler();
152 //ret = intE6_handler();
160 ret = run_bios_int(num);
164 #define SYS_BIOS 0xf0000
166 * here we are really paranoid about faking a "real"
167 * BIOS. Most of this information was pulled from
171 void setup_int_vect(void)
175 /* let the int vects point to the SYS_BIOS seg */
176 for (i = 0; i < 0x80; i++) {
178 MEM_WW((i << 2) + 2, SYS_BIOS >> 4);
183 /* font tables default location (int 1F) */
184 MEM_WW(0x1f << 2, 0xfa6e);
185 /* int 11 default location (Get Equipment Configuration) */
186 MEM_WW(0x11 << 2, 0xf84d);
187 /* int 12 default location (Get Conventional Memory Size) */
188 MEM_WW(0x12 << 2, 0xf841);
189 /* int 15 default location (I/O System Extensions) */
190 MEM_WW(0x15 << 2, 0xf859);
191 /* int 1A default location (RTC, PCI and others) */
192 MEM_WW(0x1a << 2, 0xff6e);
193 /* int 05 default location (Bound Exceeded) */
194 MEM_WW(0x05 << 2, 0xff54);
195 /* int 08 default location (Double Fault) */
196 MEM_WW(0x08 << 2, 0xfea5);
197 /* int 13 default location (Disk) */
198 MEM_WW(0x13 << 2, 0xec59);
199 /* int 0E default location (Page Fault) */
200 MEM_WW(0x0e << 2, 0xef57);
201 /* int 17 default location (Parallel Port) */
202 MEM_WW(0x17 << 2, 0xefd2);
203 /* fdd table default location (int 1e) */
204 MEM_WW(0x1e << 2, 0xefc7);
206 /* Set Equipment flag to VGA */
207 i = MEM_RB(0x0410) & 0xCF;
209 /* XXX Perhaps setup more of the BDA here. See also int42(0x00). */
212 int setup_system_bios(void *base_addr)
214 char *base = (char *) base_addr;
217 * we trap the "industry standard entry points" to the BIOS
218 * and all other locations by filling them with "hlt"
219 * TODO: implement hlt-handler for these
221 memset(base, 0xf4, 0x10000);
224 //strcpy(base + 0x0FFF5, "06/11/99");
225 /* set up eisa ident string */
226 //strcpy(base + 0x0FFD9, "PCI_ISA");
227 /* write system model id for IBM-AT */
228 //*((unsigned char *) (base + 0x0FFFE)) = 0xfc;
234 void reset_int_vect(void)
237 * This table is normally located at 0xF000:0xF0A4. However, int 0x42,
238 * function 0 (Mode Set) expects it (or a copy) somewhere in the bottom
239 * 64kB. Note that because this data doesn't survive POST, int 0x42 should
240 * only be used during EGA/VGA BIOS initialisation.
242 static const u8 VideoParms[] = {
243 /* Timing for modes 0x00 & 0x01 */
244 0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c,
245 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
246 /* Timing for modes 0x02 & 0x03 */
247 0x71, 0x50, 0x5a, 0x0a, 0x1f, 0x06, 0x19, 0x1c,
248 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
249 /* Timing for modes 0x04, 0x05 & 0x06 */
250 0x38, 0x28, 0x2d, 0x0a, 0x7f, 0x06, 0x64, 0x70,
251 0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
252 /* Timing for mode 0x07 */
253 0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19,
254 0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
255 /* Display page lengths in little endian order */
256 0x00, 0x08, /* Modes 0x00 and 0x01 */
257 0x00, 0x10, /* Modes 0x02 and 0x03 */
258 0x00, 0x40, /* Modes 0x04 and 0x05 */
259 0x00, 0x40, /* Modes 0x06 and 0x07 */
260 /* Number of columns for each mode */
261 40, 40, 80, 80, 40, 40, 80, 80,
262 /* CGA Mode register value for each mode */
263 0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29,
265 0x00, 0x00, 0x00, 0x00
269 for (i = 0; i < sizeof(VideoParms); i++)
270 MEM_WB(i + (0x1000 - sizeof(VideoParms)), VideoParms[i]);
271 MEM_WW(0x1d << 2, 0x1000 - sizeof(VideoParms));
272 MEM_WW((0x1d << 2) + 2, 0);
274 printk_debug("SETUP INT\n");
275 MEM_WW(0x10 << 2, 0xf065);
276 MEM_WW((0x10 << 2) + 2, SYS_BIOS >> 4);
277 MEM_WW(0x42 << 2, 0xf065);
278 MEM_WW((0x42 << 2) + 2, SYS_BIOS >> 4);
279 MEM_WW(0x6D << 2, 0xf065);
280 MEM_WW((0x6D << 2) + 2, SYS_BIOS >> 4);
283 void run_bios(struct device * dev, unsigned long addr)
287 unsigned short initialcs = (addr & 0xF0000) >> 4;
288 unsigned short initialip = (addr + 3) & 0xFFFF;
289 unsigned short devfn = dev->bus->secondary << 8 | dev->path.pci.devfn;
290 X86EMU_intrFuncs intFuncs[256];
292 X86EMU_setMemBase(0, 0x100000);
293 X86EMU_setupPioFuncs(&myfuncs);
294 for (i = 0; i < 256; i++)
295 intFuncs[i] = do_int;
296 X86EMU_setupIntrFuncs(intFuncs);
299 char *date = "01/01/99";
300 for (i = 0; date[i]; i++)
301 wrb(0xffff5 + i, date[i]);
307 /* FixME: move PIT init to its own file */
315 X86_AX = devfn ? devfn : 0xff;
320 /* Initialize stack and data segment */
326 /* We need a sane way to return from bios
327 * execution. A hlt instruction and a pointer
328 * to it, both kept on the stack, will do.
330 pushw(0xf4f4); /* hlt; hlt */
334 // X86EMU_trace_on();
336 printk_info("entering emulator\n");