Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / biosemu / biosemu.c
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 successful!\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 }