ebe5fc1df9137e7a1a4cedb894910c69d89d15df
[coreboot.git] / src / devices / emulator / biosemu.c
1 #include <arch/io.h>
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>
7
8 #include <x86emu/x86emu.h>
9
10 #include "pcbios/pcibios.h"
11
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)
15
16 #define MEM_RB(where) rdb(where)
17 #define MEM_RW(where) rdw(where)
18 #define MEM_RL(where) rdl(where)
19
20 u8 x_inb(u16 port);
21 u16 x_inw(u16 port);
22 void x_outb(u16 port, u8 val);
23 void x_outw(u16 port, u16 val);
24 u32 x_inl(u16 port);
25 void x_outl(u16 port, u32 val);
26
27
28 // sys.c
29 void X86EMU_setMemBase(void *base, size_t size);
30
31 /* general software interrupt handler */
32 u32 getIntVect(int num)
33 {
34         return MEM_RW(num << 2) + (MEM_RW((num << 2) + 2) << 4);
35 }
36
37 /* FixME: There is already a push_word() in the emulator */
38 void pushw(u16 val)
39 {
40         X86_ESP -= 2;
41         MEM_WW(((u32) X86_SS << 4) + X86_SP, val);
42 }
43
44 int run_bios_int(int num)
45 {
46         u32 eflags;
47
48         eflags = X86_EFLAGS;
49         pushw(eflags);
50         pushw(X86_CS);
51         pushw(X86_IP);
52         X86_CS = MEM_RW((num << 2) + 2);
53         X86_IP = MEM_RW(num << 2);
54
55         return 1;
56 }
57
58 u8 x_inb(u16 port)
59 {
60         u8 val;
61
62         val = inb(port);
63
64         //if (port != 0x40)
65         //    printk_debug("inb(0x%04x) = 0x%02x\n", port, val);
66
67         return val;
68 }
69
70 u16 x_inw(u16 port)
71 {
72         u16 val;
73
74         val = inw(port);
75
76         //printk_debug("inw(0x%04x) = 0x%04x\n", port, val);
77         return val;
78 }
79
80 u32 x_inl(u16 port)
81 {
82         u32 val;
83
84         val = inl(port);
85
86         //printk_debug("inl(0x%04x) = 0x%08x\n", port, val);
87         return val;
88 }
89
90 void x_outb(u16 port, u8 val)
91 {
92         //if (port != 0x43)
93         //      printk_debug("outb(0x%02x, 0x%04x)\n", val, port);
94         outb(val, port);
95 }
96
97 void x_outw(u16 port, u16 val)
98 {
99         //printk_debug("outw(0x%04x, 0x%04x)\n", val, port);
100         outw(val, port);
101 }
102
103 void x_outl(u16 port, u32 val)
104 {
105         //printk_debug("outl(0x%08x, 0x%04x)\n", val, port);
106         outl(val, port);
107 }
108
109 X86EMU_pioFuncs myfuncs = {
110         x_inb, x_inw, x_inl,
111         x_outb, x_outw, x_outl
112 };
113
114
115
116 /* Interrupt multiplexer */
117
118 void do_int(int num)
119 {
120         int ret = 0;
121
122 //      printk_debug("int%x vector at %x\n", num, getIntVect(num));
123
124         switch (num) {
125 #ifndef _PC
126         case 0x10:
127         case 0x42:
128         case 0x6D:
129                 if (getIntVect(num) == 0x0000) {
130                         printk_debug("un-inited int vector\n");
131                         ret = 1;
132                 }
133                 if (getIntVect(num) == 0xFF065) {
134                         //ret = int42_handler();
135                         ret = 1;
136                 }
137                 break;
138 #endif
139         case 0x15:
140                 //ret = int15_handler();
141                 ret = 1;
142                 break;
143         case 0x16:
144                 //ret = int16_handler();
145                 ret = 0;
146                 break;
147         case 0x1A:
148                 ret = pcibios_handler();
149                 ret = 1;
150                 break;
151         case 0xe6:
152                 //ret = intE6_handler();
153                 ret = 0;
154                 break;
155         default:
156                 break;
157         }
158
159         if (!ret)
160                 ret = run_bios_int(num);
161
162 }
163 #if 0
164 #define SYS_BIOS 0xf0000
165 /*
166  * here we are really paranoid about faking a "real"
167  * BIOS. Most of this information was pulled from
168  * dosemu.
169  */
170 #if 0
171 void setup_int_vect(void)
172 {
173         int i;
174
175         /* let the int vects point to the SYS_BIOS seg */
176         for (i = 0; i < 0x80; i++) {
177                 MEM_WW(i << 2, 0);
178                 MEM_WW((i << 2) + 2, SYS_BIOS >> 4);
179         }
180
181         reset_int_vect();
182
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);
205
206         /* Set Equipment flag to VGA */
207         i = MEM_RB(0x0410) & 0xCF;
208         MEM_WB(0x0410, i);
209         /* XXX Perhaps setup more of the BDA here.  See also int42(0x00). */
210 }
211
212 int setup_system_bios(void *base_addr)
213 {
214         char *base = (char *) base_addr;
215
216         /*
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
220          */
221         memset(base, 0xf4, 0x10000);
222
223         /* set bios date */
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;
229
230         return 1;
231 }
232 #endif
233
234 void reset_int_vect(void)
235 {
236         /*
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.
241          */
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,
264                 /* Padding */
265                 0x00, 0x00, 0x00, 0x00
266         };
267         int i;
268
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);
273
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);
281 }
282 #endif
283 void run_bios(struct device * dev, unsigned long addr)
284 {
285 #if 1
286         int i;
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];
291
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);
297
298         {
299                 char *date = "01/01/99";
300                 for (i = 0; date[i]; i++)
301                         wrb(0xffff5 + i, date[i]);
302                 wrb(0xffff7, '/');
303                 wrb(0xffffa, '/');
304         }
305
306         {
307             /* FixME: move PIT init to its own file */
308             outb(0x36, 0x43);
309             outb(0x00, 0x40);
310             outb(0x00, 0x40);
311         }
312         //setup_int_vect();
313
314         /* cpu setup */
315         X86_AX = devfn ? devfn : 0xff;
316         X86_DX = 0x80;
317         X86_EIP = initialip;
318         X86_CS = initialcs;
319
320         /* Initialize stack and data segment */
321         X86_SS = initialcs;
322         X86_SP = 0xfffe;
323         X86_DS = 0x0040;
324         X86_ES = 0x0000;
325
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.
329          */
330         pushw(0xf4f4);          /* hlt; hlt */
331         pushw(X86_SS);
332         pushw(X86_SP + 2);
333
334 //      X86EMU_trace_on();
335
336         printk_info("entering emulator\n");
337
338         X86EMU_exec();
339 #endif
340 }