OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [powerpc/] [shared/] [bootloader/] [em86.c] - Blame information for rev 30

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.