source: rtems/c/src/lib/libbsp/powerpc/shared/bootloader/em86.c @ 116633f

Last change on this file since 116633f was 116633f, checked in by Joel Sherrill <joel.sherrill@…>, on 09/04/03 at 18:45:20

2003-09-04 Joel Sherrill <joel@…>

  • bootloader/bootldr.h, bootloader/em86.c, bootloader/em86real.S, bootloader/exception.S, bootloader/head.S, bootloader/lib.c, bootloader/misc.c, bootloader/mm.c, bootloader/pci.c, clock/p_clock.c, console/console.c, console/consoleIo.h, console/inch.c, console/keyboard.h, console/polled_io.c, include/bsp.h, irq/i8259.c, irq/irq.c, irq/irq.h, irq/irq_asm.S, irq/irq_init.c, motorola/motorola.c, motorola/motorola.h, openpic/openpic.c, openpic/openpic.h, pci/pci.c, residual/residual.c, start/start.S, startup/bspstart.c, vectors/vectors.h, vectors/vectors_init.c: URL for license changed.
  • Property mode set to 100644
File size: 14.8 KB
Line 
1/*
2 *  em86.c -- Include file for bootloader.
3 *
4 *  Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
5 *
6 *  Modified to compile in RTEMS development environment
7 *  by Eric Valette
8 *
9 *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
10 *
11 *  The license and distribution terms for this file may be
12 *  found in found in the file LICENSE in this distribution or at
13 *  http://www.rtems.com/license/LICENSE.
14 *
15 * $Id$
16 */
17
18/*****************************************************************************
19*
20* Code to interpret Video BIOS ROM routines.
21*
22*
23******************************************************************************/
24
25/* These include are for the development version only */
26#include <sys/types.h>
27#include "pci.h"
28#include <libcpu/byteorder.h>
29#ifdef __BOOT__
30#include "bootldr.h"
31#include <limits.h>
32#include <rtems/bspIo.h>
33#endif
34
35
36/* Code options,  put them on the compiler command line */     
37/* #define EIP_STATS */ /* EIP based profiling */
38/* #undef EIP_STATS */
39
40typedef union _reg_type1 {
41        unsigned e;
42        unsigned short x;
43        struct {
44                unsigned char l, h;
45        } lh;
46} reg_type1;
47
48typedef union _reg_type2 {
49        unsigned e;
50        unsigned short x;
51} reg_type2;
52
53typedef struct _x86 {
54        reg_type1
55          _eax, _ecx, _edx, _ebx;
56        reg_type2
57          _esp, _ebp, _esi, _edi;
58        unsigned
59          es, cs, ss, ds, fs, gs, eip, eflags;
60        unsigned char
61          *esbase, *csbase, *ssbase, *dsbase, *fsbase, *gsbase;
62        volatile unsigned char *iobase;
63        unsigned char *ioperm;
64        unsigned
65          reason, nexteip, parm1, parm2, opcode, base;
66        unsigned *optable, opreg; /* no more used! */
67        unsigned char* vbase;
68        unsigned instructions;
69#ifdef __BOOT__
70        u_char * ram;
71        u_char * rom;
72        struct pci_dev * dev;
73#else
74        unsigned filler[14]; /* Skip to  next 64 byte boundary */
75        unsigned eipstats[32768][2];
76#endif
77} x86;
78
79x86 v86_private __attribute__((aligned(32)));
80
81
82/* Emulator is in another source file */
83extern
84void em86_enter(x86 * p);
85
86#define EAX (p->_eax.e)
87#define ECX (p->_ecx.e)
88#define EDX (p->_edx.e)
89#define EBX (p->_ebx.e)
90#define ESP (p->_esp.e)
91#define EBP (p->_ebp.e)
92#define ESI (p->_esi.e)
93#define EDI (p->_edi.e)
94#define AX (p->_eax.x)
95#define CX (p->_ecx.x)
96#define DX (p->_edx.x)
97#define BX (p->_ebx.x)
98#define SP (p->_esp.x)
99#define BP (p->_ebp.x)
100#define SI (p->_esi.x)
101#define DI (p->_edi.x)
102#define AL (p->_eax.lh.l)
103#define CL (p->_ecx.lh.l)
104#define DL (p->_edx.lh.l)
105#define BL (p->_ebx.lh.l)
106#define AH (p->_eax.lh.h)
107#define CH (p->_ecx.lh.h)
108#define DH (p->_edx.lh.h)
109#define BH (p->_ebx.lh.h)
110
111/* Function used to debug */
112#ifdef __BOOT__
113#define printf printk
114#endif
115#ifdef DEBUG
116static void dump86(x86 * p){
117        unsigned char *s = p->csbase + p->eip;
118        printf("cs:eip=%04x:%08x, eax=%08x, ecx=%08x, edx=%08x, ebx=%08x\n",
119               p->cs, p->eip, ld_le32(&EAX),
120               ld_le32(&ECX), ld_le32(&EDX), ld_le32(&EBX));
121        printf("ss:esp=%04x:%08x, ebp=%08x, esi=%08x, edi=%08x, efl=%08x\n",
122               p->ss, ld_le32(&ESP), ld_le32(&EBP),
123               ld_le32(&ESI), ld_le32(&EDI), p->eflags);
124        printf("nip=%08x, ds=%04x, es=%04x, fs=%04x, gs=%04x, total=%d\n",
125               p->nexteip, p->ds, p->es, p->fs, p->gs, p->instructions);
126        printf("code: %02x %02x %02x %02x %02x %02x "
127               "%02x %02x %02x %02x %02x %02x\n",
128               s[0], s[1], s[2], s[3], s[4], s[5],
129               s[6], s[7], s[8], s[9], s[10], s[11]);
130#ifndef __BOOT__
131        printf("op1=%08x, op2=%08x, result=%08x, flags=%08x\n",
132               p->filler[11], p->filler[12], p->filler[13], p->filler[14]);
133#endif
134}
135#else
136#define dump86(x)
137#endif
138
139int bios86pci(x86 * p) {
140        unsigned reg=ld_le16(&DI);
141        reg_type2 tmp;
142       
143        if (AL>=8 && AL<=13 && reg>0xff) {
144                AH = PCIBIOS_BAD_REGISTER_NUMBER;
145        } else {
146                switch(AL) {
147                case 2: /* find_device */
148                  /* Should be improved for BIOS able to handle
149                   * multiple devices. We simply suppose the BIOS
150                   * inits a single device, and return an error
151                   * if it tries to find more...
152                   */
153                  if (SI) {
154                        AH=PCIBIOS_DEVICE_NOT_FOUND;
155                  } else {
156                        BH = p->dev->bus->number;
157                        BL = p->dev->devfn;
158                        AH = 0;
159                  }
160                  break;
161                /*
162                case 3: find_class not implemented for now.
163                */
164                case 8:       /* read_config_byte */
165                  AH=pcibios_read_config_byte(BH, BL, reg, &CL);
166                  break;
167                case 9:       /* read_config_word */
168                  AH=pcibios_read_config_word(BH, BL, reg, &tmp.x);
169                  CX=ld_le16(&tmp.x);
170                  break;
171                case 10:      /* read_config_dword */
172                  AH=pcibios_read_config_dword(BH, BL, reg, &tmp.e);
173                  ECX=ld_le32(&tmp.e);
174                  break;
175                case 11:      /* write_config_byte */
176                  AH=pcibios_write_config_byte(BH, BL, reg, CL);
177                  break;
178                case 12:      /* write_config_word */
179                  AH=pcibios_write_config_word(BH, BL, reg, ld_le16(&CX));
180                  break;
181                case 13:      /* write_config_dword */
182                  AH=pcibios_write_config_dword(BH, BL, reg, ld_le32(&ECX));
183                  break;
184                default:
185                  printf("Unimplemented or illegal PCI service call #%d!\n",
186                         AL);
187                  return 1;
188                }
189        }
190        p->eip = p->nexteip;
191        /* Set/clear carry according to result */
192        if (AH) p->eflags |= 1; else p->eflags &=~1;
193        return 0;
194}
195
196void push2(x86 *p, unsigned value) {
197        unsigned char * sbase= p->ssbase;
198        unsigned newsp = (ld_le16(&SP)-2)&0xffff;
199        st_le16(&SP,newsp);
200        st_le16((unsigned short *)(sbase+newsp), value);
201}
202
203unsigned pop2(x86 *p) {
204        unsigned char * sbase=p->ssbase;
205        unsigned oldsp = ld_le16(&SP);
206        st_le16(&SP,oldsp+2);
207        return ld_le16((unsigned short *)(sbase+oldsp));
208}
209
210int int10h(x86 * p) { /* Process BIOS video interrupt */
211        unsigned vector;
212        vector=ld_le32((unsigned *)p->vbase+0x10);
213        if (((vector&0xffff0000)>>16)==0xc000) {
214                push2(p, p->eflags);
215                push2(p, p->cs);
216                push2(p, p->nexteip);
217                p->cs=vector>>16;
218                p->csbase=p->vbase + (p->cs<<4);
219                p->eip=vector&0xffff;
220#if 1
221                p->eflags&=0xfcff;  /* Clear AC/TF/IF */
222#else
223                p->eflags = (p->eflags&0xfcff)|0x100;  /* Set TF for debugging */
224#endif
225                /* p->eflags|=0x100; uncomment to force a trap */
226                return(0);
227        } else {
228                switch(AH) {
229                case 0x12:
230                  switch(BL){
231                  case 0x32:
232                    p->eip=p->nexteip;
233                    return(0);
234                    break;
235                  default:
236                    break;
237                  }
238                default:
239                  break;
240                }
241                printf("unhandled soft interrupt 0x10: vector=%x\n", vector);
242                return(1);
243        }
244}
245
246int process_softint(x86 * p) {
247#if 0
248        if (p->parm1!=0x10 || AH!=0x0e) {
249                printf("Soft interrupt\n");
250                dump86(p);
251        }
252#endif
253        switch(p->parm1) {
254        case 0x10: /* BIOS video interrupt */
255          return int10h(p);
256        case 0x1a:
257          if(AH==0xb1) return bios86pci(p);
258          break;
259        default:
260          break;
261        }
262        dump86(p);
263        printf("Unhandled soft interrupt number 0x%04x, AX=0x%04x\n",
264             p->parm1, ld_le16(&AX));
265        return(1);
266}
267
268/* The only function called back by the emulator is em86_trap, all
269   instructions may that change the code segment are trapped here.
270   p->reason is one of the following codes.  */
271#define code_zerdiv     0
272#define code_trap       1
273#define code_int3       3
274#define code_into       4
275#define code_bound      5
276#define code_ud         6
277#define code_dna        7
278       
279#define code_iretw      256
280#define code_iretl      257
281#define code_lcallw     258
282#define code_lcalll     259
283#define code_ljmpw      260
284#define code_ljmpl      261
285#define code_lretw      262
286#define code_lretl      263
287#define code_softint    264
288#define code_lock       265     /* Lock prefix */
289/* Codes 1024 to 2047 are used for I/O port access instructions:
290 - The three LSB define the port size (1, 2 or 4)
291 - bit of weight 512 means out if set, in if clear
292 - bit of weight 256 means ins/outs if set, in/out if clear
293 - bit of weight 128 means use esi/edi if set, si/di if clear
294   (only used for ins/outs instructions, always clear for in/out)       
295 */
296#define code_inb        1024+1
297#define code_inw        1024+2
298#define code_inl        1024+4
299#define code_outb       1024+512+1
300#define code_outw       1024+512+2
301#define code_outl       1024+512+4
302#define code_insb_a16   1024+256+1
303#define code_insw_a16   1024+256+2
304#define code_insl_a16   1024+256+4
305#define code_outsb_a16  1024+512+256+1
306#define code_outsw_a16  1024+512+256+2
307#define code_outsl_a16  1024+512+256+4
308#define code_insb_a32   1024+256+128+1
309#define code_insw_a32   1024+256+128+2
310#define code_insl_a32   1024+256+128+4
311#define code_outsb_a32  1024+512+256+128+1
312#define code_outsw_a32  1024+512+256+128+2
313#define code_outsl_a32  1024+512+256+128+4
314
315int em86_trap(x86 *p) {
316#ifndef __BOOT__
317          int i;
318          unsigned char command[80];
319          unsigned char *verb, *t;
320          unsigned short *fp;
321          static unsigned char def=0;
322          static unsigned char * bptaddr=NULL;  /* Breakpoint address */
323          static unsigned char bptopc; /* Replaced breakpoint opcode */
324          unsigned char cmd;
325          unsigned tmp;
326#endif
327          switch(p->reason) {
328          case code_int3:
329#ifndef __BOOT__
330            if(p->csbase+p->eip == bptaddr) {
331              *bptaddr=bptopc;
332              bptaddr=NULL;
333            }
334            else printf("Unexpected ");
335#endif
336            printf("Breakpoint Interrupt !\n");
337            /* Note that this fallthrough (no break;) is on purpose */
338#ifdef __BOOT__
339            return 0;
340#else
341          case code_trap:
342            dump86(p);
343            for(;;) {
344                printf("b(reakpoint, g(o, q(uit, s(tack, t(race ? [%c] ", def);
345                fgets(command,sizeof(command),stdin);
346                verb = strtok(command,"         \n");
347                if(verb) cmd=*verb; else cmd=def;
348                def=0;
349                switch(cmd) {
350                case 'b':
351                case 'B':
352                  if(bptaddr) *bptaddr=bptopc;
353                  t=strtok(0,"  \n");
354                  i=sscanf(t,"%x",&tmp);
355                  if(i==1) {
356                    bptaddr=p->vbase + tmp;
357                    bptopc=*bptaddr;
358                    *bptaddr=0xcc;
359                  } else bptaddr=NULL;
360                  break;
361                case 'q':
362                case 'Q':
363                  return 1;
364                  break;
365                 
366                case 'g':
367                case 'G':
368                  p->eflags &= ~0x100;
369                  return 0;
370                  break;
371                 
372                case 's':
373                case 'S': /* Print the 8 stack top words */
374                  fp = (unsigned short *)(p->ssbase+ld_le16(&SP));
375                  printf("Stack [%04x:%04x]: %04x %04x %04x %04x %04x %04x %04x %04x\n",
376                         p->ss, ld_le16(&SP),
377                         ld_le16(fp+0), ld_le16(fp+1), ld_le16(fp+2), ld_le16(fp+3),
378                         ld_le16(fp+4), ld_le16(fp+5), ld_le16(fp+6), ld_le16(fp+7));
379                  break;
380                case 't':
381                case 'T':
382                  p->eflags |= 0x10100;  /* Set the resume and trap flags */
383                  def='t';
384                  return 0;
385                  break;
386                  /* Should add some code to edit registers */
387                }
388            }
389#endif
390            break;
391          case code_ud:
392            printf("Attempt to execute an unimplemented"
393                   "or undefined opcode!\n");
394            dump86(p);
395            return(1); /* exit interpreter */
396            break;
397          case code_dna:
398            printf("Attempt to execute a floating point instruction!\n");
399            dump86(p);
400            return(1);
401            break;
402          case code_softint:
403            return process_softint(p);
404            break;
405          case code_iretw:
406            p->eip=pop2(p);
407            p->cs=pop2(p);
408            p->csbase=p->vbase + (p->cs<<4);
409            p->eflags= (p->eflags&0xfffe0000)|pop2(p);
410            /* p->eflags|= 0x100; */ /* Uncomment to trap after iretws */
411            return(0);
412            break;
413#ifndef __BOOT__
414          case code_inb:
415          case code_inw:
416          case code_inl:
417          case code_insb_a16:
418          case code_insw_a16:
419          case code_insl_a16:
420          case code_insb_a32:
421          case code_insw_a32:
422          case code_insl_a32:
423          case code_outb:
424          case code_outw:
425          case code_outl:
426          case code_outsb_a16:
427          case code_outsw_a16:
428          case code_outsl_a16:
429          case code_outsb_a32:
430          case code_outsw_a32:
431          case code_outsl_a32:
432            /* For now we simply enable I/O to the ports and continue */
433            for(i=p->parm1; i<p->parm1+(p->reason&7); i++) {
434              p->ioperm[i/8] &= ~(1<<i%8);
435            }
436            printf("Access to ports %04x-%04x enabled.\n",
437                   p->parm1, p->parm1+(p->reason&7)-1);
438            return(0);
439#endif
440          case code_lretw:
441            /* Check for the exit eyecatcher */
442            if ( *(u_int *)(p->ssbase+ld_le16(&SP)) == UINT_MAX) return 1;
443            /* No break on purpose */
444          default:
445            dump86(p);
446            printf("em86_trap called with unhandled reason code !\n");
447            return(1);
448
449          }
450}
451
452void cleanup_v86_mess(void) {
453        x86 *p = (x86 *) bd->v86_private;
454       
455        /* This automatically removes the mappings ! */
456        vfree(p->vbase);
457        p->vbase = 0;
458        pfree(p->ram);
459        p->ram = 0;
460        sfree(p->ioperm);
461        p->ioperm=0;
462}
463     
464
465int init_v86(void) {
466        x86 *p = (x86 *) bd->v86_private;
467       
468        /* p->vbase is non null when the v86 is properly set-up */
469        if (p->vbase) return 0;
470
471        /* Set everything to 0 */
472        memset(p, 0, sizeof(*p));
473        p->ioperm = salloc(65536/8+1);
474        p->ram = palloc(0xa0000);
475        p->iobase = ptr_mem_map->io_base;
476
477        if (!p->ram || !p->ioperm) return 1;
478
479        /* The ioperm array must have an additional byte at the end ! */
480        p->ioperm[65536/8] = 0xff;
481
482        p->vbase = valloc(0x110000);
483        if (!p->vbase) return 1;
484
485        /* These calls should never fail. */
486        vmap(p->vbase, (u_long)p->ram|PTE_RAM, 0xa0000);
487        vmap(p->vbase+0x100000, (u_long)p->ram|PTE_RAM, 0x10000);
488        vmap(p->vbase+0xa0000,
489             ((u_long)ptr_mem_map->isa_mem_base+0xa0000)|PTE_IO, 0x20000);
490        return 0;
491}
492
493void em86_main(struct pci_dev *dev){
494        x86 *p = (x86 *) bd->v86_private;
495        u_short signature;
496        u_char length;
497        volatile u_int *src;
498        u_int *dst, left, saved_rom;
499#if defined(MONITOR_IO) && !defined(__BOOT__)
500#define IOMASK 0xff
501#else
502#define IOMASK 0
503#endif
504
505       
506#ifndef __BOOT__
507        int i;
508        /* Allow or disable access to all ports */
509        for(i=0; i<65536/8; i++) p->ioperm[i]=IOMASK;
510        p->ioperm[i] = 0xff; /* Last unused byte must have this value */
511#endif
512        p->dev = dev;
513        memset(p->vbase, 0, 0xa0000);
514        /* Set up a few registers */
515        p->cs = 0xc000; p->csbase = p->vbase + 0xc0000;
516        p->ss = 0x1000; p->ssbase = p->vbase + 0x10000;
517        p->eflags=0x200;
518        st_le16(&SP,0xfffc); p->eip=3;
519
520        p->dsbase = p->esbase = p->fsbase = p->gsbase = p->vbase;
521
522        /* Follow the PCI BIOS specification */
523        AH=dev->bus->number;
524        AL=dev->devfn;
525
526        /* All other registers are irrelevant except ES:DI which
527         * should point to a PnP installation check block. This
528         * is not yet implemented due to lack of references. */
529
530        /* Store a return address of 0xffff:0xffff as eyecatcher */
531        *(u_int *)(p->ssbase+ld_le16(&SP)) = UINT_MAX;
532       
533        /* Interrupt for BIOS EGA services is 0xf000:0xf065 (int 0x10) */
534        st_le32((u_int *)p->vbase + 0x10, 0xf000f065);
535       
536        /* Enable the ROM, read it and disable it immediately */
537        pci_read_config_dword(dev, PCI_ROM_ADDRESS, &saved_rom);
538        pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0x000c0001);
539
540        /* Check that there is an Intel ROM. Should we also check that
541         * the first instruction is a jump (0xe9 or 0xeb) ?
542         */
543        signature = *(u_short *)(ptr_mem_map->isa_mem_base+0xc0000);
544        if (signature!=0x55aa) {
545                printf("bad signature: %04x.\n", signature);
546                return;
547        }
548        /* Allocate memory and copy the video rom to vbase+0xc0000; */
549        length = ptr_mem_map->isa_mem_base[0xc0002];
550        p->rom = palloc(length*512);
551        if (!p->rom) return;
552
553
554        for(dst=(u_int *) p->rom,
555            src=(volatile u_int *)(ptr_mem_map->isa_mem_base+0xc0000),
556            left = length*512/sizeof(u_int);
557            left--;
558            *dst++=*src++);
559       
560        /* Disable the ROM and map the copy in virtual address space, note
561         * that the ROM has to be mapped as RAM since some BIOSes (at least
562         * Cirrus) perform write accesses to their own ROM. The reason seems
563         * to be that they check that they must execute from shadow RAM
564         * because accessing the ROM prevents accessing the video RAM       
565         * according to comments in linux/arch/alpha/kernel/bios32.c.
566         */
567       
568        pci_write_config_dword(dev, PCI_ROM_ADDRESS, saved_rom);
569        vmap(p->vbase+0xc0000, (u_long)p->rom|PTE_RAM, length*512);
570
571        /* Now actually emulate the ROM init routine */
572        em86_enter(p);
573       
574        /* Free the acquired resources */
575        vunmap(p->vbase+0xc0000);
576        pfree(p->rom);
577}
578
579
580
581
582
Note: See TracBrowser for help on using the repository browser.