1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
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
11 * IBM Corporation - initial implementation
12 *****************************************************************************/
14 #include "compat/rtas.h"
22 #include <x86emu/x86emu.h>
23 #include "../x86emu/prim_ops.h"
25 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
26 #include <device/pci.h>
27 #include <device/pci_ops.h>
31 //setup to run the code at the address, that the Interrupt Vector points to...
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);
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);
50 // handle int10 (VGA BIOS Interrupt)
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)){
60 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
65 // BDA offset 49h is current video mode
66 my_wrb(0x449, M.x86.R_AL);
69 else if (M.x86.R_AL == 6)
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);
88 // BDA offset 50h-60h are 8 cursor position words for
89 // eight possible video pages
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));
97 // BDA offset 62h is current page number
98 my_wrb(0x462, M.x86.R_AL);
104 //scroll down windows
107 //read character and attribute at position
108 M.x86.R_AH = 0x07; // white-on-black
109 M.x86.R_AL = 0x20; // a space...
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) {
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);
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) {
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);
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))
143 printf("%c", M.x86.R_AL);
144 // for debugging, to read all lines
145 //if (M.x86.R_AL == 0xd) // carriage return
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);
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,
170 // this table translates ASCII chars into their XT scan codes:
171 static 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,
209 translate_keycode(u64 * keycode)
213 if (*keycode < 256) {
214 scan_code = keycode_table[*keycode];
215 char_code = (u8) * keycode & 0xff;
224 printf("%s(): unknown multibyte keycode: %llx\n",
229 //assemble scan/char code in keycode
230 *keycode = (u64) ((((u16) scan_code) << 8) | char_code);
233 // handle int16 (Keyboard BIOS Interrupt)
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)
244 // and as long as a key is available (not 0) we dont read further keys
245 u64 *keycode = (u64 *) (M.mem_base + 0x41e);
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) {
256 M.x86.R_AX = (u16) * keycode;
260 M.x86.R_AH = 0x61; // scancode for space key
261 M.x86.R_AL = 0x20; // a space
266 // ZF set = no keystroke
267 // read first byte of key code
269 // already read, but not yet taken
271 M.x86.R_AX = (u16) * keycode;
273 /* TODO: we need getchar... */
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
284 // TODO: only after ESC?? what about other multibyte keys
285 printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace
287 /* TODO: we need getchar... */
288 while ((c = -1 /*getchar()*/) != -1) {
289 *keycode = (*keycode << 8) | c;
290 DEBUG_PRINTF(" key read: %0llx\n",
293 translate_keycode(keycode);
294 DEBUG_PRINTF(" translated key: %0llx\n",
301 M.x86.R_AX = (u16) * keycode;
303 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
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,
319 // handle int1a (PCI BIOS Interrupt)
323 // function number in AX
326 switch (M.x86.R_AX) {
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!
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
341 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n",
342 __func__, M.x86.R_AX);
343 /* FixME: support SI != 0 */
344 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
345 dev = dev_find_device(M.x86.R_DX, M.x86.R_CX, 0);
348 ("%s(): function %x: PCI Find Device --> 0x%04x\n",
349 __func__, M.x86.R_AX, M.x86.R_BX);
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
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)) {
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;
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);
374 M.x86.R_AH = 0x86; // return code: device not found
377 case 0xb108: //read configuration byte
378 case 0xb109: //read configuration word
379 case 0xb10a: //read configuration dword
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);
385 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
386 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));
390 // fail accesses to non-existent devices...
392 dev = bios_device.dev;
393 if ((bus != bios_device.bus)
394 || (devfn != bios_device.devfn)) {
395 // fail accesses to any device but ours...
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);
402 M.x86.R_AH = 0x87; //return code: bad pci register
406 switch (M.x86.R_AX) {
409 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
410 pci_read_config8(dev, offs);
412 (u8) rtas_pci_config_read(bios_device.
418 ("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n",
419 __func__, M.x86.R_AX, offs,
424 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
425 pci_read_config16(dev, offs);
427 (u16) rtas_pci_config_read(bios_device.
433 ("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n",
434 __func__, M.x86.R_AX, offs,
439 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
440 pci_read_config32(dev, offs);
442 (u32) rtas_pci_config_read(bios_device.
448 ("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n",
449 __func__, M.x86.R_AX, offs,
454 M.x86.R_AH = 0x0; // return code: success
457 case 0xb10b: //write configuration byte
458 case 0xb10c: //write configuration word
459 case 0xb10d: //write configuration dword
463 if ((bus != bios_device.bus)
464 || (devfn != bios_device.devfn)) {
465 // fail accesses to any device but ours...
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);
471 M.x86.R_AH = 0x87; //return code: bad pci register
475 switch (M.x86.R_AX) {
477 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
478 pci_write_config8(bios_device.dev, offs, M.x86.R_CL);
480 rtas_pci_config_write(bios_device.puid, 1, bus,
481 devfn, offs, M.x86.R_CL);
484 ("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n",
485 __func__, M.x86.R_AX, offs,
489 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
490 pci_write_config16(bios_device.dev, offs, M.x86.R_CX);
492 rtas_pci_config_write(bios_device.puid, 2, bus,
493 devfn, offs, M.x86.R_CX);
496 ("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n",
497 __func__, M.x86.R_AX, offs,
501 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
502 pci_write_config32(bios_device.dev, offs, M.x86.R_ECX);
504 rtas_pci_config_write(bios_device.puid, 4, bus,
505 devfn, offs, M.x86.R_ECX);
508 ("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n",
509 __func__, M.x86.R_AX, offs,
514 M.x86.R_AH = 0x0; // return code: success
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,
528 // main Interrupt Handler routine, should be registered as x86emu interrupt handler
530 handleInterrupt(int intNum)
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);
539 /* check wether this interrupt has a function pointer set in yabel_intFuncArray and run that */
540 if (yabel_intFuncArray[intNum]) {
541 DEBUG_PRINTF_INTR("%s(%x) intHandler overridden, calling it...\n", __func__, intNum);
542 int_handled = (*yabel_intFuncArray[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
553 // ignore interrupt...
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,
567 // Keyboard BIOS Interrupt
572 // PCI BIOS Interrupt
577 /* the selfdefined PMM INT number, this is called by the code in PMM struct, it
578 * is handled by pmm_handleInt()
584 printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
586 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
587 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
594 // if we did not handle the interrupt, jump to the interrupt vector...
600 // prepare and execute Interrupt 10 (VGA Interrupt)
604 // Initialize stack and data segment
605 M.x86.R_SS = STACK_SEGMENT;
606 M.x86.R_DS = DATA_SEGMENT;
607 M.x86.R_SP = STACK_START_OFFSET;
609 // push a HLT instruction and a pointer to it onto the stack
610 // any return will pop the pointer and jump to the HLT, thus
611 // exiting (more or less) cleanly
612 push_word(0xf4f4); //F4=HLT
613 //push_word(M.x86.R_SS);
614 //push_word(M.x86.R_SP + 2);
616 // setupInt will push the current CS and IP to the stack to return to it,
617 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
619 M.x86.R_CS = M.x86.R_SS;
620 M.x86.R_IP = M.x86.R_SP; // + 4;
622 CHECK_DBG(DEBUG_TRACE_X86EMU) {
625 CHECK_DBG(DEBUG_JMP) {
626 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
627 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
628 M.x86.debug |= DEBUG_TRACECALL_F;
629 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
632 DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n",
635 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
638 // prepare and execute Interrupt 13 (Disk Interrupt)
642 // Initialize stack and data segment
643 M.x86.R_SS = STACK_SEGMENT;
644 M.x86.R_DS = DATA_SEGMENT;
645 M.x86.R_SP = STACK_START_OFFSET;
647 // push a HLT instruction and a pointer to it onto the stack
648 // any return will pop the pointer and jump to the HLT, thus
649 // exiting (more or less) cleanly
650 push_word(0xf4f4); //F4=HLT
651 //push_word(M.x86.R_SS);
652 //push_word(M.x86.R_SP + 2);
654 // setupInt will push the current CS and IP to the stack to return to it,
655 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
657 M.x86.R_CS = M.x86.R_SS;
658 M.x86.R_IP = M.x86.R_SP;
660 CHECK_DBG(DEBUG_TRACE_X86EMU) {
663 CHECK_DBG(DEBUG_JMP) {
664 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
665 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
666 M.x86.debug |= DEBUG_TRACECALL_F;
667 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
671 DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n",
674 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);