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 *****************************************************************************/
15 #include "compat/rtas.h"
22 #include "interrupt.h"
24 #include <x86emu/x86emu.h>
25 #include "../x86emu/prim_ops.h"
27 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
28 #include <device/pci.h>
29 #include <device/pci_ops.h>
33 //setup to run the code at the address, that the Interrupt Vector points to...
37 DEBUG_PRINTF_INTR("%s(%x): executing interrupt handler @%08x\n",
38 __func__, intNum, my_rdl(intNum * 4));
39 // push current R_FLG... will be popped by IRET
40 push_word((u16) M.x86.R_FLG);
43 // push current CS:IP to the stack, will be popped by IRET
44 push_word(M.x86.R_CS);
45 push_word(M.x86.R_IP);
46 // set CS:IP to the interrupt handler address... so the next executed instruction will
47 // be the interrupt handler
48 M.x86.R_CS = my_rdw(intNum * 4 + 2);
49 M.x86.R_IP = my_rdw(intNum * 4);
52 // handle int10 (VGA BIOS Interrupt)
56 // the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h
57 // function number in AH
58 //DEBUG_PRINTF_CS_IP("%s:\n", __func__);
59 //x86emu_dump_xregs();
60 //if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){
62 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
67 // BDA offset 49h is current video mode
68 my_wrb(0x449, M.x86.R_AL);
71 else if (M.x86.R_AL == 6)
81 // set cursor position
82 // BH: pagenumber, DX: cursor_pos (DH:row, DL:col)
83 // BDA offset 50h-60h are 8 cursor position words for
84 // eight possible video pages
85 my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX);
90 // BDA offset 50h-60h are 8 cursor position words for
91 // eight possible video pages
93 M.x86.R_CH = 0; // start scan line ???
94 M.x86.R_CL = 0; // end scan line ???
95 M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2));
99 // BDA offset 62h is current page number
100 my_wrb(0x462, M.x86.R_AL);
106 //scroll down windows
109 //read character and attribute at position
110 M.x86.R_AH = 0x07; // white-on-black
111 M.x86.R_AL = 0x20; // a space...
114 // write character and attribute
115 //AL: char, BH: page number, BL: attribute, CX: number of times to write
116 //BDA offset 62h is current page number
117 CHECK_DBG(DEBUG_PRINT_INT10) {
119 if (M.x86.R_BH == my_rdb(0x462)) {
120 for (i = 0; i < M.x86.R_CX; i++)
121 printf("%c", M.x86.R_AL);
127 //AL: char, BH: page number, BL: attribute, CX: number of times to write
128 //BDA offset 62h is current page number
129 CHECK_DBG(DEBUG_PRINT_INT10) {
131 if (M.x86.R_BH == my_rdb(0x462)) {
132 for (i = 0; i < M.x86.R_CX; i++)
133 printf("%c", M.x86.R_AL);
138 // teletype output: write character and advance cursor...
139 //AL: char, BH: page number, BL: attribute
140 //BDA offset 62h is current page number
141 CHECK_DBG(DEBUG_PRINT_INT10) {
142 // we ignore the pagenumber on this call...
143 //if (M.x86.R_BH == my_rdb(0x462))
145 printf("%c", M.x86.R_AL);
146 // for debugging, to read all lines
147 //if (M.x86.R_AL == 0xd) // carriage return
154 // BDA offset 49h is current video mode
155 // BDA offset 62h is current page number
156 // BDA offset 4ah is columns on screen
157 M.x86.R_AH = 80; //number of character columns... we hardcode it to 80
158 M.x86.R_AL = my_rdb(0x449);
159 M.x86.R_BH = my_rdb(0x462);
162 printf("%s(): unknown function (%x) for int10 handler.\n",
163 __func__, M.x86.R_AH);
164 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
165 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
172 // this table translates ASCII chars into their XT scan codes:
173 static u8 keycode_table[256] = {
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 - 7
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8 - 15
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 23
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 - 31
178 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, // 32 - 39
179 0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35, // 40 - 47
180 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 48 - 55
181 0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35, // 56 - 63
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64 - 71
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72 - 79
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 87
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 95
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 103
187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 104 - 111
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112 - 119
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 - 127
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 translate_keycode(u64 * keycode)
215 if (*keycode < 256) {
216 scan_code = keycode_table[*keycode];
217 char_code = (u8) * keycode & 0xff;
226 printf("%s(): unknown multibyte keycode: %llx\n",
231 //assemble scan/char code in keycode
232 *keycode = (u64) ((((u16) scan_code) << 8) | char_code);
235 // handle int16 (Keyboard BIOS Interrupt)
239 // keyboard buffer is in BIOS Memory Area:
240 // offset 0x1a (WORD) pointer to next char in keybuffer
241 // offset 0x1c (WORD) pointer to next insert slot in keybuffer
242 // offset 0x1e-0x3e: 16 WORD Ring Buffer
243 // since we currently always read the char from the FW buffer,
244 // we misuse the ring buffer, we use it as pointer to a u64 that stores
245 // multi-byte keys (e.g. special keys in VT100 terminal)
246 // and as long as a key is available (not 0) we dont read further keys
247 u64 *keycode = (u64 *) (M.mem_base + 0x41e);
249 // function number in AH
250 DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n",
251 __func__, M.x86.R_AH);
252 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX,
253 M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
254 switch (M.x86.R_AH) {
258 M.x86.R_AX = (u16) * keycode;
262 M.x86.R_AH = 0x61; // scancode for space key
263 M.x86.R_AL = 0x20; // a space
268 // ZF set = no keystroke
269 // read first byte of key code
271 // already read, but not yet taken
273 M.x86.R_AX = (u16) * keycode;
275 /* TODO: we need getchar... */
283 // since after an ESC it may take a while to receive the next char,
284 // we send something that is not shown on the screen, and then try to get
286 // TODO: only after ESC?? what about other multibyte keys
287 printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace
289 /* TODO: we need getchar... */
290 while ((c = -1 /*getchar()*/) != -1) {
291 *keycode = (*keycode << 8) | c;
292 DEBUG_PRINTF(" key read: %0llx\n",
295 translate_keycode(keycode);
296 DEBUG_PRINTF(" translated key: %0llx\n",
303 M.x86.R_AX = (u16) * keycode;
305 //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
311 printf("%s(): unknown function (%x) for int16 handler.\n",
312 __func__, M.x86.R_AH);
313 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
314 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
321 // handle int1a (PCI BIOS Interrupt)
325 // function number in AX
328 switch (M.x86.R_AX) {
330 // Installation check
331 CLEAR_FLAG(F_CF); // clear CF
332 M.x86.R_EDX = 0x20494350; // " ICP" endian swapped "PCI "
333 M.x86.R_AL = 0x1; // Config Space Mechanism 1 supported
334 M.x86.R_BX = 0x0210; // PCI Interface Level Version 2.10
335 M.x86.R_CL = 0xff; // number of last PCI Bus in system TODO: check!
339 // device_id in CX, vendor_id in DX
340 // device index in SI (i.e. if multiple devices with same vendor/device id
341 // are connected). We currently only support device index 0
343 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n",
344 __func__, M.x86.R_AX);
345 /* FixME: support SI != 0 */
346 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
347 dev = dev_find_device(M.x86.R_DX, M.x86.R_CX, 0);
350 ("%s(): function %x: PCI Find Device --> 0x%04x\n",
351 __func__, M.x86.R_AX, M.x86.R_BX);
353 M.x86.R_BH = dev->bus->secondary;
354 M.x86.R_BL = dev->path.pci.devfn;
355 M.x86.R_AH = 0x00; // return code: success
358 // only allow the device to find itself...
359 if ((M.x86.R_CX == bios_device.pci_device_id)
360 && (M.x86.R_DX == bios_device.pci_vendor_id)
361 // device index must be 0
362 && (M.x86.R_SI == 0)) {
364 M.x86.R_AH = 0x00; // return code: success
365 M.x86.R_BH = bios_device.bus;
366 M.x86.R_BL = bios_device.devfn;
370 ("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/00) \n",
371 __func__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX,
372 M.x86.R_SI, bios_device.pci_device_id,
373 bios_device.pci_vendor_id);
376 M.x86.R_AH = 0x86; // return code: device not found
379 case 0xb108: //read configuration byte
380 case 0xb109: //read configuration word
381 case 0xb10a: //read configuration dword
385 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
386 __func__, M.x86.R_AX, bus, devfn, offs);
387 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
388 dev = dev_find_slot(bus, devfn);
389 DEBUG_PRINTF_INTR("%s(): function: %x: dev_find_slot() returned: %s\n",
390 __func__, M.x86.R_AX, dev_path(dev));
392 // fail accesses to non-existent devices...
394 dev = bios_device.dev;
395 if ((bus != bios_device.bus)
396 || (devfn != bios_device.devfn)) {
397 // fail accesses to any device but ours...
400 ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
401 __func__, bus, bios_device.bus, devfn,
402 bios_device.devfn, offs);
404 M.x86.R_AH = 0x87; //return code: bad pci register
408 switch (M.x86.R_AX) {
411 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
412 pci_read_config8(dev, offs);
414 (u8) rtas_pci_config_read(bios_device.
420 ("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n",
421 __func__, M.x86.R_AX, offs,
426 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
427 pci_read_config16(dev, offs);
429 (u16) rtas_pci_config_read(bios_device.
435 ("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n",
436 __func__, M.x86.R_AX, offs,
441 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
442 pci_read_config32(dev, offs);
444 (u32) rtas_pci_config_read(bios_device.
450 ("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n",
451 __func__, M.x86.R_AX, offs,
456 M.x86.R_AH = 0x0; // return code: success
459 case 0xb10b: //write configuration byte
460 case 0xb10c: //write configuration word
461 case 0xb10d: //write configuration dword
465 if ((bus != bios_device.bus)
466 || (devfn != bios_device.devfn)) {
467 // fail accesses to any device but ours...
469 ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n",
470 __func__, bus, bios_device.bus, devfn,
471 bios_device.devfn, offs);
473 M.x86.R_AH = 0x87; //return code: bad pci register
477 switch (M.x86.R_AX) {
479 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
480 pci_write_config8(bios_device.dev, offs, M.x86.R_CL);
482 rtas_pci_config_write(bios_device.puid, 1, bus,
483 devfn, offs, M.x86.R_CL);
486 ("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n",
487 __func__, M.x86.R_AX, offs,
491 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
492 pci_write_config16(bios_device.dev, offs, M.x86.R_CX);
494 rtas_pci_config_write(bios_device.puid, 2, bus,
495 devfn, offs, M.x86.R_CX);
498 ("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n",
499 __func__, M.x86.R_AX, offs,
503 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
504 pci_write_config32(bios_device.dev, offs, M.x86.R_ECX);
506 rtas_pci_config_write(bios_device.puid, 4, bus,
507 devfn, offs, M.x86.R_ECX);
510 ("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n",
511 __func__, M.x86.R_AX, offs,
516 M.x86.R_AH = 0x0; // return code: success
520 printf("%s(): unknown function (%x) for int1a handler.\n",
521 __func__, M.x86.R_AX);
522 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
523 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
530 // main Interrupt Handler routine, should be registered as x86emu interrupt handler
532 handleInterrupt(int intNum)
535 #ifndef DEBUG_PRINT_INT10
536 // this printf makes output by int 10 unreadable...
537 // so we only enable it, if int10 print is disabled
538 DEBUG_PRINTF_INTR("%s(%x)\n", __func__, intNum);
541 /* check wether this interrupt has a function pointer set in yabel_intFuncArray and run that */
542 if (yabel_intFuncArray[intNum]) {
543 DEBUG_PRINTF_INTR("%s(%x) intHandler overridden, calling it...\n", __func__, intNum);
544 int_handled = (*yabel_intFuncArray[intNum])();
547 case 0x10: //BIOS video interrupt
548 case 0x42: // INT 10h relocated by EGA/VGA BIOS
549 case 0x6d: // INT 10h relocated by VGA BIOS
550 // get interrupt vector from IDT (4 bytes per Interrupt starting at address 0
551 if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address
552 (my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid
555 // ignore interrupt...
557 ("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n",
558 __func__, intNum, my_rdl(intNum * 4));
559 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
560 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
569 // Keyboard BIOS Interrupt
574 // PCI BIOS Interrupt
579 /* the selfdefined PMM INT number, this is called by the code in PMM struct, it
580 * is handled by pmm_handleInt()
586 printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
588 DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
589 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
596 // if we did not handle the interrupt, jump to the interrupt vector...
602 // prepare and execute Interrupt 10 (VGA Interrupt)
606 // Initialize stack and data segment
607 M.x86.R_SS = STACK_SEGMENT;
608 M.x86.R_DS = DATA_SEGMENT;
609 M.x86.R_SP = STACK_START_OFFSET;
611 // push a HLT instruction and a pointer to it onto the stack
612 // any return will pop the pointer and jump to the HLT, thus
613 // exiting (more or less) cleanly
614 push_word(0xf4f4); //F4=HLT
615 //push_word(M.x86.R_SS);
616 //push_word(M.x86.R_SP + 2);
618 // setupInt will push the current CS and IP to the stack to return to it,
619 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
621 M.x86.R_CS = M.x86.R_SS;
622 M.x86.R_IP = M.x86.R_SP; // + 4;
624 CHECK_DBG(DEBUG_TRACE_X86EMU) {
627 CHECK_DBG(DEBUG_JMP) {
628 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
629 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
630 M.x86.debug |= DEBUG_TRACECALL_F;
631 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
634 DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n",
637 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
640 // prepare and execute Interrupt 13 (Disk Interrupt)
644 // Initialize stack and data segment
645 M.x86.R_SS = STACK_SEGMENT;
646 M.x86.R_DS = DATA_SEGMENT;
647 M.x86.R_SP = STACK_START_OFFSET;
649 // push a HLT instruction and a pointer to it onto the stack
650 // any return will pop the pointer and jump to the HLT, thus
651 // exiting (more or less) cleanly
652 push_word(0xf4f4); //F4=HLT
653 //push_word(M.x86.R_SS);
654 //push_word(M.x86.R_SP + 2);
656 // setupInt will push the current CS and IP to the stack to return to it,
657 // but we want to halt, so set CS:IP to the HLT instruction we just pushed
659 M.x86.R_CS = M.x86.R_SS;
660 M.x86.R_IP = M.x86.R_SP;
662 CHECK_DBG(DEBUG_TRACE_X86EMU) {
665 CHECK_DBG(DEBUG_JMP) {
666 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
667 M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
668 M.x86.debug |= DEBUG_TRACECALL_F;
669 M.x86.debug |= DEBUG_TRACECALL_REGS_F;
673 DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n",
676 DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);