|
|
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.