[acc25ee] | 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.OARcorp.com/rtems/license.html. |
---|
| 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 | #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 | |
---|