|
|
1.1 ! root 1: /****************************************************************************** ! 2: * Copyright (c) 2004, 2008 IBM Corporation ! 3: * All rights reserved. ! 4: * This program and the accompanying materials ! 5: * are made available under the terms of the BSD License ! 6: * which accompanies this distribution, and is available at ! 7: * http://www.opensource.org/licenses/bsd-license.php ! 8: * ! 9: * Contributors: ! 10: * IBM Corporation - initial implementation ! 11: *****************************************************************************/ ! 12: ! 13: ! 14: #include <stdio.h> ! 15: #include <stdlib.h> ! 16: #include <string.h> ! 17: ! 18: #include <stdint.h> ! 19: #include <cpu.h> ! 20: ! 21: #include "debug.h" ! 22: ! 23: #include <x86emu/x86emu.h> ! 24: #include <x86emu/regs.h> ! 25: #include <x86emu/prim_ops.h> // for push_word ! 26: ! 27: #include "biosemu.h" ! 28: #include "io.h" ! 29: #include "mem.h" ! 30: #include "interrupt.h" ! 31: #include "device.h" ! 32: ! 33: #include <rtas.h> ! 34: ! 35: ! 36: static X86EMU_memFuncs my_mem_funcs = { ! 37: my_rdb, my_rdw, my_rdl, ! 38: my_wrb, my_wrw, my_wrl ! 39: }; ! 40: ! 41: static X86EMU_pioFuncs my_pio_funcs = { ! 42: my_inb, my_inw, my_inl, ! 43: my_outb, my_outw, my_outl ! 44: }; ! 45: ! 46: void dump(uint8_t * addr, uint32_t len); ! 47: ! 48: uint32_t ! 49: biosemu(char argc, char **argv) ! 50: { ! 51: uint8_t *rom_image; ! 52: int i = 0; ! 53: uint8_t *biosmem; ! 54: uint32_t biosmem_size; ! 55: #ifdef DEBUG ! 56: //debug_flags = DEBUG_PRINT_INT10 | DEBUG_PNP;// | DEBUG_PMM;// | DEBUG_INTR | DEBUG_CHECK_VMEM_ACCESS | DEBUG_MEM | DEBUG_IO;// | DEBUG_TRACE_X86EMU | DEBUG_JMP; ! 57: #endif ! 58: if (argc < 4) { ! 59: printf("Usage %s <vmem_base> <vmem_size> <device_path> [<debug_flags>]\n", argv[0]); ! 60: for (i = 0; i < argc; i++) { ! 61: printf("argv[%d]: %s\n", i, argv[i]); ! 62: } ! 63: return -1; ! 64: } ! 65: // argv[1] is address of virtual BIOS mem... ! 66: // argv[2] is the size ! 67: biosmem = (uint8_t *) strtoul(argv[1], 0, 16); ! 68: biosmem_size = strtoul(argv[2], 0, 16); ! 69: if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) { ! 70: printf("Error: Not enough virtual memory: %x, required: %x!\n", ! 71: biosmem_size, MIN_REQUIRED_VMEM_SIZE); ! 72: return -1; ! 73: } ! 74: // argv[3] is the device to open and use... ! 75: if (dev_init(argv[3]) != 0) { ! 76: printf("Error initializing device!\n"); ! 77: return -1; ! 78: } ! 79: if (dev_check_exprom() != 0) { ! 80: printf("Error: Device Expansion ROM invalid!\n"); ! 81: return -1; ! 82: } ! 83: // argv[4] if set, is additional debug_flags ! 84: if (argc >= 5) { ! 85: debug_flags |= strtoul(argv[4], 0, 16); ! 86: printf("debug_flags: %x\n", debug_flags); ! 87: } ! 88: rom_image = (uint8_t *) bios_device.img_addr; ! 89: DEBUG_PRINTF("executing rom_image from %p\n", rom_image); ! 90: DEBUG_PRINTF("biosmem at %p\n", biosmem); ! 91: ! 92: DEBUG_PRINTF("Image Size: %d\n", bios_device.img_size); ! 93: ! 94: // in case we jump somewhere unexpected, or execution is finished, ! 95: // fill the biosmem with hlt instructions (0xf4) ! 96: memset(biosmem, 0xf4, biosmem_size); ! 97: ! 98: M.mem_base = (long) biosmem; ! 99: M.mem_size = biosmem_size; ! 100: DEBUG_PRINTF("membase set: %08x, size: %08x\n", (int) M.mem_base, ! 101: (int) M.mem_size); ! 102: ! 103: // copy expansion ROM image to segment OPTION_ROM_CODE_SEGMENT ! 104: // NOTE: this sometimes fails, some bytes are 0x00... so we compare ! 105: // after copying and do some retries... ! 106: uint8_t *mem_img = biosmem + (OPTION_ROM_CODE_SEGMENT << 4); ! 107: uint8_t copy_count = 0; ! 108: uint8_t cmp_result = 0; ! 109: do { ! 110: #if 0 ! 111: set_ci(); ! 112: memcpy(mem_img, rom_image, len); ! 113: clr_ci(); ! 114: #else ! 115: // memcpy fails... try copy byte-by-byte with set/clr_ci ! 116: uint8_t c; ! 117: for (i = 0; i < bios_device.img_size; i++) { ! 118: set_ci(); ! 119: c = *(rom_image + i); ! 120: if (c != *(rom_image + i)) { ! 121: clr_ci(); ! 122: printf("Copy failed at: %x/%x\n", i, ! 123: bios_device.img_size); ! 124: printf("rom_image(%x): %x, mem_img(%x): %x\n", ! 125: i, *(rom_image + i), i, *(mem_img + i)); ! 126: break; ! 127: } ! 128: clr_ci(); ! 129: *(mem_img + i) = c; ! 130: } ! 131: #endif ! 132: copy_count++; ! 133: set_ci(); ! 134: cmp_result = memcmp(mem_img, rom_image, bios_device.img_size); ! 135: clr_ci(); ! 136: } ! 137: while ((copy_count < 5) && (cmp_result != 0)); ! 138: if (cmp_result != 0) { ! 139: printf ! 140: ("\nCopying Expansion ROM Image to Memory failed after %d retries! (%x)\n", ! 141: copy_count, cmp_result); ! 142: dump(rom_image, 0x20); ! 143: dump(mem_img, 0x20); ! 144: return 0; ! 145: } ! 146: // setup default Interrupt Vectors ! 147: // some expansion ROMs seem to check for these addresses.. ! 148: // each handler is only an IRET (0xCF) instruction ! 149: // ROM BIOS Int 10 Handler F000:F065 ! 150: my_wrl(0x10 * 4, 0xf000f065); ! 151: my_wrb(0x000ff065, 0xcf); ! 152: // ROM BIOS Int 11 Handler F000:F84D ! 153: my_wrl(0x11 * 4, 0xf000f84d); ! 154: my_wrb(0x000ff84d, 0xcf); ! 155: // ROM BIOS Int 12 Handler F000:F841 ! 156: my_wrl(0x12 * 4, 0xf000f841); ! 157: my_wrb(0x000ff841, 0xcf); ! 158: // ROM BIOS Int 13 Handler F000:EC59 ! 159: my_wrl(0x13 * 4, 0xf000ec59); ! 160: my_wrb(0x000fec59, 0xcf); ! 161: // ROM BIOS Int 14 Handler F000:E739 ! 162: my_wrl(0x14 * 4, 0xf000e739); ! 163: my_wrb(0x000fe739, 0xcf); ! 164: // ROM BIOS Int 15 Handler F000:F859 ! 165: my_wrl(0x15 * 4, 0xf000f859); ! 166: my_wrb(0x000ff859, 0xcf); ! 167: // ROM BIOS Int 16 Handler F000:E82E ! 168: my_wrl(0x16 * 4, 0xf000e82e); ! 169: my_wrb(0x000fe82e, 0xcf); ! 170: // ROM BIOS Int 17 Handler F000:EFD2 ! 171: my_wrl(0x17 * 4, 0xf000efd2); ! 172: my_wrb(0x000fefd2, 0xcf); ! 173: // ROM BIOS Int 1A Handler F000:FE6E ! 174: my_wrl(0x1a * 4, 0xf000fe6e); ! 175: my_wrb(0x000ffe6e, 0xcf); ! 176: ! 177: // setup BIOS Data Area (0000:04xx, or 0040:00xx) ! 178: // we currently 0 this area, meaning "we dont have ! 179: // any hardware" :-) no serial/parallel ports, floppys, ... ! 180: memset(biosmem + 0x400, 0x0, 0x100); ! 181: ! 182: // at offset 13h in BDA is the memory size in kbytes ! 183: my_wrw(0x413, biosmem_size / 1024); ! 184: // at offset 0eh in BDA is the segment of the Extended BIOS Data Area ! 185: // see setup further down ! 186: my_wrw(0x40e, INITIAL_EBDA_SEGMENT); ! 187: // TODO: setup BDA Video Data ( offset 49h-66h) ! 188: // e.g. to store video mode, cursor position, ... ! 189: // in int10 (done) handler and VBE Functions ! 190: ! 191: // TODO: setup BDA Fixed Disk Data ! 192: // 74h: Fixed Disk Last Operation Status ! 193: // 75h: Fixed Disk Number of Disk Drives ! 194: ! 195: // TODO: check BDA for further needed data... ! 196: ! 197: //setup Extended BIOS Data Area ! 198: //we currently 0 this area ! 199: memset(biosmem + (INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE); ! 200: // at offset 0h in EBDA is the size of the EBDA in KB ! 201: my_wrw((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024); ! 202: //TODO: check for further needed EBDA data... ! 203: ! 204: // setup original ROM BIOS Area (F000:xxxx) ! 205: char *date = "06/11/99"; ! 206: for (i = 0; date[i]; i++) ! 207: my_wrb(0xffff5 + i, date[i]); ! 208: // set up eisa ident string ! 209: char *ident = "PCI_ISA"; ! 210: for (i = 0; ident[i]; i++) ! 211: my_wrb(0xfffd9 + i, ident[i]); ! 212: ! 213: // write system model id for IBM-AT ! 214: // according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515, ! 215: // model FC is the original AT and also used in all DOSEMU Versions. ! 216: my_wrb(0xFFFFE, 0xfc); ! 217: ! 218: //setup interrupt handler ! 219: X86EMU_intrFuncs intrFuncs[256]; ! 220: for (i = 0; i < 256; i++) ! 221: intrFuncs[i] = handleInterrupt; ! 222: X86EMU_setupIntrFuncs(intrFuncs); ! 223: X86EMU_setupPioFuncs(&my_pio_funcs); ! 224: X86EMU_setupMemFuncs(&my_mem_funcs); ! 225: ! 226: // setup the CPU ! 227: M.x86.R_AH = bios_device.bus; ! 228: M.x86.R_AL = bios_device.devfn; ! 229: M.x86.R_DX = 0x80; ! 230: M.x86.R_EIP = 3; ! 231: M.x86.R_CS = OPTION_ROM_CODE_SEGMENT; ! 232: ! 233: // Initialize stack and data segment ! 234: M.x86.R_SS = STACK_SEGMENT; ! 235: M.x86.R_SP = STACK_START_OFFSET; ! 236: M.x86.R_DS = DATA_SEGMENT; ! 237: ! 238: // push a HLT instruction and a pointer to it onto the stack ! 239: // any return will pop the pointer and jump to the HLT, thus ! 240: // exiting (more or less) cleanly ! 241: push_word(0xf4f4); //F4=HLT ! 242: push_word(M.x86.R_SS); ! 243: push_word(M.x86.R_SP + 2); ! 244: ! 245: CHECK_DBG(DEBUG_TRACE_X86EMU) { ! 246: X86EMU_trace_on(); ! 247: } else { ! 248: #ifdef DEBUG ! 249: M.x86.debug |= DEBUG_SAVE_IP_CS_F; ! 250: M.x86.debug |= DEBUG_DECODE_F; ! 251: M.x86.debug |= DEBUG_DECODE_NOPRINT_F; ! 252: #endif ! 253: } ! 254: CHECK_DBG(DEBUG_JMP) { ! 255: M.x86.debug |= DEBUG_TRACEJMP_F; ! 256: M.x86.debug |= DEBUG_TRACEJMP_REGS_F; ! 257: M.x86.debug |= DEBUG_TRACECALL_F; ! 258: M.x86.debug |= DEBUG_TRACECALL_REGS_F; ! 259: } ! 260: ! 261: DEBUG_PRINTF("Executing Initialization Vector...\n"); ! 262: X86EMU_exec(); ! 263: DEBUG_PRINTF("done\n"); ! 264: ! 265: // according to PNP BIOS Spec, Option ROMs should upon exit, return some boot device status in ! 266: // AX (see PNP BIOS Spec Section 3.3 ! 267: DEBUG_PRINTF_CS_IP("Option ROM Exit Status: %04x\n", M.x86.R_AX); ! 268: #ifdef DEBUG ! 269: DEBUG_PRINTF("Exit Status Decode:\n"); ! 270: if (M.x86.R_AX & 0x100) { // bit 8 ! 271: DEBUG_PRINTF ! 272: (" IPL Device supporting INT 13h Block Device Format:\n"); ! 273: switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 ! 274: case 0: ! 275: DEBUG_PRINTF(" No IPL Device attached\n"); ! 276: break; ! 277: case 1: ! 278: DEBUG_PRINTF(" IPL Device status unknown\n"); ! 279: break; ! 280: case 2: ! 281: DEBUG_PRINTF(" IPL Device attached\n"); ! 282: break; ! 283: case 3: ! 284: DEBUG_PRINTF(" IPL Device status RESERVED!!\n"); ! 285: break; ! 286: } ! 287: } ! 288: if (M.x86.R_AX & 0x80) { // bit 7 ! 289: DEBUG_PRINTF ! 290: (" Output Device supporting INT 10h Character Output:\n"); ! 291: switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 ! 292: case 0: ! 293: DEBUG_PRINTF(" No Display Device attached\n"); ! 294: break; ! 295: case 1: ! 296: DEBUG_PRINTF(" Display Device status unknown\n"); ! 297: break; ! 298: case 2: ! 299: DEBUG_PRINTF(" Display Device attached\n"); ! 300: break; ! 301: case 3: ! 302: DEBUG_PRINTF(" Display Device status RESERVED!!\n"); ! 303: break; ! 304: } ! 305: } ! 306: if (M.x86.R_AX & 0x40) { // bit 6 ! 307: DEBUG_PRINTF ! 308: (" Input Device supporting INT 9h Character Input:\n"); ! 309: switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 ! 310: case 0: ! 311: DEBUG_PRINTF(" No Input Device attached\n"); ! 312: break; ! 313: case 1: ! 314: DEBUG_PRINTF(" Input Device status unknown\n"); ! 315: break; ! 316: case 2: ! 317: DEBUG_PRINTF(" Input Device attached\n"); ! 318: break; ! 319: case 3: ! 320: DEBUG_PRINTF(" Input Device status RESERVED!!\n"); ! 321: break; ! 322: } ! 323: } ! 324: #endif ! 325: // check wether the stack is "clean" i.e. containing the HLT instruction ! 326: // we pushed before executing, and pointing to the original stack address... ! 327: // indicating that the initialization probably was successful ! 328: if ((pop_word() == 0xf4f4) && (M.x86.R_SS == STACK_SEGMENT) ! 329: && (M.x86.R_SP == STACK_START_OFFSET)) { ! 330: DEBUG_PRINTF("Stack is clean, initialization successfull!\n"); ! 331: } else { ! 332: DEBUG_PRINTF ! 333: ("Stack unclean, initialization probably NOT COMPLETE!!!\n"); ! 334: DEBUG_PRINTF("SS:SP = %04x:%04x, expected: %04x:%04x\n", ! 335: M.x86.R_SS, M.x86.R_SP, STACK_SEGMENT, ! 336: STACK_START_OFFSET); ! 337: } ! 338: ! 339: ! 340: // TODO: according to the BIOS Boot Spec initializations may be ended using INT18h and setting ! 341: // the status. ! 342: // We need to implement INT18 accordingly, pseudo code is in specsbbs101.pdf page 30 ! 343: // (also for Int19) ! 344: return 0; ! 345: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.