Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:54

0001 /*
0002  *  em86.c -- Include file for bootloader.
0003  */
0004 
0005 /*
0006  *  Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
0007  *
0008  *  Modified to compile in RTEMS development environment
0009  *  by Eric Valette
0010  *
0011  *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
0012  *
0013  *  The license and distribution terms for this file may be
0014  *  found in the file LICENSE in this distribution or at
0015  *  http://www.rtems.org/license/LICENSE.
0016  */
0017 
0018 /*****************************************************************************
0019 *
0020 * Code to interpret Video BIOS ROM routines.
0021 *
0022 *
0023 ******************************************************************************/
0024 
0025 /* These include are for the development version only */
0026 #include <sys/types.h>
0027 #include "pci.h"
0028 #include <libcpu/byteorder.h>
0029 #ifdef __BOOT__
0030 #include "bootldr.h"
0031 #include <limits.h>
0032 #include <rtems/bspIo.h>
0033 #endif
0034 
0035 /* Code options,  put them on the compiler command line */
0036 /* #define EIP_STATS */ /* EIP based profiling */
0037 /* #undef EIP_STATS */
0038 
0039 typedef union _reg_type1 {
0040     unsigned e;
0041     unsigned short x;
0042     struct {
0043         unsigned char l, h;
0044     } lh;
0045 } reg_type1;
0046 
0047 typedef union _reg_type2 {
0048     uint32_t e;
0049     uint16_t x;
0050 } reg_type2;
0051 
0052 typedef struct _x86 {
0053     reg_type1
0054       _eax, _ecx, _edx, _ebx;
0055     reg_type2
0056       _esp, _ebp, _esi, _edi;
0057     unsigned
0058       es, cs, ss, ds, fs, gs, eip, eflags;
0059     unsigned char
0060       *esbase, *csbase, *ssbase, *dsbase, *fsbase, *gsbase;
0061     volatile unsigned char *iobase;
0062     unsigned char *ioperm;
0063     unsigned
0064       reason, nexteip, parm1, parm2, opcode, base;
0065     unsigned *optable, opreg; /* no more used! */
0066     unsigned char* vbase;
0067     unsigned instructions;
0068 #ifdef __BOOT__
0069     u_char * ram;
0070     u_char * rom;
0071     struct pci_dev * dev;
0072 #else
0073         unsigned filler[14]; /* Skip to  next 64 byte boundary */
0074         unsigned eipstats[32768][2];
0075 #endif
0076 } x86;
0077 
0078 x86 v86_private __attribute__((aligned(32)));
0079 
0080 /* Emulator is in another source file */
0081 extern
0082 void em86_enter(x86 * p);
0083 
0084 #define EAX (p->_eax.e)
0085 #define ECX (p->_ecx.e)
0086 #define EDX (p->_edx.e)
0087 #define EBX (p->_ebx.e)
0088 #define ESP (p->_esp.e)
0089 #define EBP (p->_ebp.e)
0090 #define ESI (p->_esi.e)
0091 #define EDI (p->_edi.e)
0092 #define AX (p->_eax.x)
0093 #define CX (p->_ecx.x)
0094 #define DX (p->_edx.x)
0095 #define BX (p->_ebx.x)
0096 #define SP (p->_esp.x)
0097 #define BP (p->_ebp.x)
0098 #define SI (p->_esi.x)
0099 #define DI (p->_edi.x)
0100 #define AL (p->_eax.lh.l)
0101 #define CL (p->_ecx.lh.l)
0102 #define DL (p->_edx.lh.l)
0103 #define BL (p->_ebx.lh.l)
0104 #define AH (p->_eax.lh.h)
0105 #define CH (p->_ecx.lh.h)
0106 #define DH (p->_edx.lh.h)
0107 #define BH (p->_ebx.lh.h)
0108 
0109 /* Function used to debug */
0110 #ifdef __BOOT__
0111 #define printf printk
0112 #endif
0113 #ifdef DEBUG
0114 static void dump86(x86 * p){
0115     unsigned char *s = p->csbase + p->eip;
0116     printf("cs:eip=%04x:%08x, eax=%08x, ecx=%08x, edx=%08x, ebx=%08x\n",
0117            p->cs, p->eip, ld_le32(&EAX),
0118            ld_le32(&ECX), ld_le32(&EDX), ld_le32(&EBX));
0119     printf("ss:esp=%04x:%08x, ebp=%08x, esi=%08x, edi=%08x, efl=%08x\n",
0120            p->ss, ld_le32(&ESP), ld_le32(&EBP),
0121            ld_le32(&ESI), ld_le32(&EDI), p->eflags);
0122     printf("nip=%08x, ds=%04x, es=%04x, fs=%04x, gs=%04x, total=%d\n",
0123            p->nexteip, p->ds, p->es, p->fs, p->gs, p->instructions);
0124     printf("code: %02x %02x %02x %02x %02x %02x "
0125            "%02x %02x %02x %02x %02x %02x\n",
0126            s[0], s[1], s[2], s[3], s[4], s[5],
0127            s[6], s[7], s[8], s[9], s[10], s[11]);
0128 #ifndef __BOOT__
0129     printf("op1=%08x, op2=%08x, result=%08x, flags=%08x\n",
0130            p->filler[11], p->filler[12], p->filler[13], p->filler[14]);
0131 #endif
0132 }
0133 #else
0134 #define dump86(x)
0135 #endif
0136 
0137 static int bios86pci(x86 * p) {
0138     unsigned reg=ld_le16(&DI);
0139     reg_type2 tmp;
0140 
0141     if (AL>=8 && AL<=13 && reg>0xff) {
0142         AH = PCIBIOS_BAD_REGISTER_NUMBER;
0143     } else {
0144         switch(AL) {
0145         case 2: /* find_device */
0146           /* Should be improved for BIOS able to handle
0147            * multiple devices. We simply suppose the BIOS
0148            * inits a single device, and return an error
0149            * if it tries to find more...
0150            */
0151           if (SI) {
0152             AH=PCIBIOS_DEVICE_NOT_FOUND;
0153           } else {
0154             BH = p->dev->bus->number;
0155             BL = p->dev->devfn;
0156             AH = 0;
0157           }
0158           break;
0159         /*
0160         case 3: find_class not implemented for now.
0161         */
0162         case 8:       /* read_config_byte */
0163           AH=pcibios_read_config_byte(BH, BL, reg, &CL);
0164           break;
0165         case 9:       /* read_config_word */
0166           AH=pcibios_read_config_word(BH, BL, reg, &tmp.x);
0167           CX=ld_le16(&tmp.x);
0168           break;
0169         case 10:      /* read_config_dword */
0170           AH=pcibios_read_config_dword(BH, BL, reg, &tmp.e);
0171           ECX=ld_le32(&tmp.e);
0172           break;
0173         case 11:      /* write_config_byte */
0174           AH=pcibios_write_config_byte(BH, BL, reg, CL);
0175           break;
0176         case 12:      /* write_config_word */
0177           AH=pcibios_write_config_word(BH, BL, reg, ld_le16(&CX));
0178           break;
0179         case 13:      /* write_config_dword */
0180           AH=pcibios_write_config_dword(
0181             BH, BL, reg, ld_le32((uint32_t *)&ECX));
0182           break;
0183         default:
0184           printf("Unimplemented or illegal PCI service call #%d!\n",
0185              AL);
0186           return 1;
0187         }
0188     }
0189     p->eip = p->nexteip;
0190     /* Set/clear carry according to result */
0191     if (AH) p->eflags |= 1; else p->eflags &=~1;
0192     return 0;
0193 }
0194 
0195 static void push2(x86 *p, unsigned value) {
0196     unsigned char * sbase= p->ssbase;
0197     unsigned newsp = (ld_le16(&SP)-2)&0xffff;
0198     st_le16(&SP,newsp);
0199     st_le16((unsigned short *)(sbase+newsp), value);
0200 }
0201 
0202 static unsigned pop2(x86 *p) {
0203     unsigned char * sbase=p->ssbase;
0204     unsigned oldsp = ld_le16(&SP);
0205     st_le16(&SP,oldsp+2);
0206     return ld_le16((unsigned short *)(sbase+oldsp));
0207 }
0208 
0209 static int int10h(x86 * p) { /* Process BIOS video interrupt */
0210     unsigned vector;
0211     vector=ld_le32((uint32_t *)p->vbase+0x10);
0212     if (((vector&0xffff0000)>>16)==0xc000) {
0213         push2(p, p->eflags);
0214         push2(p, p->cs);
0215         push2(p, p->nexteip);
0216         p->cs=vector>>16;
0217         p->csbase=p->vbase + (p->cs<<4);
0218         p->eip=vector&0xffff;
0219 #if 1
0220         p->eflags&=0xfcff;  /* Clear AC/TF/IF */
0221 #else
0222         p->eflags = (p->eflags&0xfcff)|0x100;  /* Set TF for debugging */
0223 #endif
0224         /* p->eflags|=0x100; uncomment to force a trap */
0225         return(0);
0226     } else {
0227         switch(AH) {
0228         case 0x12:
0229           switch(BL){
0230           case 0x32:
0231             p->eip=p->nexteip;
0232             return(0);
0233             break;
0234           default:
0235             break;
0236           }
0237         default:
0238           break;
0239         }
0240         printf("unhandled soft interrupt 0x10: vector=%x\n", vector);
0241         return(1);
0242     }
0243 }
0244 
0245 static int process_softint(x86 * p) {
0246 #if 0
0247     if (p->parm1!=0x10 || AH!=0x0e) {
0248         printf("Soft interrupt\n");
0249         dump86(p);
0250     }
0251 #endif
0252     switch(p->parm1) {
0253     case 0x10: /* BIOS video interrupt */
0254       return int10h(p);
0255     case 0x1a:
0256       if(AH==0xb1) return bios86pci(p);
0257       break;
0258     default:
0259       break;
0260     }
0261     dump86(p);
0262     printf("Unhandled soft interrupt number 0x%04x, AX=0x%04x\n",
0263          p->parm1, ld_le16(&AX));
0264     return(1);
0265 }
0266 
0267 /* The only function called back by the emulator is em86_trap, all
0268    instructions may that change the code segment are trapped here.
0269    p->reason is one of the following codes.  */
0270 #define code_zerdiv 0
0271 #define code_trap   1
0272 #define code_int3   3
0273 #define code_into   4
0274 #define code_bound  5
0275 #define code_ud     6
0276 #define code_dna    7
0277 
0278 #define code_iretw  256
0279 #define code_iretl  257
0280 #define code_lcallw 258
0281 #define code_lcalll 259
0282 #define code_ljmpw  260
0283 #define code_ljmpl  261
0284 #define code_lretw  262
0285 #define code_lretl  263
0286 #define code_softint    264
0287 #define code_lock   265 /* Lock prefix */
0288 /* Codes 1024 to 2047 are used for I/O port access instructions:
0289  - The three LSB define the port size (1, 2 or 4)
0290  - bit of weight 512 means out if set, in if clear
0291  - bit of weight 256 means ins/outs if set, in/out if clear
0292  - bit of weight 128 means use esi/edi if set, si/di if clear
0293    (only used for ins/outs instructions, always clear for in/out)
0294  */
0295 #define code_inb    1024+1
0296 #define code_inw    1024+2
0297 #define code_inl    1024+4
0298 #define code_outb   1024+512+1
0299 #define code_outw   1024+512+2
0300 #define code_outl   1024+512+4
0301 #define code_insb_a16   1024+256+1
0302 #define code_insw_a16   1024+256+2
0303 #define code_insl_a16   1024+256+4
0304 #define code_outsb_a16  1024+512+256+1
0305 #define code_outsw_a16  1024+512+256+2
0306 #define code_outsl_a16  1024+512+256+4
0307 #define code_insb_a32   1024+256+128+1
0308 #define code_insw_a32   1024+256+128+2
0309 #define code_insl_a32   1024+256+128+4
0310 #define code_outsb_a32  1024+512+256+128+1
0311 #define code_outsw_a32  1024+512+256+128+2
0312 #define code_outsl_a32  1024+512+256+128+4
0313 
0314 int em86_trap(x86 *p) {
0315 #ifndef __BOOT__
0316       int i;
0317       unsigned char command[80];
0318       unsigned char *verb, *t;
0319       unsigned short *fp;
0320       static unsigned char def=0;
0321       static unsigned char * bptaddr=NULL;  /* Breakpoint address */
0322       static unsigned char bptopc; /* Replaced breakpoint opcode */
0323       unsigned char cmd;
0324       unsigned tmp;
0325 #endif
0326       switch(p->reason) {
0327       case code_int3:
0328 #ifndef __BOOT__
0329         if(p->csbase+p->eip == bptaddr) {
0330           *bptaddr=bptopc;
0331           bptaddr=NULL;
0332         }
0333         else printf("Unexpected ");
0334 #endif
0335         printf("Breakpoint Interrupt !\n");
0336         /* Note that this fallthrough (no break;) is on purpose */
0337 #ifdef __BOOT__
0338         return 0;
0339 #else
0340       case code_trap:
0341         dump86(p);
0342         for(;;) {
0343             printf("b(reakpoint, g(o, q(uit, s(tack, t(race ? [%c] ", def);
0344         fgets(command,sizeof(command),stdin);
0345         verb = strtok(command,"     \n");
0346         if(verb) cmd=*verb; else cmd=def;
0347         def=0;
0348         switch(cmd) {
0349         case 'b':
0350         case 'B':
0351           if(bptaddr) *bptaddr=bptopc;
0352           t=strtok(0,"  \n");
0353           i=sscanf(t,"%x",&tmp);
0354           if(i==1) {
0355             bptaddr=p->vbase + tmp;
0356             bptopc=*bptaddr;
0357             *bptaddr=0xcc;
0358           } else bptaddr=NULL;
0359           break;
0360         case 'q':
0361         case 'Q':
0362           return 1;
0363           break;
0364 
0365         case 'g':
0366         case 'G':
0367           p->eflags &= ~0x100;
0368           return 0;
0369           break;
0370 
0371         case 's':
0372         case 'S': /* Print the 8 stack top words */
0373           fp = (unsigned short *)(p->ssbase+ld_le16(&SP));
0374           printf("Stack [%04x:%04x]: %04x %04x %04x %04x %04x %04x %04x %04x\n",
0375              p->ss, ld_le16(&SP),
0376              ld_le16(fp+0), ld_le16(fp+1), ld_le16(fp+2), ld_le16(fp+3),
0377              ld_le16(fp+4), ld_le16(fp+5), ld_le16(fp+6), ld_le16(fp+7));
0378           break;
0379         case 't':
0380         case 'T':
0381           p->eflags |= 0x10100;  /* Set the resume and trap flags */
0382           def='t';
0383           return 0;
0384           break;
0385           /* Should add some code to edit registers */
0386         }
0387         }
0388 #endif
0389         break;
0390       case code_ud:
0391         printf("Attempt to execute an unimplemented"
0392            "or undefined opcode!\n");
0393         dump86(p);
0394         return(1); /* exit interpreter */
0395         break;
0396       case code_dna:
0397         printf("Attempt to execute a floating point instruction!\n");
0398         dump86(p);
0399         return(1);
0400         break;
0401       case code_softint:
0402         return process_softint(p);
0403         break;
0404       case code_iretw:
0405         p->eip=pop2(p);
0406         p->cs=pop2(p);
0407         p->csbase=p->vbase + (p->cs<<4);
0408         p->eflags= (p->eflags&0xfffe0000)|pop2(p);
0409         /* p->eflags|= 0x100; */ /* Uncomment to trap after iretws */
0410         return(0);
0411         break;
0412 #ifndef __BOOT__
0413       case code_inb:
0414       case code_inw:
0415       case code_inl:
0416       case code_insb_a16:
0417       case code_insw_a16:
0418       case code_insl_a16:
0419       case code_insb_a32:
0420       case code_insw_a32:
0421       case code_insl_a32:
0422       case code_outb:
0423       case code_outw:
0424       case code_outl:
0425       case code_outsb_a16:
0426       case code_outsw_a16:
0427       case code_outsl_a16:
0428       case code_outsb_a32:
0429       case code_outsw_a32:
0430       case code_outsl_a32:
0431         /* For now we simply enable I/O to the ports and continue */
0432         for(i=p->parm1; i<p->parm1+(p->reason&7); i++) {
0433           p->ioperm[i/8] &= ~(1<<i%8);
0434         }
0435         printf("Access to ports %04x-%04x enabled.\n",
0436            p->parm1, p->parm1+(p->reason&7)-1);
0437         return(0);
0438 #endif
0439       case code_lretw:
0440         /* Check for the exit eyecatcher */
0441         if ( *(u_int *)(p->ssbase+ld_le16(&SP)) == UINT_MAX) return 1;
0442         /* No break on purpose */
0443       default:
0444         dump86(p);
0445         printf("em86_trap called with unhandled reason code !\n");
0446         return(1);
0447 
0448       }
0449 }
0450 
0451 void cleanup_v86_mess(void) {
0452     x86 *p = (x86 *) bd->v86_private;
0453 
0454     /* This automatically removes the mappings ! */
0455     vfree(p->vbase);
0456     p->vbase = 0;
0457     pfree(p->ram);
0458     p->ram = 0;
0459     sfree(p->ioperm);
0460     p->ioperm=0;
0461 }
0462 
0463 int init_v86(void) {
0464     x86 *p = (x86 *) bd->v86_private;
0465 
0466     /* p->vbase is non null when the v86 is properly set-up */
0467     if (p->vbase) return 0;
0468 
0469     /* Set everything to 0 */
0470     memset(p, 0, sizeof(*p));
0471     p->ioperm = salloc(65536/8+1);
0472     p->ram = palloc(0xa0000);
0473     p->iobase = ptr_mem_map->io_base;
0474 
0475     if (!p->ram || !p->ioperm) return 1;
0476 
0477     /* The ioperm array must have an additional byte at the end ! */
0478     p->ioperm[65536/8] = 0xff;
0479 
0480     p->vbase = valloc(0x110000);
0481     if (!p->vbase) return 1;
0482 
0483     /* These calls should never fail. */
0484     vmap(p->vbase, (u_long)p->ram|PTE_RAM, 0xa0000);
0485     vmap(p->vbase+0x100000, (u_long)p->ram|PTE_RAM, 0x10000);
0486     vmap(p->vbase+0xa0000,
0487          ((u_long)ptr_mem_map->isa_mem_base+0xa0000)|PTE_IO, 0x20000);
0488     return 0;
0489 }
0490 
0491 void em86_main(struct pci_dev *dev){
0492     x86 *p = (x86 *) bd->v86_private;
0493     u_short signature;
0494     u_char length;
0495     volatile u_int *src;
0496     u_int *dst, left;
0497     uint32_t saved_rom;
0498 #if defined(MONITOR_IO) && !defined(__BOOT__)
0499 #define IOMASK 0xff
0500 #else
0501 #define IOMASK 0
0502 #endif
0503 
0504 #ifndef __BOOT__
0505     int i;
0506     /* Allow or disable access to all ports */
0507     for(i=0; i<65536/8; i++) p->ioperm[i]=IOMASK;
0508     p->ioperm[i] = 0xff; /* Last unused byte must have this value */
0509 #endif
0510     p->dev = dev;
0511     memset(p->vbase, 0, 0xa0000);
0512     /* Set up a few registers */
0513     p->cs = 0xc000; p->csbase = p->vbase + 0xc0000;
0514     p->ss = 0x1000; p->ssbase = p->vbase + 0x10000;
0515     p->eflags=0x200;
0516     st_le16(&SP,0xfffc); p->eip=3;
0517 
0518     p->dsbase = p->esbase = p->fsbase = p->gsbase = p->vbase;
0519 
0520     /* Follow the PCI BIOS specification */
0521     AH=dev->bus->number;
0522     AL=dev->devfn;
0523 
0524     /* All other registers are irrelevant except ES:DI which
0525      * should point to a PnP installation check block. This
0526      * is not yet implemented due to lack of references. */
0527 
0528     /* Store a return address of 0xffff:0xffff as eyecatcher */
0529     *(u_int *)(p->ssbase+ld_le16(&SP)) = UINT_MAX;
0530 
0531     /* Interrupt for BIOS EGA services is 0xf000:0xf065 (int 0x10) */
0532     st_le32((uint32_t *)p->vbase + 0x10, 0xf000f065);
0533 
0534     /* Enable the ROM, read it and disable it immediately */
0535     pci_bootloader_read_config_dword(dev, PCI_ROM_ADDRESS, &saved_rom);
0536     pci_bootloader_write_config_dword(dev, PCI_ROM_ADDRESS, 0x000c0001);
0537 
0538     /* Check that there is an Intel ROM. Should we also check that
0539      * the first instruction is a jump (0xe9 or 0xeb) ?
0540      */
0541     signature = *(u_short *)(ptr_mem_map->isa_mem_base+0xc0000);
0542     if (signature!=0x55aa) {
0543         printf("bad signature: %04x.\n", signature);
0544         return;
0545     }
0546     /* Allocate memory and copy the video rom to vbase+0xc0000; */
0547     length = ptr_mem_map->isa_mem_base[0xc0002];
0548     p->rom = palloc(length*512);
0549     if (!p->rom) return;
0550 
0551     for(dst=(u_int *) p->rom,
0552         src=(volatile u_int *)(ptr_mem_map->isa_mem_base+0xc0000),
0553         left = length*512/sizeof(u_int);
0554         left--;
0555         *dst++=*src++);
0556 
0557     /* Disable the ROM and map the copy in virtual address space, note
0558      * that the ROM has to be mapped as RAM since some BIOSes (at least
0559      * Cirrus) perform write accesses to their own ROM. The reason seems
0560      * to be that they check that they must execute from shadow RAM
0561      * because accessing the ROM prevents accessing the video RAM
0562      * according to comments in linux/arch/alpha/kernel/bios32.c.
0563      */
0564 
0565     pci_bootloader_write_config_dword(dev, PCI_ROM_ADDRESS, saved_rom);
0566     vmap(p->vbase+0xc0000, (u_long)p->rom|PTE_RAM, length*512);
0567 
0568     /* Now actually emulate the ROM init routine */
0569     em86_enter(p);
0570 
0571     /* Free the acquired resources */
0572     vunmap(p->vbase+0xc0000);
0573     pfree(p->rom);
0574 }