diff options
Diffstat (limited to 'c/src/lib/libbsp/powerpc/shared/bootloader/em86.c')
-rw-r--r-- | c/src/lib/libbsp/powerpc/shared/bootloader/em86.c | 574 |
1 files changed, 0 insertions, 574 deletions
diff --git a/c/src/lib/libbsp/powerpc/shared/bootloader/em86.c b/c/src/lib/libbsp/powerpc/shared/bootloader/em86.c deleted file mode 100644 index 5ce4b0cc34..0000000000 --- a/c/src/lib/libbsp/powerpc/shared/bootloader/em86.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * em86.c -- Include file for bootloader. - */ - -/* - * Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es - * - * Modified to compile in RTEMS development environment - * by Eric Valette - * - * Copyright (C) 1999 Eric Valette. valette@crf.canon.fr - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -/***************************************************************************** -* -* Code to interpret Video BIOS ROM routines. -* -* -******************************************************************************/ - -/* These include are for the development version only */ -#include <sys/types.h> -#include "pci.h" -#include <libcpu/byteorder.h> -#ifdef __BOOT__ -#include "bootldr.h" -#include <limits.h> -#include <rtems/bspIo.h> -#endif - -/* Code options, put them on the compiler command line */ -/* #define EIP_STATS */ /* EIP based profiling */ -/* #undef EIP_STATS */ - -typedef union _reg_type1 { - unsigned e; - unsigned short x; - struct { - unsigned char l, h; - } lh; -} reg_type1; - -typedef union _reg_type2 { - uint32_t e; - uint16_t x; -} reg_type2; - -typedef struct _x86 { - reg_type1 - _eax, _ecx, _edx, _ebx; - reg_type2 - _esp, _ebp, _esi, _edi; - unsigned - es, cs, ss, ds, fs, gs, eip, eflags; - unsigned char - *esbase, *csbase, *ssbase, *dsbase, *fsbase, *gsbase; - volatile unsigned char *iobase; - unsigned char *ioperm; - unsigned - reason, nexteip, parm1, parm2, opcode, base; - unsigned *optable, opreg; /* no more used! */ - unsigned char* vbase; - unsigned instructions; -#ifdef __BOOT__ - u_char * ram; - u_char * rom; - struct pci_dev * dev; -#else - unsigned filler[14]; /* Skip to next 64 byte boundary */ - unsigned eipstats[32768][2]; -#endif -} x86; - -x86 v86_private __attribute__((aligned(32))); - -/* Emulator is in another source file */ -extern -void em86_enter(x86 * p); - -#define EAX (p->_eax.e) -#define ECX (p->_ecx.e) -#define EDX (p->_edx.e) -#define EBX (p->_ebx.e) -#define ESP (p->_esp.e) -#define EBP (p->_ebp.e) -#define ESI (p->_esi.e) -#define EDI (p->_edi.e) -#define AX (p->_eax.x) -#define CX (p->_ecx.x) -#define DX (p->_edx.x) -#define BX (p->_ebx.x) -#define SP (p->_esp.x) -#define BP (p->_ebp.x) -#define SI (p->_esi.x) -#define DI (p->_edi.x) -#define AL (p->_eax.lh.l) -#define CL (p->_ecx.lh.l) -#define DL (p->_edx.lh.l) -#define BL (p->_ebx.lh.l) -#define AH (p->_eax.lh.h) -#define CH (p->_ecx.lh.h) -#define DH (p->_edx.lh.h) -#define BH (p->_ebx.lh.h) - -/* Function used to debug */ -#ifdef __BOOT__ -#define printf printk -#endif -#ifdef DEBUG -static void dump86(x86 * p){ - unsigned char *s = p->csbase + p->eip; - printf("cs:eip=%04x:%08x, eax=%08x, ecx=%08x, edx=%08x, ebx=%08x\n", - p->cs, p->eip, ld_le32(&EAX), - ld_le32(&ECX), ld_le32(&EDX), ld_le32(&EBX)); - printf("ss:esp=%04x:%08x, ebp=%08x, esi=%08x, edi=%08x, efl=%08x\n", - p->ss, ld_le32(&ESP), ld_le32(&EBP), - ld_le32(&ESI), ld_le32(&EDI), p->eflags); - printf("nip=%08x, ds=%04x, es=%04x, fs=%04x, gs=%04x, total=%d\n", - p->nexteip, p->ds, p->es, p->fs, p->gs, p->instructions); - printf("code: %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x\n", - s[0], s[1], s[2], s[3], s[4], s[5], - s[6], s[7], s[8], s[9], s[10], s[11]); -#ifndef __BOOT__ - printf("op1=%08x, op2=%08x, result=%08x, flags=%08x\n", - p->filler[11], p->filler[12], p->filler[13], p->filler[14]); -#endif -} -#else -#define dump86(x) -#endif - -static int bios86pci(x86 * p) { - unsigned reg=ld_le16(&DI); - reg_type2 tmp; - - if (AL>=8 && AL<=13 && reg>0xff) { - AH = PCIBIOS_BAD_REGISTER_NUMBER; - } else { - switch(AL) { - case 2: /* find_device */ - /* Should be improved for BIOS able to handle - * multiple devices. We simply suppose the BIOS - * inits a single device, and return an error - * if it tries to find more... - */ - if (SI) { - AH=PCIBIOS_DEVICE_NOT_FOUND; - } else { - BH = p->dev->bus->number; - BL = p->dev->devfn; - AH = 0; - } - break; - /* - case 3: find_class not implemented for now. - */ - case 8: /* read_config_byte */ - AH=pcibios_read_config_byte(BH, BL, reg, &CL); - break; - case 9: /* read_config_word */ - AH=pcibios_read_config_word(BH, BL, reg, &tmp.x); - CX=ld_le16(&tmp.x); - break; - case 10: /* read_config_dword */ - AH=pcibios_read_config_dword(BH, BL, reg, &tmp.e); - ECX=ld_le32(&tmp.e); - break; - case 11: /* write_config_byte */ - AH=pcibios_write_config_byte(BH, BL, reg, CL); - break; - case 12: /* write_config_word */ - AH=pcibios_write_config_word(BH, BL, reg, ld_le16(&CX)); - break; - case 13: /* write_config_dword */ - AH=pcibios_write_config_dword( - BH, BL, reg, ld_le32((uint32_t *)&ECX)); - break; - default: - printf("Unimplemented or illegal PCI service call #%d!\n", - AL); - return 1; - } - } - p->eip = p->nexteip; - /* Set/clear carry according to result */ - if (AH) p->eflags |= 1; else p->eflags &=~1; - return 0; -} - -static void push2(x86 *p, unsigned value) { - unsigned char * sbase= p->ssbase; - unsigned newsp = (ld_le16(&SP)-2)&0xffff; - st_le16(&SP,newsp); - st_le16((unsigned short *)(sbase+newsp), value); -} - -static unsigned pop2(x86 *p) { - unsigned char * sbase=p->ssbase; - unsigned oldsp = ld_le16(&SP); - st_le16(&SP,oldsp+2); - return ld_le16((unsigned short *)(sbase+oldsp)); -} - -static int int10h(x86 * p) { /* Process BIOS video interrupt */ - unsigned vector; - vector=ld_le32((uint32_t *)p->vbase+0x10); - if (((vector&0xffff0000)>>16)==0xc000) { - push2(p, p->eflags); - push2(p, p->cs); - push2(p, p->nexteip); - p->cs=vector>>16; - p->csbase=p->vbase + (p->cs<<4); - p->eip=vector&0xffff; -#if 1 - p->eflags&=0xfcff; /* Clear AC/TF/IF */ -#else - p->eflags = (p->eflags&0xfcff)|0x100; /* Set TF for debugging */ -#endif - /* p->eflags|=0x100; uncomment to force a trap */ - return(0); - } else { - switch(AH) { - case 0x12: - switch(BL){ - case 0x32: - p->eip=p->nexteip; - return(0); - break; - default: - break; - } - default: - break; - } - printf("unhandled soft interrupt 0x10: vector=%x\n", vector); - return(1); - } -} - -static int process_softint(x86 * p) { -#if 0 - if (p->parm1!=0x10 || AH!=0x0e) { - printf("Soft interrupt\n"); - dump86(p); - } -#endif - switch(p->parm1) { - case 0x10: /* BIOS video interrupt */ - return int10h(p); - case 0x1a: - if(AH==0xb1) return bios86pci(p); - break; - default: - break; - } - dump86(p); - printf("Unhandled soft interrupt number 0x%04x, AX=0x%04x\n", - p->parm1, ld_le16(&AX)); - return(1); -} - -/* The only function called back by the emulator is em86_trap, all - instructions may that change the code segment are trapped here. - p->reason is one of the following codes. */ -#define code_zerdiv 0 -#define code_trap 1 -#define code_int3 3 -#define code_into 4 -#define code_bound 5 -#define code_ud 6 -#define code_dna 7 - -#define code_iretw 256 -#define code_iretl 257 -#define code_lcallw 258 -#define code_lcalll 259 -#define code_ljmpw 260 -#define code_ljmpl 261 -#define code_lretw 262 -#define code_lretl 263 -#define code_softint 264 -#define code_lock 265 /* Lock prefix */ -/* Codes 1024 to 2047 are used for I/O port access instructions: - - The three LSB define the port size (1, 2 or 4) - - bit of weight 512 means out if set, in if clear - - bit of weight 256 means ins/outs if set, in/out if clear - - bit of weight 128 means use esi/edi if set, si/di if clear - (only used for ins/outs instructions, always clear for in/out) - */ -#define code_inb 1024+1 -#define code_inw 1024+2 -#define code_inl 1024+4 -#define code_outb 1024+512+1 -#define code_outw 1024+512+2 -#define code_outl 1024+512+4 -#define code_insb_a16 1024+256+1 -#define code_insw_a16 1024+256+2 -#define code_insl_a16 1024+256+4 -#define code_outsb_a16 1024+512+256+1 -#define code_outsw_a16 1024+512+256+2 -#define code_outsl_a16 1024+512+256+4 -#define code_insb_a32 1024+256+128+1 -#define code_insw_a32 1024+256+128+2 -#define code_insl_a32 1024+256+128+4 -#define code_outsb_a32 1024+512+256+128+1 -#define code_outsw_a32 1024+512+256+128+2 -#define code_outsl_a32 1024+512+256+128+4 - -int em86_trap(x86 *p) { -#ifndef __BOOT__ - int i; - unsigned char command[80]; - unsigned char *verb, *t; - unsigned short *fp; - static unsigned char def=0; - static unsigned char * bptaddr=NULL; /* Breakpoint address */ - static unsigned char bptopc; /* Replaced breakpoint opcode */ - unsigned char cmd; - unsigned tmp; -#endif - switch(p->reason) { - case code_int3: -#ifndef __BOOT__ - if(p->csbase+p->eip == bptaddr) { - *bptaddr=bptopc; - bptaddr=NULL; - } - else printf("Unexpected "); -#endif - printf("Breakpoint Interrupt !\n"); - /* Note that this fallthrough (no break;) is on purpose */ -#ifdef __BOOT__ - return 0; -#else - case code_trap: - dump86(p); - for(;;) { - printf("b(reakpoint, g(o, q(uit, s(tack, t(race ? [%c] ", def); - fgets(command,sizeof(command),stdin); - verb = strtok(command," \n"); - if(verb) cmd=*verb; else cmd=def; - def=0; - switch(cmd) { - case 'b': - case 'B': - if(bptaddr) *bptaddr=bptopc; - t=strtok(0," \n"); - i=sscanf(t,"%x",&tmp); - if(i==1) { - bptaddr=p->vbase + tmp; - bptopc=*bptaddr; - *bptaddr=0xcc; - } else bptaddr=NULL; - break; - case 'q': - case 'Q': - return 1; - break; - - case 'g': - case 'G': - p->eflags &= ~0x100; - return 0; - break; - - case 's': - case 'S': /* Print the 8 stack top words */ - fp = (unsigned short *)(p->ssbase+ld_le16(&SP)); - printf("Stack [%04x:%04x]: %04x %04x %04x %04x %04x %04x %04x %04x\n", - p->ss, ld_le16(&SP), - ld_le16(fp+0), ld_le16(fp+1), ld_le16(fp+2), ld_le16(fp+3), - ld_le16(fp+4), ld_le16(fp+5), ld_le16(fp+6), ld_le16(fp+7)); - break; - case 't': - case 'T': - p->eflags |= 0x10100; /* Set the resume and trap flags */ - def='t'; - return 0; - break; - /* Should add some code to edit registers */ - } - } -#endif - break; - case code_ud: - printf("Attempt to execute an unimplemented" - "or undefined opcode!\n"); - dump86(p); - return(1); /* exit interpreter */ - break; - case code_dna: - printf("Attempt to execute a floating point instruction!\n"); - dump86(p); - return(1); - break; - case code_softint: - return process_softint(p); - break; - case code_iretw: - p->eip=pop2(p); - p->cs=pop2(p); - p->csbase=p->vbase + (p->cs<<4); - p->eflags= (p->eflags&0xfffe0000)|pop2(p); - /* p->eflags|= 0x100; */ /* Uncomment to trap after iretws */ - return(0); - break; -#ifndef __BOOT__ - case code_inb: - case code_inw: - case code_inl: - case code_insb_a16: - case code_insw_a16: - case code_insl_a16: - case code_insb_a32: - case code_insw_a32: - case code_insl_a32: - case code_outb: - case code_outw: - case code_outl: - case code_outsb_a16: - case code_outsw_a16: - case code_outsl_a16: - case code_outsb_a32: - case code_outsw_a32: - case code_outsl_a32: - /* For now we simply enable I/O to the ports and continue */ - for(i=p->parm1; i<p->parm1+(p->reason&7); i++) { - p->ioperm[i/8] &= ~(1<<i%8); - } - printf("Access to ports %04x-%04x enabled.\n", - p->parm1, p->parm1+(p->reason&7)-1); - return(0); -#endif - case code_lretw: - /* Check for the exit eyecatcher */ - if ( *(u_int *)(p->ssbase+ld_le16(&SP)) == UINT_MAX) return 1; - /* No break on purpose */ - default: - dump86(p); - printf("em86_trap called with unhandled reason code !\n"); - return(1); - - } -} - -void cleanup_v86_mess(void) { - x86 *p = (x86 *) bd->v86_private; - - /* This automatically removes the mappings ! */ - vfree(p->vbase); - p->vbase = 0; - pfree(p->ram); - p->ram = 0; - sfree(p->ioperm); - p->ioperm=0; -} - -int init_v86(void) { - x86 *p = (x86 *) bd->v86_private; - - /* p->vbase is non null when the v86 is properly set-up */ - if (p->vbase) return 0; - - /* Set everything to 0 */ - memset(p, 0, sizeof(*p)); - p->ioperm = salloc(65536/8+1); - p->ram = palloc(0xa0000); - p->iobase = ptr_mem_map->io_base; - - if (!p->ram || !p->ioperm) return 1; - - /* The ioperm array must have an additional byte at the end ! */ - p->ioperm[65536/8] = 0xff; - - p->vbase = valloc(0x110000); - if (!p->vbase) return 1; - - /* These calls should never fail. */ - vmap(p->vbase, (u_long)p->ram|PTE_RAM, 0xa0000); - vmap(p->vbase+0x100000, (u_long)p->ram|PTE_RAM, 0x10000); - vmap(p->vbase+0xa0000, - ((u_long)ptr_mem_map->isa_mem_base+0xa0000)|PTE_IO, 0x20000); - return 0; -} - -void em86_main(struct pci_dev *dev){ - x86 *p = (x86 *) bd->v86_private; - u_short signature; - u_char length; - volatile u_int *src; - u_int *dst, left; - uint32_t saved_rom; -#if defined(MONITOR_IO) && !defined(__BOOT__) -#define IOMASK 0xff -#else -#define IOMASK 0 -#endif - -#ifndef __BOOT__ - int i; - /* Allow or disable access to all ports */ - for(i=0; i<65536/8; i++) p->ioperm[i]=IOMASK; - p->ioperm[i] = 0xff; /* Last unused byte must have this value */ -#endif - p->dev = dev; - memset(p->vbase, 0, 0xa0000); - /* Set up a few registers */ - p->cs = 0xc000; p->csbase = p->vbase + 0xc0000; - p->ss = 0x1000; p->ssbase = p->vbase + 0x10000; - p->eflags=0x200; - st_le16(&SP,0xfffc); p->eip=3; - - p->dsbase = p->esbase = p->fsbase = p->gsbase = p->vbase; - - /* Follow the PCI BIOS specification */ - AH=dev->bus->number; - AL=dev->devfn; - - /* All other registers are irrelevant except ES:DI which - * should point to a PnP installation check block. This - * is not yet implemented due to lack of references. */ - - /* Store a return address of 0xffff:0xffff as eyecatcher */ - *(u_int *)(p->ssbase+ld_le16(&SP)) = UINT_MAX; - - /* Interrupt for BIOS EGA services is 0xf000:0xf065 (int 0x10) */ - st_le32((uint32_t *)p->vbase + 0x10, 0xf000f065); - - /* Enable the ROM, read it and disable it immediately */ - pci_bootloader_read_config_dword(dev, PCI_ROM_ADDRESS, &saved_rom); - pci_bootloader_write_config_dword(dev, PCI_ROM_ADDRESS, 0x000c0001); - - /* Check that there is an Intel ROM. Should we also check that - * the first instruction is a jump (0xe9 or 0xeb) ? - */ - signature = *(u_short *)(ptr_mem_map->isa_mem_base+0xc0000); - if (signature!=0x55aa) { - printf("bad signature: %04x.\n", signature); - return; - } - /* Allocate memory and copy the video rom to vbase+0xc0000; */ - length = ptr_mem_map->isa_mem_base[0xc0002]; - p->rom = palloc(length*512); - if (!p->rom) return; - - for(dst=(u_int *) p->rom, - src=(volatile u_int *)(ptr_mem_map->isa_mem_base+0xc0000), - left = length*512/sizeof(u_int); - left--; - *dst++=*src++); - - /* Disable the ROM and map the copy in virtual address space, note - * that the ROM has to be mapped as RAM since some BIOSes (at least - * Cirrus) perform write accesses to their own ROM. The reason seems - * to be that they check that they must execute from shadow RAM - * because accessing the ROM prevents accessing the video RAM - * according to comments in linux/arch/alpha/kernel/bios32.c. - */ - - pci_bootloader_write_config_dword(dev, PCI_ROM_ADDRESS, saved_rom); - vmap(p->vbase+0xc0000, (u_long)p->rom|PTE_RAM, length*512); - - /* Now actually emulate the ROM init routine */ - em86_enter(p); - - /* Free the acquired resources */ - vunmap(p->vbase+0xc0000); - pfree(p->rom); -} |