blob: 92b058b644c267aaf2a1bba344c29086b2ff5f66 [file] [log] [blame]
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001/******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
4 * All rights reserved.
5 * This program and the accompanying materials
6 * are made available under the terms of the BSD License
7 * which accompanies this distribution, and is available at
8 * http://www.opensource.org/licenses/bsd-license.php
9 *
10 * Contributors:
11 * IBM Corporation - initial implementation
12 *****************************************************************************/
13
Uwe Hermann01ce6012010-03-05 10:03:50 +000014#include <types.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000015#include "compat/rtas.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000016
17#include "biosemu.h"
18#include "mem.h"
19#include "device.h"
20#include "debug.h"
21#include "pmm.h"
Uwe Hermann01ce6012010-03-05 10:03:50 +000022#include "interrupt.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000023
24#include <x86emu/x86emu.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000025#include "../x86emu/prim_ops.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000026
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000027#include <device/pci.h>
28#include <device/pci_ops.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000029
30
31//setup to run the code at the address, that the Interrupt Vector points to...
Myles Watsonb0259112010-03-05 18:27:19 +000032static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000033setupInt(int intNum)
34{
35 DEBUG_PRINTF_INTR("%s(%x): executing interrupt handler @%08x\n",
36 __func__, intNum, my_rdl(intNum * 4));
37 // push current R_FLG... will be popped by IRET
38 push_word((u16) M.x86.R_FLG);
39 CLEAR_FLAG(F_IF);
40 CLEAR_FLAG(F_TF);
41 // push current CS:IP to the stack, will be popped by IRET
42 push_word(M.x86.R_CS);
43 push_word(M.x86.R_IP);
44 // set CS:IP to the interrupt handler address... so the next executed instruction will
45 // be the interrupt handler
46 M.x86.R_CS = my_rdw(intNum * 4 + 2);
47 M.x86.R_IP = my_rdw(intNum * 4);
48}
49
50// handle int10 (VGA BIOS Interrupt)
Myles Watsonb0259112010-03-05 18:27:19 +000051static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000052handleInt10(void)
53{
54 // the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h
55 // function number in AH
56 //DEBUG_PRINTF_CS_IP("%s:\n", __func__);
57 //x86emu_dump_xregs();
58 //if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){
59 //X86EMU_trace_on();
60 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
61 //}
62 switch (M.x86.R_AH) {
63 case 0x00:
64 // set video mode
65 // BDA offset 49h is current video mode
66 my_wrb(0x449, M.x86.R_AL);
67 if (M.x86.R_AL > 7)
68 M.x86.R_AL = 0x20;
69 else if (M.x86.R_AL == 6)
70 M.x86.R_AL = 0x3f;
71 else
72 M.x86.R_AL = 0x30;
73 break;
74 case 0x01:
75 // set cursor shape
76 // ignore
77 break;
78 case 0x02:
79 // set cursor position
80 // BH: pagenumber, DX: cursor_pos (DH:row, DL:col)
81 // BDA offset 50h-60h are 8 cursor position words for
82 // eight possible video pages
83 my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX);
84 break;
85 case 0x03:
86 //get cursor position
87 // BH: pagenumber
88 // BDA offset 50h-60h are 8 cursor position words for
89 // eight possible video pages
90 M.x86.R_AX = 0;
91 M.x86.R_CH = 0; // start scan line ???
92 M.x86.R_CL = 0; // end scan line ???
93 M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2));
94 break;
95 case 0x05:
96 // set active page
97 // BDA offset 62h is current page number
98 my_wrb(0x462, M.x86.R_AL);
99 break;
100 case 0x06:
101 //scroll up windows
102 break;
103 case 0x07:
104 //scroll down windows
105 break;
106 case 0x08:
107 //read character and attribute at position
108 M.x86.R_AH = 0x07; // white-on-black
109 M.x86.R_AL = 0x20; // a space...
110 break;
111 case 0x09:
112 // write character and attribute
113 //AL: char, BH: page number, BL: attribute, CX: number of times to write
114 //BDA offset 62h is current page number
115 CHECK_DBG(DEBUG_PRINT_INT10) {
116 u32 i = 0;
117 if (M.x86.R_BH == my_rdb(0x462)) {
118 for (i = 0; i < M.x86.R_CX; i++)
119 printf("%c", M.x86.R_AL);
120 }
121 }
122 break;
123 case 0x0a:
124 // write character
125 //AL: char, BH: page number, BL: attribute, CX: number of times to write
126 //BDA offset 62h is current page number
127 CHECK_DBG(DEBUG_PRINT_INT10) {
128 u32 i = 0;
129 if (M.x86.R_BH == my_rdb(0x462)) {
130 for (i = 0; i < M.x86.R_CX; i++)
131 printf("%c", M.x86.R_AL);
132 }
133 }
134 break;
135 case 0x0e:
136 // teletype output: write character and advance cursor...
137 //AL: char, BH: page number, BL: attribute
138 //BDA offset 62h is current page number
139 CHECK_DBG(DEBUG_PRINT_INT10) {
140 // we ignore the pagenumber on this call...
141 //if (M.x86.R_BH == my_rdb(0x462))
142 {
143 printf("%c", M.x86.R_AL);
144 // for debugging, to read all lines
145 //if (M.x86.R_AL == 0xd) // carriage return
146 // printf("\n");
147 }
148 }
149 break;
150 case 0x0f:
151 // get video mode
152 // BDA offset 49h is current video mode
153 // BDA offset 62h is current page number
154 // BDA offset 4ah is columns on screen
155 M.x86.R_AH = 80; //number of character columns... we hardcode it to 80
156 M.x86.R_AL = my_rdb(0x449);
157 M.x86.R_BH = my_rdb(0x462);
158 break;
159 default:
160 printf("%s(): unknown function (%x) for int10 handler.\n",
161 __func__, M.x86.R_AH);
162 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
163 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
164 M.x86.R_DX);
165 HALT_SYS();
166 break;
167 }
168}
169
170// this table translates ASCII chars into their XT scan codes:
171static u8 keycode_table[256] = {
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 - 7
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8 - 15
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 23
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 - 31
176 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, // 32 - 39
177 0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35, // 40 - 47
178 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 48 - 55
179 0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35, // 56 - 63
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64 - 71
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72 - 79
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 87
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 95
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 103
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 104 - 111
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112 - 119
187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 - 127
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204}
205
206;
207
Myles Watsonb0259112010-03-05 18:27:19 +0000208static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000209translate_keycode(u64 * keycode)
210{
211 u8 scan_code = 0;
212 u8 char_code = 0;
213 if (*keycode < 256) {
214 scan_code = keycode_table[*keycode];
215 char_code = (u8) * keycode & 0xff;
216 } else {
217 switch (*keycode) {
218 case 0x1b50:
219 // F1
220 scan_code = 0x3b;
221 char_code = 0x0;
222 break;
223 default:
224 printf("%s(): unknown multibyte keycode: %llx\n",
225 __func__, *keycode);
226 break;
227 }
228 }
229 //assemble scan/char code in keycode
230 *keycode = (u64) ((((u16) scan_code) << 8) | char_code);
231}
232
233// handle int16 (Keyboard BIOS Interrupt)
Myles Watsonb0259112010-03-05 18:27:19 +0000234static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000235handleInt16(void)
236{
237 // keyboard buffer is in BIOS Memory Area:
238 // offset 0x1a (WORD) pointer to next char in keybuffer
239 // offset 0x1c (WORD) pointer to next insert slot in keybuffer
240 // offset 0x1e-0x3e: 16 WORD Ring Buffer
241 // since we currently always read the char from the FW buffer,
242 // we misuse the ring buffer, we use it as pointer to a u64 that stores
243 // multi-byte keys (e.g. special keys in VT100 terminal)
Martin Roth63373ed2013-07-08 16:24:19 -0600244 // and as long as a key is available (not 0) we don't read further keys
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000245 u64 *keycode = (u64 *) (M.mem_base + 0x41e);
246 s8 c;
247 // function number in AH
248 DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n",
249 __func__, M.x86.R_AH);
250 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX,
251 M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
252 switch (M.x86.R_AH) {
253 case 0x00:
254 // get keystroke
255 if (*keycode) {
256 M.x86.R_AX = (u16) * keycode;
257 // clear keycode
258 *keycode = 0;
259 } else {
260 M.x86.R_AH = 0x61; // scancode for space key
261 M.x86.R_AL = 0x20; // a space
262 }
263 break;
264 case 0x01:
265 // check keystroke
266 // ZF set = no keystroke
267 // read first byte of key code
268 if (*keycode) {
269 // already read, but not yet taken
270 CLEAR_FLAG(F_ZF);
271 M.x86.R_AX = (u16) * keycode;
272 } else {
273 /* TODO: we need getchar... */
274 c = -1; //getchar();
275 if (c == -1) {
276 // no key available
277 SET_FLAG(F_ZF);
278 } else {
279 *keycode = c;
280
281 // since after an ESC it may take a while to receive the next char,
282 // we send something that is not shown on the screen, and then try to get
283 // the next char
284 // TODO: only after ESC?? what about other multibyte keys
285 printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace
286
287 /* TODO: we need getchar... */
288 while ((c = -1 /*getchar()*/) != -1) {
289 *keycode = (*keycode << 8) | c;
290 DEBUG_PRINTF(" key read: %0llx\n",
291 *keycode);
292 }
293 translate_keycode(keycode);
294 DEBUG_PRINTF(" translated key: %0llx\n",
295 *keycode);
296 if (*keycode == 0) {
297 //not found
298 SET_FLAG(F_ZF);
299 } else {
300 CLEAR_FLAG(F_ZF);
301 M.x86.R_AX = (u16) * keycode;
302 //X86EMU_trace_on();
303 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
304 }
305 }
306 }
307 break;
308 default:
309 printf("%s(): unknown function (%x) for int16 handler.\n",
310 __func__, M.x86.R_AH);
311 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
312 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
313 M.x86.R_DX);
314 HALT_SYS();
315 break;
316 }
317}
318
319// handle int1a (PCI BIOS Interrupt)
Myles Watsonb0259112010-03-05 18:27:19 +0000320static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000321handleInt1a(void)
322{
323 // function number in AX
324 u8 bus, devfn, offs;
325 struct device* dev;
326 switch (M.x86.R_AX) {
327 case 0xb101:
328 // Installation check
329 CLEAR_FLAG(F_CF); // clear CF
330 M.x86.R_EDX = 0x20494350; // " ICP" endian swapped "PCI "
331 M.x86.R_AL = 0x1; // Config Space Mechanism 1 supported
332 M.x86.R_BX = 0x0210; // PCI Interface Level Version 2.10
333 M.x86.R_CL = 0xff; // number of last PCI Bus in system TODO: check!
334 break;
335 case 0xb102:
336 // Find PCI Device
337 // device_id in CX, vendor_id in DX
338 // device index in SI (i.e. if multiple devices with same vendor/device id
339 // are connected). We currently only support device index 0
340 //
341 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n",
342 __func__, M.x86.R_AX);
343 /* FixME: support SI != 0 */
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000344#if CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000345 dev = dev_find_device(M.x86.R_DX, M.x86.R_CX, 0);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000346 if (dev != 0) {
347 DEBUG_PRINTF_INTR
348 ("%s(): function %x: PCI Find Device --> 0x%04x\n",
349 __func__, M.x86.R_AX, M.x86.R_BX);
350
351 M.x86.R_BH = dev->bus->secondary;
352 M.x86.R_BL = dev->path.pci.devfn;
353 M.x86.R_AH = 0x00; // return code: success
354 CLEAR_FLAG(F_CF);
355#else
356 // only allow the device to find itself...
357 if ((M.x86.R_CX == bios_device.pci_device_id)
358 && (M.x86.R_DX == bios_device.pci_vendor_id)
359 // device index must be 0
360 && (M.x86.R_SI == 0)) {
361 CLEAR_FLAG(F_CF);
362 M.x86.R_AH = 0x00; // return code: success
363 M.x86.R_BH = bios_device.bus;
364 M.x86.R_BL = bios_device.devfn;
365#endif
366 } else {
367 DEBUG_PRINTF_INTR
368 ("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/00) \n",
369 __func__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX,
370 M.x86.R_SI, bios_device.pci_device_id,
371 bios_device.pci_vendor_id);
372
373 SET_FLAG(F_CF);
374 M.x86.R_AH = 0x86; // return code: device not found
375 }
376 break;
377 case 0xb108: //read configuration byte
378 case 0xb109: //read configuration word
379 case 0xb10a: //read configuration dword
380 bus = M.x86.R_BH;
381 devfn = M.x86.R_BL;
382 offs = M.x86.R_DI;
383 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
384 __func__, M.x86.R_AX, bus, devfn, offs);
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000385#if CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000386 dev = dev_find_slot(bus, devfn);
387 DEBUG_PRINTF_INTR("%s(): function: %x: dev_find_slot() returned: %s\n",
388 __func__, M.x86.R_AX, dev_path(dev));
389 if (dev == 0) {
390 // fail accesses to non-existent devices...
391#else
392 dev = bios_device.dev;
393 if ((bus != bios_device.bus)
394 || (devfn != bios_device.devfn)) {
395 // fail accesses to any device but ours...
396#endif
397 printf
398 ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
399 __func__, bus, bios_device.bus, devfn,
400 bios_device.devfn, offs);
401 SET_FLAG(F_CF);
402 M.x86.R_AH = 0x87; //return code: bad pci register
403 HALT_SYS();
404 return;
405 } else {
406 switch (M.x86.R_AX) {
407 case 0xb108:
408 M.x86.R_CL =
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000409#if CONFIG_PCI_OPTION_ROM_RUN_YABEL
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000410 pci_read_config8(dev, offs);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000411#else
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000412 (u8) rtas_pci_config_read(bios_device.
413 puid, 1,
414 bus, devfn,
415 offs);
416#endif
417 DEBUG_PRINTF_INTR
418 ("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n",
419 __func__, M.x86.R_AX, offs,
420 M.x86.R_CL);
421 break;
422 case 0xb109:
423 M.x86.R_CX =
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000424#if CONFIG_PCI_OPTION_ROM_RUN_YABEL
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000425 pci_read_config16(dev, offs);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000426#else
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000427 (u16) rtas_pci_config_read(bios_device.
428 puid, 2,
429 bus, devfn,
430 offs);
431#endif
432 DEBUG_PRINTF_INTR
433 ("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n",
434 __func__, M.x86.R_AX, offs,
435 M.x86.R_CX);
436 break;
437 case 0xb10a:
438 M.x86.R_ECX =
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000439#if CONFIG_PCI_OPTION_ROM_RUN_YABEL
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000440 pci_read_config32(dev, offs);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000441#else
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000442 (u32) rtas_pci_config_read(bios_device.
443 puid, 4,
444 bus, devfn,
445 offs);
446#endif
447 DEBUG_PRINTF_INTR
448 ("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n",
449 __func__, M.x86.R_AX, offs,
450 M.x86.R_ECX);
451 break;
452 }
453 CLEAR_FLAG(F_CF);
454 M.x86.R_AH = 0x0; // return code: success
455 }
456 break;
457 case 0xb10b: //write configuration byte
458 case 0xb10c: //write configuration word
459 case 0xb10d: //write configuration dword
460 bus = M.x86.R_BH;
461 devfn = M.x86.R_BL;
462 offs = M.x86.R_DI;
463 if ((bus != bios_device.bus)
464 || (devfn != bios_device.devfn)) {
465 // fail accesses to any device but ours...
466 printf
467 ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n",
468 __func__, bus, bios_device.bus, devfn,
469 bios_device.devfn, offs);
470 SET_FLAG(F_CF);
471 M.x86.R_AH = 0x87; //return code: bad pci register
472 HALT_SYS();
473 return;
474 } else {
475 switch (M.x86.R_AX) {
476 case 0xb10b:
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000477#if CONFIG_PCI_OPTION_ROM_RUN_YABEL
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000478 pci_write_config8(bios_device.dev, offs, M.x86.R_CL);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000479#else
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000480 rtas_pci_config_write(bios_device.puid, 1, bus,
481 devfn, offs, M.x86.R_CL);
482#endif
483 DEBUG_PRINTF_INTR
484 ("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n",
485 __func__, M.x86.R_AX, offs,
486 M.x86.R_CL);
487 break;
488 case 0xb10c:
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000489#if CONFIG_PCI_OPTION_ROM_RUN_YABEL
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000490 pci_write_config16(bios_device.dev, offs, M.x86.R_CX);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000491#else
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000492 rtas_pci_config_write(bios_device.puid, 2, bus,
493 devfn, offs, M.x86.R_CX);
494#endif
495 DEBUG_PRINTF_INTR
496 ("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n",
497 __func__, M.x86.R_AX, offs,
498 M.x86.R_CX);
499 break;
500 case 0xb10d:
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000501#if CONFIG_PCI_OPTION_ROM_RUN_YABEL
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000502 pci_write_config32(bios_device.dev, offs, M.x86.R_ECX);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000503#else
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000504 rtas_pci_config_write(bios_device.puid, 4, bus,
505 devfn, offs, M.x86.R_ECX);
506#endif
507 DEBUG_PRINTF_INTR
508 ("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n",
509 __func__, M.x86.R_AX, offs,
510 M.x86.R_ECX);
511 break;
512 }
513 CLEAR_FLAG(F_CF);
514 M.x86.R_AH = 0x0; // return code: success
515 }
516 break;
517 default:
518 printf("%s(): unknown function (%x) for int1a handler.\n",
519 __func__, M.x86.R_AX);
520 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
521 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
522 M.x86.R_DX);
523 HALT_SYS();
524 break;
525 }
526}
527
528// main Interrupt Handler routine, should be registered as x86emu interrupt handler
529void
530handleInterrupt(int intNum)
531{
532 u8 int_handled = 0;
533#ifndef DEBUG_PRINT_INT10
534 // this printf makes output by int 10 unreadable...
535 // so we only enable it, if int10 print is disabled
536 DEBUG_PRINTF_INTR("%s(%x)\n", __func__, intNum);
537#endif
538
Martin Roth63373ed2013-07-08 16:24:19 -0600539 /* check whether this interrupt has a function pointer set in yabel_intFuncArray and run that */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000540 if (yabel_intFuncArray[intNum]) {
541 DEBUG_PRINTF_INTR("%s(%x) intHandler overridden, calling it...\n", __func__, intNum);
542 int_handled = (*yabel_intFuncArray[intNum])();
543 } else {
544 switch (intNum) {
545 case 0x10: //BIOS video interrupt
546 case 0x42: // INT 10h relocated by EGA/VGA BIOS
547 case 0x6d: // INT 10h relocated by VGA BIOS
548 // get interrupt vector from IDT (4 bytes per Interrupt starting at address 0
549 if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address
550 (my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid
551 {
552#if 0
553 // ignore interrupt...
554 DEBUG_PRINTF_INTR
555 ("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n",
556 __func__, intNum, my_rdl(intNum * 4));
557 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
558 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
559 M.x86.R_DX);
560 //HALT_SYS();
561#endif
562 handleInt10();
563 int_handled = 1;
564 }
565 break;
566 case 0x16:
567 // Keyboard BIOS Interrupt
568 handleInt16();
569 int_handled = 1;
570 break;
571 case 0x1a:
572 // PCI BIOS Interrupt
573 handleInt1a();
574 int_handled = 1;
575 break;
576 case PMM_INT_NUM:
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000577 /* The self-defined PMM INT number, this is called by
578 * the code in PMM struct, and it is handled by
579 * pmm_handleInt()
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000580 */
581 pmm_handleInt();
582 int_handled = 1;
583 break;
584 default:
585 printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
586 my_rdl(intNum * 4));
587 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
588 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
589 M.x86.R_DX);
590 int_handled = 1;
591 HALT_SYS();
592 break;
593 }
594 }
595 // if we did not handle the interrupt, jump to the interrupt vector...
596 if (!int_handled) {
597 setupInt(intNum);
598 }
599}
600
601// prepare and execute Interrupt 10 (VGA Interrupt)
602void
603runInt10(void)
604{
605 // Initialize stack and data segment
606 M.x86.R_SS = STACK_SEGMENT;
607 M.x86.R_DS = DATA_SEGMENT;
608 M.x86.R_SP = STACK_START_OFFSET;
609
610 // push a HLT instruction and a pointer to it onto the stack
611 // any return will pop the pointer and jump to the HLT, thus
612 // exiting (more or less) cleanly
613 push_word(0xf4f4); //F4=HLT
614 //push_word(M.x86.R_SS);
615 //push_word(M.x86.R_SP + 2);
616
617 // setupInt will push the current CS and IP to the stack to return to it,
618 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
619 // to the stack
620 M.x86.R_CS = M.x86.R_SS;
621 M.x86.R_IP = M.x86.R_SP; // + 4;
622
623 CHECK_DBG(DEBUG_TRACE_X86EMU) {
624 X86EMU_trace_on();
625 }
626 CHECK_DBG(DEBUG_JMP) {
627 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
628 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
629 M.x86.debug |= DEBUG_TRACECALL_F;
630 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
631 }
632 setupInt(0x10);
633 DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n",
634 __func__);
635 X86EMU_exec();
636 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
637}
638
639// prepare and execute Interrupt 13 (Disk Interrupt)
640void
641runInt13(void)
642{
643 // Initialize stack and data segment
644 M.x86.R_SS = STACK_SEGMENT;
645 M.x86.R_DS = DATA_SEGMENT;
646 M.x86.R_SP = STACK_START_OFFSET;
647
648 // push a HLT instruction and a pointer to it onto the stack
649 // any return will pop the pointer and jump to the HLT, thus
650 // exiting (more or less) cleanly
651 push_word(0xf4f4); //F4=HLT
652 //push_word(M.x86.R_SS);
653 //push_word(M.x86.R_SP + 2);
654
655 // setupInt will push the current CS and IP to the stack to return to it,
656 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
657 // to the stack
658 M.x86.R_CS = M.x86.R_SS;
659 M.x86.R_IP = M.x86.R_SP;
660
661 CHECK_DBG(DEBUG_TRACE_X86EMU) {
662 X86EMU_trace_on();
663 }
664 CHECK_DBG(DEBUG_JMP) {
665 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
666 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
667 M.x86.debug |= DEBUG_TRACECALL_F;
668 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
669 }
670
671 setupInt(0x13);
672 DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n",
673 __func__);
674 X86EMU_exec();
675 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
676}