1. Change CONFIG_DEBUG to DEBUG in util/x86emu/*
[coreboot.git] / util / x86emu / biosemu.c
1 /*
2  * This software and ancillary information (herein called SOFTWARE )
3  * called LinuxBIOS          is made available under the terms described
4  * here.  The SOFTWARE has been approved for release with associated
5  * LA-CC Number 00-34   .  Unless otherwise indicated, this SOFTWARE has
6  * been authored by an employee or employees of the University of
7  * California, operator of the Los Alamos National Laboratory under
8  * Contract No. W-7405-ENG-36 with the U.S. Department of Energy.  The
9  * U.S. Government has rights to use, reproduce, and distribute this
10  * SOFTWARE.  The public may copy, distribute, prepare derivative works
11  * and publicly display this SOFTWARE without charge, provided that this
12  * Notice and any statement of authorship are reproduced on all copies.
13  * Neither the Government nor the University makes any warranty, express
14  * or implied, or assumes any liability or responsibility for the use of
15  * this SOFTWARE.  If SOFTWARE is modified to produce derivative works,
16  * such modified SOFTWARE should be clearly marked, so as not to confuse
17  * it with the version available from LANL.
18  */
19  /*
20  * This file is part of the coreboot project.
21  *
22  *  (c) Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
23  *  Copyright (C) 2009 coresystems GmbH
24  *
25  * This program is free software; you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by 
27  * the Free Software Foundation; either version 2 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with this program; if not, write to the Free Software
37  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
38  */
39 #include <string.h>
40 #include <arch/io.h>
41 #include <console/console.h>
42 #include <device/device.h>
43 #include <device/pci.h>
44 #include <device/pci_ids.h>
45 #include <device/pci_ops.h>
46 #include <x86emu/x86emu.h>
47 #include "x86emu/prim_ops.h"
48
49 #define DATA_SEGMENT 0x2000
50 #define STACK_SEGMENT 0x1000    //1000:xxxx
51 #define STACK_START_OFFSET 0xfffe
52 #define INITIAL_EBDA_SEGMENT 0xF600     // segment of the Extended BIOS Data Area
53 #define INITIAL_EBDA_SIZE 0x400 // size of the EBDA (at least 1KB!! since size is stored in KB!)
54
55 enum {
56         PCI_BIOS_PRESENT        = 0xB101,
57         FIND_PCI_DEVICE         = 0xB102,
58         FIND_PCI_CLASS_CODE     = 0xB103,
59         GENERATE_SPECIAL_CYCLE  = 0xB106,
60         READ_CONFIG_BYTE        = 0xB108,
61         READ_CONFIG_WORD        = 0xB109,
62         READ_CONFIG_DWORD       = 0xB10A,
63         WRITE_CONFIG_BYTE       = 0xB10B,
64         WRITE_CONFIG_WORD       = 0xB10C,
65         WRITE_CONFIG_DWORD      = 0xB10D,
66         GET_IRQ_ROUTING_OPTIONS = 0xB10E,
67         SET_PCI_IRQ             = 0xB10F
68 };
69
70 enum {
71         SUCCESSFUL              = 0x00,
72         FUNC_NOT_SUPPORTED      = 0x81,
73         BAD_VENDOR_ID           = 0x83,
74         DEVICE_NOT_FOUND        = 0x86,
75         BAD_REGISTER_NUMBER     = 0x87,
76         SET_FAILED              = 0x88,
77         BUFFER_TOO_SMALL        = 0x89
78 };
79
80 #define MEM_WB(where, what) wrb(where, what)
81 #define MEM_WW(where, what) wrw(where, what)
82 #define MEM_WL(where, what) wrl(where, what)
83
84 #define MEM_RB(where) rdb(where)
85 #define MEM_RW(where) rdw(where)
86 #define MEM_RL(where) rdl(where)
87
88 static u8 biosemu_inb(u16 port)
89 {
90         u8 val;
91
92         val = inb(port);
93 #ifdef DEBUG
94         if (port != 0x40)
95             printk("inb(0x%04x) = 0x%02x\n", port, val);
96 #endif
97
98         return val;
99 }
100
101 static u16 biosemu_inw(u16 port)
102 {
103         u16 val;
104
105         val = inw(port);
106
107 #ifdef DEBUG
108         printk("inw(0x%04x) = 0x%04x\n", port, val);
109 #endif
110         return val;
111 }
112
113 static u32 biosemu_inl(u16 port)
114 {
115         u32 val;
116
117         val = inl(port);
118
119 #ifdef DEBUG
120         printk("inl(0x%04x) = 0x%08x\n", port, val);
121 #endif
122         return val;
123 }
124
125 static void biosemu_outb(u16 port, u8 val)
126 {
127 #ifdef DEBUG
128         if (port != 0x43)
129                 printk("outb(0x%02x, 0x%04x)\n", val, port);
130 #endif
131         outb(val, port);
132 }
133
134 static void biosemu_outw(u16 port, u16 val)
135 {
136 #ifdef DEBUG
137         printk("outw(0x%04x, 0x%04x)\n", val, port);
138 #endif
139         outw(val, port);
140 }
141
142 static void biosemu_outl(u16 port, u32 val)
143 {
144 #ifdef DEBUG
145         printk("outl(0x%08x, 0x%04x)\n", val, port);
146 #endif
147         outl(val, port);
148 }
149
150 static X86EMU_pioFuncs biosemu_piofuncs = {
151         biosemu_inb,  biosemu_inw,  biosemu_inl,
152         biosemu_outb, biosemu_outw, biosemu_outl
153 };
154
155 /* Interrupt Handlers */
156
157 static int int15_handler(void)
158 {
159         /* This int15 handler is VIA Tech. and Intel specific. Other chipsets need other
160          * handlers. The right way to do this is to move this handler code into
161          * the mainboard or northbridge code.
162          */
163         switch (X86_AX) {
164         case 0x5f19:
165                 X86_EFLAGS |= FB_CF;    /* set carry flag */
166                 break;
167         case 0x5f18:
168                 X86_EAX = 0x5f;
169                 // MCLK = 133, 32M frame buffer, 256 M main memory
170                 X86_EBX = 0x545;
171                 X86_ECX = 0x060;
172                 X86_EFLAGS &= ~FB_CF;
173                 break;
174         case 0x5f00:
175                 X86_EAX = 0x8600;
176                 X86_EFLAGS |= FB_CF;    /* set carry flag */
177                 break;
178         case 0x5f01:
179                 X86_EAX = 0x5f;
180                 X86_ECX = (X86_ECX & 0xffffff00 ) | 2; // panel type =  2 = 1024 * 768
181                 X86_EFLAGS &= ~FB_CF;
182                 break;
183         case 0x5f02:
184                 X86_EAX = 0x5f;
185                 X86_EBX = (X86_EBX & 0xffff0000) | 2;
186                 X86_ECX = (X86_ECX & 0xffff0000) | 0x401;  // PAL + crt only
187                 X86_EDX = (X86_EDX & 0xffff0000) | 0;  // TV Layout - default
188                 X86_EFLAGS &= ~FB_CF;
189                 break;
190         case 0x5f0f:
191                 X86_EAX = 0x860f;
192                 X86_EFLAGS |= FB_CF;    /* set carry flag */
193                 break;
194         /* And now Intel IGD code */
195 #define BOOT_DISPLAY_DEFAULT    0
196 #define BOOT_DISPLAY_CRT        (1 << 0)
197 #define BOOT_DISPLAY_TV         (1 << 1)
198 #define BOOT_DISPLAY_EFP        (1 << 2)
199 #define BOOT_DISPLAY_LCD        (1 << 3)
200 #define BOOT_DISPLAY_CRT2       (1 << 4)
201 #define BOOT_DISPLAY_TV2        (1 << 5)
202 #define BOOT_DISPLAY_EFP2       (1 << 6)
203 #define BOOT_DISPLAY_LCD2       (1 << 7)
204
205         case 0x5f35:
206                 X86_EAX = 0x5f;
207                 X86_ECX = BOOT_DISPLAY_DEFAULT;
208                 X86_EFLAGS &= ~FB_CF;
209                 break;
210         case 0x5f40:
211                 X86_EAX = 0x5f;
212                 X86_ECX = 3; // This is mainboard specific
213                 printk("DISPLAY=%x\n", X86_ECX);
214                 X86_EFLAGS &= ~FB_CF;
215                 break;
216         default:
217                 printk("Unknown INT15 function %04x!\n", X86_AX);
218                 X86_EFLAGS |= FB_CF;    /* set carry flag */
219         }
220
221         return 1;
222 }
223
224 static int int1a_handler(void)
225 {
226         int ret = 0;
227         struct device *dev = 0;
228
229         switch (X86_AX) {
230         case PCI_BIOS_PRESENT:
231                 X86_AH  = 0x00;         /* no config space/special cycle support */
232                 X86_AL  = 0x01;         /* config mechanism 1 */
233                 X86_EDX = 'P' | 'C' << 8 | 'I' << 16 | ' ' << 24;
234                 X86_EBX = 0x0210;       /* Version 2.10 */
235                 X86_ECX = 0xFF00;       /* FIXME: Max bus number */
236                 X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
237                 ret = 1;
238                 break;
239         case FIND_PCI_DEVICE:
240                 /* FIXME: support SI != 0 */
241                 dev = dev_find_device(X86_DX, X86_CX, dev);
242                 if (dev != 0) {
243                         X86_BH = dev->bus->secondary;
244                         X86_BL = dev->path.pci.devfn;
245                         X86_AH = SUCCESSFUL;
246                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
247                         ret = 1;
248                 } else {
249                         X86_AH = DEVICE_NOT_FOUND;
250                         X86_EFLAGS |= FB_CF;    /* set carry flag */
251                         ret = 0;
252                 }
253                 break;
254         case FIND_PCI_CLASS_CODE:
255                 /* FixME: support SI != 0 */
256                 dev = dev_find_class(X86_ECX, dev);
257                 if (dev != 0) {
258                         X86_BH = dev->bus->secondary;
259                         X86_BL = dev->path.pci.devfn;
260                         X86_AH = SUCCESSFUL;
261                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
262                         ret = 1;
263                 } else {
264                         X86_AH = DEVICE_NOT_FOUND;
265                         X86_EFLAGS |= FB_CF;    /* set carry flag */
266                         ret = 0;
267                 }
268                 break;
269         case READ_CONFIG_BYTE:
270                 dev = dev_find_slot(X86_BH, X86_BL);
271                 if (dev != 0) {
272                         X86_CL = pci_read_config8(dev, X86_DI);
273                         X86_AH = SUCCESSFUL;
274                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
275                         ret = 1;
276                 } else {
277                         X86_AH = DEVICE_NOT_FOUND;
278                         X86_EFLAGS |= FB_CF;    /* set carry flag */    
279                         ret = 0;
280                 }
281                 break;
282         case READ_CONFIG_WORD:
283                 dev = dev_find_slot(X86_BH, X86_BL);
284                 if (dev != 0) {
285                         X86_CX = pci_read_config16(dev, X86_DI);
286                         X86_AH = SUCCESSFUL;
287                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
288                         ret = 1;
289                 } else {
290                         X86_AH = DEVICE_NOT_FOUND;
291                         X86_EFLAGS |= FB_CF;    /* set carry flag */    
292                         ret = 0;
293                 }
294                 break;
295         case READ_CONFIG_DWORD:
296                 dev = dev_find_slot(X86_BH, X86_BL);
297                 if (dev != 0) {
298                         X86_ECX = pci_read_config32(dev, X86_DI);
299                         X86_AH = SUCCESSFUL;
300                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
301                         ret = 1;
302                 } else {
303                         X86_AH = DEVICE_NOT_FOUND;
304                         X86_EFLAGS |= FB_CF;    /* set carry flag */    
305                         ret = 0;
306                 }
307                 break;
308         case WRITE_CONFIG_BYTE:
309                 dev = dev_find_slot(X86_BH, X86_BL);
310                 if (dev != 0) {
311                         pci_write_config8(dev, X86_DI, X86_CL);
312                         X86_AH = SUCCESSFUL;
313                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
314                         ret = 1;
315                 } else {
316                         X86_AH = DEVICE_NOT_FOUND;
317                         X86_EFLAGS |= FB_CF;    /* set carry flag */    
318                         ret = 0;
319                 }
320                 break;
321         case WRITE_CONFIG_WORD:
322                 dev = dev_find_slot(X86_BH, X86_BL);
323                 if (dev != 0) {
324                         pci_write_config16(dev, X86_DI, X86_CX);
325                         X86_AH = SUCCESSFUL;
326                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
327                         ret = 1;
328                 } else {
329                         X86_AH = DEVICE_NOT_FOUND;
330                         X86_EFLAGS |= FB_CF;    /* set carry flag */    
331                         ret = 0;
332                 }
333                 break;
334         case WRITE_CONFIG_DWORD:
335                 dev = dev_find_slot(X86_BH, X86_BL);
336                 if (dev != 0) {
337                         pci_write_config16(dev, X86_DI, X86_ECX);
338                         X86_AH = SUCCESSFUL;
339                         X86_EFLAGS &= ~FB_CF;   /* clear carry flag */
340                         ret = 1;
341                 } else {
342                         X86_AH = DEVICE_NOT_FOUND;
343                         X86_EFLAGS |= FB_CF;    /* set carry flag */    
344                         ret = 0;
345                 }
346                 break;
347         default:
348                 X86_AH = FUNC_NOT_SUPPORTED;
349                 X86_EFLAGS |= FB_CF; 
350                 break;
351         }
352
353         return ret;
354 }
355
356 /* Interrupt multiplexer */
357
358 /* Find base address of interrupt handler */
359 static u32 getIntVect(int num)
360 {
361         return MEM_RW(num << 2) + (MEM_RW((num << 2) + 2) << 4);
362 }
363
364 static int run_bios_int(int num)
365 {
366         u32 eflags;
367
368         eflags = X86_EFLAGS;
369         push_word(eflags);
370         push_word(X86_CS);
371         push_word(X86_IP);
372         X86_CS = MEM_RW((num << 2) + 2);
373         X86_IP = MEM_RW(num << 2);
374
375         return 1;
376 }
377
378 static void do_int(int num)
379 {
380         int ret = 0;
381
382         printk("int%x (AX=%04x) vector at %x\n", num, X86_AX, getIntVect(num));
383
384         switch (num) {
385         case 0x10:
386         case 0x42:
387         case 0x6D:
388                 if (getIntVect(num) == 0x0000) {
389                         printk("uninitialized interrupt vector\n");
390                         ret = 1;
391                 }
392                 if (getIntVect(num) == 0xFF065) {
393                         //ret = int42_handler();
394                         ret = 1;
395                 }
396                 break;
397         case 0x15:
398                 ret = int15_handler();
399                 ret = 1;
400                 break;
401         case 0x16:
402                 //ret = int16_handler();
403                 ret = 0;
404                 break;
405         case 0x1A:
406                 ret = int1a_handler();
407                 ret = 1;
408                 break;
409         case 0xe6:
410                 //ret = intE6_handler();
411                 ret = 0;
412                 break;
413         default:
414                 break;
415         }
416
417         if (!ret)
418                 ret = run_bios_int(num);
419
420 }
421
422 /*
423  * here we are really paranoid about faking a "real"
424  * BIOS. Most of this information was pulled from
425  * dosemu.
426  */
427 static void setup_system_bios(void)
428 {
429         int i;
430
431         /* Set up Interrupt Vectors. The IVT starts at 0x0000:0x0000
432          * Additionally, we put some stub code into the F segment for
433          * those pesky little buggers that jmp to the hard coded addresses
434          * instead of calling int XX. This stub code looks like this
435          *
436          *  CD XX       int 0xXX
437          *  C3          ret
438          *  F4          hlt
439          */
440
441         /* int 05 default location (Bound Exceeded) */
442         MEM_WL(0x05 << 2, 0xf000ff54);
443         MEM_WL(0xfff54, 0xf4c305cd);
444         /* int 08 default location (Double Fault) */
445         MEM_WL(0x08 << 2, 0xf000fea5);
446         MEM_WL(0xffea5, 0xf4c308cd);
447         /* int 0E default location (Page Fault) */
448         MEM_WL(0x0e << 2, 0xf000ef57);
449         MEM_WL(0xfef57, 0xf4c30ecd);
450         /* int 10 default location */
451         MEM_WL(0x10 << 2, 0xf000f065);
452         MEM_WL(0xff065, 0xf4c310cd);
453         /* int 11 default location (Get Equipment Configuration) */
454         MEM_WL(0x11 << 2, 0xf000f84d);
455         MEM_WL(0xff84d, 0xf4c311cd);
456         /* int 12 default location (Get Conventional Memory Size) */
457         MEM_WL(0x12 << 2, 0xf000f841);
458         MEM_WL(0xff841, 0xf4c312cd);
459         /* int 13 default location (Disk) */
460         MEM_WL(0x13 << 2, 0xf000ec59);
461         MEM_WL(0xfec59, 0xf4c313cd);
462         /* int 14 default location (Disk) */
463         MEM_WL(0x14 << 2, 0xf000e739);
464         MEM_WL(0xfe739, 0xf4c314cd);
465         /* int 15 default location (I/O System Extensions) */
466         MEM_WL(0x15 << 2, 0xf000f859);
467         MEM_WL(0xf859, 0xf4c315cd);
468         /* int 16 default location */
469         MEM_WL(0x16 << 2, 0xf000e82e);
470         MEM_WL(0xfe82e, 0xf4c316cd);
471         /* int 17 default location (Parallel Port) */
472         MEM_WL(0x17 << 2, 0xf000efd2);
473         MEM_WL(0xfefd2, 0xf4c317cd);
474         /* int 1A default location (RTC, PCI and others) */
475         MEM_WL(0x1a << 2, 0xf000fe6e);
476         MEM_WL(0xffe6e, 0xf4c31acd);
477         /* int 1E default location (FDD table) */
478         MEM_WL(0x1e << 2, 0xf000efc7);
479         MEM_WL(0xfefc7, 0xf4c31ecd);
480         /* font tables default location (int 1F) */
481         MEM_WL(0x1f << 2, 0xf000fa6e);
482         MEM_WL(0xffa6e, 0xf4c31fcd);
483         /* int 42 default location */
484         MEM_WL(0x42 << 2, 0xf000f065);
485         /* int 6D default location */
486         MEM_WL(0x6D << 2, 0xf000f065);
487
488         /* Clear EBDA */
489         for (i=(INITIAL_EBDA_SEGMENT << 4); 
490                 i<(INITIAL_EBDA_SEGMENT << 4) + INITIAL_EBDA_SIZE; i++)
491                 MEM_WB(i, 0);
492         /* at offset 0h in EBDA is the size of the EBDA in KB */
493         MEM_WW((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024);
494
495         /* Clear BDA */
496         for (i=0x400; i<0x500; i+=4)
497                 MEM_WL(i, 0);
498
499         /* Set up EBDA */
500         MEM_WW(0x40e, INITIAL_EBDA_SEGMENT);
501
502         /* Set RAM size to 16MB (fake) */
503         MEM_WW(0x413, 16384);
504
505         // TODO Set up more of BDA here
506
507         /* setup original ROM BIOS Area (F000:xxxx) */
508         const char *date = "06/23/99";
509         for (i = 0; date[i]; i++)
510                 MEM_WB(0xffff5 + i, date[i]);
511         /* set up eisa ident string */
512         const char *ident = "PCI_ISA";
513         for (i = 0; ident[i]; i++)
514                 MEM_WB(0xfffd9 + i, ident[i]);
515
516         // write system model id for IBM-AT
517         // according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515,
518         // model FC is the original AT and also used in all DOSEMU Versions.
519         MEM_WB(0xFFFFE, 0xfc);
520 }
521
522 #define BIOSEMU_MEM_BASE 0x00000000
523 #define BIOSEMU_MEM_SIZE 0x00100000
524 void run_bios(struct device * dev, unsigned long addr)
525 {
526         int i;
527         u16 initialcs = (addr & 0xF0000) >> 4;
528         u16 initialip = (addr + 3) & 0xFFFF;
529         u16 devfn = (dev->bus->secondary << 8) | dev->path.pci.devfn;
530         X86EMU_intrFuncs intFuncs[256];
531
532         X86EMU_setMemBase(BIOSEMU_MEM_BASE, BIOSEMU_MEM_SIZE);
533         X86EMU_setupPioFuncs(&biosemu_piofuncs);
534         for (i = 0; i < 256; i++)
535                 intFuncs[i] = do_int;
536         X86EMU_setupIntrFuncs(intFuncs);
537
538         setup_system_bios();
539
540         /* cpu setup */
541         X86_AX = devfn ? devfn : 0xff;
542         X86_DX = 0x80;
543         X86_EIP = initialip;
544         X86_CS = initialcs;
545
546         /* Initialize stack and data segment */
547         X86_SS = STACK_SEGMENT;
548         X86_SP = STACK_START_OFFSET;;
549         X86_DS = DATA_SEGMENT;
550
551         /* We need a sane way to return from bios
552          * execution. A hlt instruction and a pointer
553          * to it, both kept on the stack, will do.
554          */
555         push_word(0xf4f4);              /* hlt; hlt */
556         push_word(X86_SS);
557         push_word(X86_SP + 2);
558
559 #ifdef DEBUG
560         //X86EMU_trace_on();
561 #endif
562
563         printk("Executing Initialization Vector...\n");
564         X86EMU_exec();
565         printk("Option ROM Exit Status: %04x\n", X86_AX);
566
567         /* Check whether the stack is "clean" i.e. containing the HLT
568          * instruction we pushed before executing and pointing to the original
569          * stack address... indicating that the initialization probably was
570          * successful
571          */
572         if ((pop_word() == 0xf4f4) && (X86_SS == STACK_SEGMENT)
573             && (X86_SP == STACK_START_OFFSET)) {
574                 printk("Stack is clean, initialization successfull!\n");
575         } else {
576                 printk("Stack unclean, initialization probably NOT COMPLETE!!\n");
577                 printk("SS:SP = %04x:%04x, expected: %04x:%04x\n",
578                         X86_SS, X86_SP, STACK_SEGMENT, STACK_START_OFFSET);
579         }
580 }