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