blob: 338156f8ed422f2e95c42565aa0a19ed10c9c23f [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>
Martin Rotha9e1a222016-01-14 14:15:24 -07004 *
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00005 * All rights reserved.
Martin Rotha9e1a222016-01-14 14:15:24 -07006 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000030 *
31 * Contributors:
32 * IBM Corporation - initial implementation
33 *****************************************************************************/
34
Uwe Hermann01ce6012010-03-05 10:03:50 +000035#include <types.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000036#include "compat/rtas.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000037
38#include "biosemu.h"
39#include "mem.h"
40#include "device.h"
41#include "debug.h"
42#include "pmm.h"
Uwe Hermann01ce6012010-03-05 10:03:50 +000043#include "interrupt.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000044
45#include <x86emu/x86emu.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000046#include "../x86emu/prim_ops.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000047
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000048#include <device/pci.h>
49#include <device/pci_ops.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000050
51
52//setup to run the code at the address, that the Interrupt Vector points to...
Myles Watsonb0259112010-03-05 18:27:19 +000053static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000054setupInt(int intNum)
55{
56 DEBUG_PRINTF_INTR("%s(%x): executing interrupt handler @%08x\n",
57 __func__, intNum, my_rdl(intNum * 4));
58 // push current R_FLG... will be popped by IRET
59 push_word((u16) M.x86.R_FLG);
60 CLEAR_FLAG(F_IF);
61 CLEAR_FLAG(F_TF);
62 // push current CS:IP to the stack, will be popped by IRET
63 push_word(M.x86.R_CS);
64 push_word(M.x86.R_IP);
65 // set CS:IP to the interrupt handler address... so the next executed instruction will
66 // be the interrupt handler
67 M.x86.R_CS = my_rdw(intNum * 4 + 2);
68 M.x86.R_IP = my_rdw(intNum * 4);
69}
70
71// handle int10 (VGA BIOS Interrupt)
Myles Watsonb0259112010-03-05 18:27:19 +000072static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000073handleInt10(void)
74{
75 // the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h
76 // function number in AH
77 //DEBUG_PRINTF_CS_IP("%s:\n", __func__);
78 //x86emu_dump_xregs();
79 //if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){
80 //X86EMU_trace_on();
81 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
82 //}
83 switch (M.x86.R_AH) {
84 case 0x00:
85 // set video mode
86 // BDA offset 49h is current video mode
87 my_wrb(0x449, M.x86.R_AL);
88 if (M.x86.R_AL > 7)
89 M.x86.R_AL = 0x20;
90 else if (M.x86.R_AL == 6)
91 M.x86.R_AL = 0x3f;
92 else
93 M.x86.R_AL = 0x30;
94 break;
95 case 0x01:
96 // set cursor shape
97 // ignore
98 break;
99 case 0x02:
100 // set cursor position
101 // BH: pagenumber, DX: cursor_pos (DH:row, DL:col)
102 // BDA offset 50h-60h are 8 cursor position words for
103 // eight possible video pages
104 my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX);
105 break;
106 case 0x03:
107 //get cursor position
108 // BH: pagenumber
109 // BDA offset 50h-60h are 8 cursor position words for
110 // eight possible video pages
111 M.x86.R_AX = 0;
112 M.x86.R_CH = 0; // start scan line ???
113 M.x86.R_CL = 0; // end scan line ???
114 M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2));
115 break;
116 case 0x05:
117 // set active page
118 // BDA offset 62h is current page number
119 my_wrb(0x462, M.x86.R_AL);
120 break;
121 case 0x06:
122 //scroll up windows
123 break;
124 case 0x07:
125 //scroll down windows
126 break;
127 case 0x08:
128 //read character and attribute at position
129 M.x86.R_AH = 0x07; // white-on-black
130 M.x86.R_AL = 0x20; // a space...
131 break;
132 case 0x09:
133 // write character and attribute
134 //AL: char, BH: page number, BL: attribute, CX: number of times to write
135 //BDA offset 62h is current page number
136 CHECK_DBG(DEBUG_PRINT_INT10) {
137 u32 i = 0;
138 if (M.x86.R_BH == my_rdb(0x462)) {
139 for (i = 0; i < M.x86.R_CX; i++)
140 printf("%c", M.x86.R_AL);
141 }
142 }
143 break;
144 case 0x0a:
145 // write character
146 //AL: char, BH: page number, BL: attribute, CX: number of times to write
147 //BDA offset 62h is current page number
148 CHECK_DBG(DEBUG_PRINT_INT10) {
149 u32 i = 0;
150 if (M.x86.R_BH == my_rdb(0x462)) {
151 for (i = 0; i < M.x86.R_CX; i++)
152 printf("%c", M.x86.R_AL);
153 }
154 }
155 break;
156 case 0x0e:
157 // teletype output: write character and advance cursor...
158 //AL: char, BH: page number, BL: attribute
159 //BDA offset 62h is current page number
160 CHECK_DBG(DEBUG_PRINT_INT10) {
161 // we ignore the pagenumber on this call...
162 //if (M.x86.R_BH == my_rdb(0x462))
163 {
164 printf("%c", M.x86.R_AL);
165 // for debugging, to read all lines
166 //if (M.x86.R_AL == 0xd) // carriage return
167 // printf("\n");
168 }
169 }
170 break;
171 case 0x0f:
172 // get video mode
173 // BDA offset 49h is current video mode
174 // BDA offset 62h is current page number
175 // BDA offset 4ah is columns on screen
176 M.x86.R_AH = 80; //number of character columns... we hardcode it to 80
177 M.x86.R_AL = my_rdb(0x449);
178 M.x86.R_BH = my_rdb(0x462);
179 break;
180 default:
181 printf("%s(): unknown function (%x) for int10 handler.\n",
182 __func__, M.x86.R_AH);
183 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
184 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
185 M.x86.R_DX);
186 HALT_SYS();
187 break;
188 }
189}
190
191// this table translates ASCII chars into their XT scan codes:
192static u8 keycode_table[256] = {
193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 - 7
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8 - 15
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 23
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 - 31
197 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, // 32 - 39
198 0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35, // 40 - 47
199 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 48 - 55
200 0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35, // 56 - 63
201 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64 - 71
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72 - 79
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 87
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 95
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 103
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 104 - 111
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112 - 119
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 - 127
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225}
226
227;
228
Myles Watsonb0259112010-03-05 18:27:19 +0000229static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000230translate_keycode(u64 * keycode)
231{
232 u8 scan_code = 0;
233 u8 char_code = 0;
234 if (*keycode < 256) {
235 scan_code = keycode_table[*keycode];
236 char_code = (u8) * keycode & 0xff;
237 } else {
238 switch (*keycode) {
239 case 0x1b50:
240 // F1
241 scan_code = 0x3b;
242 char_code = 0x0;
243 break;
244 default:
245 printf("%s(): unknown multibyte keycode: %llx\n",
246 __func__, *keycode);
247 break;
248 }
249 }
250 //assemble scan/char code in keycode
251 *keycode = (u64) ((((u16) scan_code) << 8) | char_code);
252}
253
254// handle int16 (Keyboard BIOS Interrupt)
Myles Watsonb0259112010-03-05 18:27:19 +0000255static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000256handleInt16(void)
257{
258 // keyboard buffer is in BIOS Memory Area:
259 // offset 0x1a (WORD) pointer to next char in keybuffer
260 // offset 0x1c (WORD) pointer to next insert slot in keybuffer
261 // offset 0x1e-0x3e: 16 WORD Ring Buffer
262 // since we currently always read the char from the FW buffer,
263 // we misuse the ring buffer, we use it as pointer to a u64 that stores
264 // multi-byte keys (e.g. special keys in VT100 terminal)
Martin Roth63373ed2013-07-08 16:24:19 -0600265 // and as long as a key is available (not 0) we don't read further keys
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000266 u64 *keycode = (u64 *) (M.mem_base + 0x41e);
267 s8 c;
268 // function number in AH
269 DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n",
270 __func__, M.x86.R_AH);
271 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX,
272 M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
273 switch (M.x86.R_AH) {
274 case 0x00:
275 // get keystroke
276 if (*keycode) {
277 M.x86.R_AX = (u16) * keycode;
278 // clear keycode
279 *keycode = 0;
280 } else {
281 M.x86.R_AH = 0x61; // scancode for space key
282 M.x86.R_AL = 0x20; // a space
283 }
284 break;
285 case 0x01:
286 // check keystroke
287 // ZF set = no keystroke
288 // read first byte of key code
289 if (*keycode) {
290 // already read, but not yet taken
291 CLEAR_FLAG(F_ZF);
292 M.x86.R_AX = (u16) * keycode;
293 } else {
294 /* TODO: we need getchar... */
295 c = -1; //getchar();
296 if (c == -1) {
297 // no key available
298 SET_FLAG(F_ZF);
299 } else {
300 *keycode = c;
301
302 // since after an ESC it may take a while to receive the next char,
303 // we send something that is not shown on the screen, and then try to get
304 // the next char
305 // TODO: only after ESC?? what about other multibyte keys
306 printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace
307
308 /* TODO: we need getchar... */
309 while ((c = -1 /*getchar()*/) != -1) {
310 *keycode = (*keycode << 8) | c;
311 DEBUG_PRINTF(" key read: %0llx\n",
312 *keycode);
313 }
314 translate_keycode(keycode);
315 DEBUG_PRINTF(" translated key: %0llx\n",
316 *keycode);
317 if (*keycode == 0) {
318 //not found
319 SET_FLAG(F_ZF);
320 } else {
321 CLEAR_FLAG(F_ZF);
322 M.x86.R_AX = (u16) * keycode;
323 //X86EMU_trace_on();
324 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
325 }
326 }
327 }
328 break;
329 default:
330 printf("%s(): unknown function (%x) for int16 handler.\n",
331 __func__, M.x86.R_AH);
332 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
333 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
334 M.x86.R_DX);
335 HALT_SYS();
336 break;
337 }
338}
339
340// handle int1a (PCI BIOS Interrupt)
Myles Watsonb0259112010-03-05 18:27:19 +0000341static void
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000342handleInt1a(void)
343{
344 // function number in AX
345 u8 bus, devfn, offs;
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300346 struct device *dev = NULL;
347
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000348 switch (M.x86.R_AX) {
349 case 0xb101:
350 // Installation check
351 CLEAR_FLAG(F_CF); // clear CF
352 M.x86.R_EDX = 0x20494350; // " ICP" endian swapped "PCI "
353 M.x86.R_AL = 0x1; // Config Space Mechanism 1 supported
354 M.x86.R_BX = 0x0210; // PCI Interface Level Version 2.10
355 M.x86.R_CL = 0xff; // number of last PCI Bus in system TODO: check!
356 break;
357 case 0xb102:
358 // Find PCI Device
359 // device_id in CX, vendor_id in DX
360 // device index in SI (i.e. if multiple devices with same vendor/device id
361 // are connected). We currently only support device index 0
362 //
363 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n",
364 __func__, M.x86.R_AX);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000365
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300366 /* FixME: support SI != 0 */
367
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000368 // only allow the device to find itself...
369 if ((M.x86.R_CX == bios_device.pci_device_id)
370 && (M.x86.R_DX == bios_device.pci_vendor_id)
371 // device index must be 0
372 && (M.x86.R_SI == 0)) {
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300373 dev = bios_device.dev;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000374 M.x86.R_BH = bios_device.bus;
375 M.x86.R_BL = bios_device.devfn;
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300376 } else if (CONFIG(YABEL_PCI_ACCESS_OTHER_DEVICES)) {
377 dev = dev_find_device(M.x86.R_DX, M.x86.R_CX, 0);
378 if (dev != NULL) {
379 M.x86.R_BH = dev->bus->secondary;
380 M.x86.R_BL = dev->path.pci.devfn;
381 DEBUG_PRINTF_INTR
382 ("%s(): function %x: PCI Find Device --> 0x%04x\n",
383 __func__, M.x86.R_AX, M.x86.R_BX);
384 }
385 }
386 if (dev == NULL) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000387 DEBUG_PRINTF_INTR
Elyes HAOUASa1ac10f2016-08-21 18:21:59 +0200388 ("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/00)\n",
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000389 __func__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX,
390 M.x86.R_SI, bios_device.pci_device_id,
391 bios_device.pci_vendor_id);
392
393 SET_FLAG(F_CF);
394 M.x86.R_AH = 0x86; // return code: device not found
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300395 return;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000396 }
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300397 CLEAR_FLAG(F_CF);
398 M.x86.R_AH = 0x00; // return code: success
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000399 break;
400 case 0xb108: //read configuration byte
401 case 0xb109: //read configuration word
402 case 0xb10a: //read configuration dword
403 bus = M.x86.R_BH;
404 devfn = M.x86.R_BL;
405 offs = M.x86.R_DI;
406 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
407 __func__, M.x86.R_AX, bus, devfn, offs);
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300408
409 if ((bus == bios_device.bus) && (devfn == bios_device.devfn)) {
410 dev = bios_device.dev;
411 } else if (CONFIG(YABEL_PCI_ACCESS_OTHER_DEVICES)) {
Kyösti Mälkki98d19572019-07-04 13:15:01 +0300412 dev = pcidev_path_on_bus(bus, devfn);
413 DEBUG_PRINTF_INTR("%s(): function: %x: pcidev_path_on_bus() returned: %s\n",
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000414 __func__, M.x86.R_AX, dev_path(dev));
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300415 }
416
417 if (dev == NULL) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000418 printf
419 ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
420 __func__, bus, bios_device.bus, devfn,
421 bios_device.devfn, offs);
422 SET_FLAG(F_CF);
423 M.x86.R_AH = 0x87; //return code: bad pci register
424 HALT_SYS();
425 return;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000426 }
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300427
428 switch (M.x86.R_AX) {
429 case 0xb108:
430 M.x86.R_CL =
431#if CONFIG(PCI_OPTION_ROM_RUN_YABEL)
432 pci_read_config8(dev, offs);
433#else
434 (u8) rtas_pci_config_read(bios_device.puid, 1,
435 bus, devfn,
436 offs);
437#endif
438 DEBUG_PRINTF_INTR
439 ("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n",
440 __func__, M.x86.R_AX, offs,
441 M.x86.R_CL);
442 break;
443 case 0xb109:
444 M.x86.R_CX =
445#if CONFIG(PCI_OPTION_ROM_RUN_YABEL)
446 pci_read_config16(dev, offs);
447#else
448 (u16) rtas_pci_config_read(bios_device.puid, 2,
449 bus, devfn,
450 offs);
451#endif
452 DEBUG_PRINTF_INTR
453 ("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n",
454 __func__, M.x86.R_AX, offs,
455 M.x86.R_CX);
456 break;
457 case 0xb10a:
458 M.x86.R_ECX =
459#if CONFIG(PCI_OPTION_ROM_RUN_YABEL)
460 pci_read_config32(dev, offs);
461#else
462 (u32) rtas_pci_config_read(bios_device.puid, 4,
463 bus, devfn,
464 offs);
465#endif
466 DEBUG_PRINTF_INTR
467 ("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n",
468 __func__, M.x86.R_AX, offs,
469 M.x86.R_ECX);
470 break;
471 }
472 CLEAR_FLAG(F_CF);
473 M.x86.R_AH = 0x0; // return code: success
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000474 break;
475 case 0xb10b: //write configuration byte
476 case 0xb10c: //write configuration word
477 case 0xb10d: //write configuration dword
478 bus = M.x86.R_BH;
479 devfn = M.x86.R_BL;
480 offs = M.x86.R_DI;
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300481
482 if ((bus == bios_device.bus) && (devfn == bios_device.devfn)) {
483 dev = bios_device.dev;
484 }
485
486 if (dev == NULL) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000487 printf
488 ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n",
489 __func__, bus, bios_device.bus, devfn,
490 bios_device.devfn, offs);
491 SET_FLAG(F_CF);
492 M.x86.R_AH = 0x87; //return code: bad pci register
493 HALT_SYS();
494 return;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000495 }
Kyösti Mälkkif94aed82019-07-05 13:22:59 +0300496
497 switch (M.x86.R_AX) {
498 case 0xb10b:
499#if CONFIG(PCI_OPTION_ROM_RUN_YABEL)
500 pci_write_config8(dev, offs, M.x86.R_CL);
501#else
502 rtas_pci_config_write(bios_device.puid, 1, bus,
503 devfn, offs, M.x86.R_CL);
504#endif
505 DEBUG_PRINTF_INTR
506 ("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n",
507 __func__, M.x86.R_AX, offs,
508 M.x86.R_CL);
509 break;
510 case 0xb10c:
511#if CONFIG(PCI_OPTION_ROM_RUN_YABEL)
512 pci_write_config16(dev, offs, M.x86.R_CX);
513#else
514 rtas_pci_config_write(bios_device.puid, 2, bus,
515 devfn, offs, M.x86.R_CX);
516#endif
517 DEBUG_PRINTF_INTR
518 ("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n",
519 __func__, M.x86.R_AX, offs,
520 M.x86.R_CX);
521 break;
522 case 0xb10d:
523#if CONFIG(PCI_OPTION_ROM_RUN_YABEL)
524 pci_write_config32(dev, offs, M.x86.R_ECX);
525#else
526 rtas_pci_config_write(bios_device.puid, 4, bus,
527 devfn, offs, M.x86.R_ECX);
528#endif
529 DEBUG_PRINTF_INTR
530 ("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n",
531 __func__, M.x86.R_AX, offs,
532 M.x86.R_ECX);
533 break;
534 }
535 CLEAR_FLAG(F_CF);
536 M.x86.R_AH = 0x0; // return code: success
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000537 break;
538 default:
539 printf("%s(): unknown function (%x) for int1a handler.\n",
540 __func__, M.x86.R_AX);
541 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
542 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
543 M.x86.R_DX);
544 HALT_SYS();
545 break;
546 }
547}
548
549// main Interrupt Handler routine, should be registered as x86emu interrupt handler
550void
551handleInterrupt(int intNum)
552{
553 u8 int_handled = 0;
554#ifndef DEBUG_PRINT_INT10
555 // this printf makes output by int 10 unreadable...
556 // so we only enable it, if int10 print is disabled
557 DEBUG_PRINTF_INTR("%s(%x)\n", __func__, intNum);
558#endif
559
Martin Roth63373ed2013-07-08 16:24:19 -0600560 /* check whether this interrupt has a function pointer set in yabel_intFuncArray and run that */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000561 if (yabel_intFuncArray[intNum]) {
562 DEBUG_PRINTF_INTR("%s(%x) intHandler overridden, calling it...\n", __func__, intNum);
563 int_handled = (*yabel_intFuncArray[intNum])();
564 } else {
565 switch (intNum) {
566 case 0x10: //BIOS video interrupt
567 case 0x42: // INT 10h relocated by EGA/VGA BIOS
568 case 0x6d: // INT 10h relocated by VGA BIOS
569 // get interrupt vector from IDT (4 bytes per Interrupt starting at address 0
570 if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address
571 (my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid
572 {
573#if 0
574 // ignore interrupt...
575 DEBUG_PRINTF_INTR
576 ("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n",
577 __func__, intNum, my_rdl(intNum * 4));
578 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
579 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
580 M.x86.R_DX);
581 //HALT_SYS();
582#endif
583 handleInt10();
584 int_handled = 1;
585 }
586 break;
587 case 0x16:
588 // Keyboard BIOS Interrupt
589 handleInt16();
590 int_handled = 1;
591 break;
592 case 0x1a:
593 // PCI BIOS Interrupt
594 handleInt1a();
595 int_handled = 1;
596 break;
597 case PMM_INT_NUM:
Stefan Reinauer1d888a92011-04-21 20:24:43 +0000598 /* The self-defined PMM INT number, this is called by
599 * the code in PMM struct, and it is handled by
600 * pmm_handleInt()
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000601 */
602 pmm_handleInt();
603 int_handled = 1;
604 break;
605 default:
606 printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
607 my_rdl(intNum * 4));
608 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
609 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
610 M.x86.R_DX);
611 int_handled = 1;
612 HALT_SYS();
613 break;
614 }
615 }
616 // if we did not handle the interrupt, jump to the interrupt vector...
617 if (!int_handled) {
618 setupInt(intNum);
619 }
620}
621
622// prepare and execute Interrupt 10 (VGA Interrupt)
623void
624runInt10(void)
625{
626 // Initialize stack and data segment
627 M.x86.R_SS = STACK_SEGMENT;
628 M.x86.R_DS = DATA_SEGMENT;
629 M.x86.R_SP = STACK_START_OFFSET;
630
631 // push a HLT instruction and a pointer to it onto the stack
632 // any return will pop the pointer and jump to the HLT, thus
633 // exiting (more or less) cleanly
634 push_word(0xf4f4); //F4=HLT
635 //push_word(M.x86.R_SS);
636 //push_word(M.x86.R_SP + 2);
637
638 // setupInt will push the current CS and IP to the stack to return to it,
639 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
640 // to the stack
641 M.x86.R_CS = M.x86.R_SS;
642 M.x86.R_IP = M.x86.R_SP; // + 4;
643
644 CHECK_DBG(DEBUG_TRACE_X86EMU) {
645 X86EMU_trace_on();
646 }
647 CHECK_DBG(DEBUG_JMP) {
648 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
649 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
650 M.x86.debug |= DEBUG_TRACECALL_F;
651 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
652 }
653 setupInt(0x10);
654 DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n",
655 __func__);
656 X86EMU_exec();
657 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
658}
659
660// prepare and execute Interrupt 13 (Disk Interrupt)
661void
662runInt13(void)
663{
664 // Initialize stack and data segment
665 M.x86.R_SS = STACK_SEGMENT;
666 M.x86.R_DS = DATA_SEGMENT;
667 M.x86.R_SP = STACK_START_OFFSET;
668
669 // push a HLT instruction and a pointer to it onto the stack
670 // any return will pop the pointer and jump to the HLT, thus
671 // exiting (more or less) cleanly
672 push_word(0xf4f4); //F4=HLT
673 //push_word(M.x86.R_SS);
674 //push_word(M.x86.R_SP + 2);
675
676 // setupInt will push the current CS and IP to the stack to return to it,
677 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
678 // to the stack
679 M.x86.R_CS = M.x86.R_SS;
680 M.x86.R_IP = M.x86.R_SP;
681
682 CHECK_DBG(DEBUG_TRACE_X86EMU) {
683 X86EMU_trace_on();
684 }
685 CHECK_DBG(DEBUG_JMP) {
686 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
687 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
688 M.x86.debug |= DEBUG_TRACECALL_F;
689 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
690 }
691
692 setupInt(0x13);
693 DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n",
694 __func__);
695 X86EMU_exec();
696 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
697}