676 lines
20 KiB
C
676 lines
20 KiB
C
/******************************************************************************
|
|
* Copyright (c) 2004, 2008 IBM Corporation
|
|
* Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
|
|
* All rights reserved.
|
|
* This program and the accompanying materials
|
|
* are made available under the terms of the BSD License
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.opensource.org/licenses/bsd-license.php
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial implementation
|
|
*****************************************************************************/
|
|
|
|
#include "compat/rtas.h"
|
|
|
|
#include "biosemu.h"
|
|
#include "mem.h"
|
|
#include "device.h"
|
|
#include "debug.h"
|
|
#include "pmm.h"
|
|
|
|
#include <x86emu/x86emu.h>
|
|
#include "../x86emu/prim_ops.h"
|
|
|
|
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
|
#include <device/pci.h>
|
|
#include <device/pci_ops.h>
|
|
#endif
|
|
|
|
|
|
//setup to run the code at the address, that the Interrupt Vector points to...
|
|
void
|
|
setupInt(int intNum)
|
|
{
|
|
DEBUG_PRINTF_INTR("%s(%x): executing interrupt handler @%08x\n",
|
|
__func__, intNum, my_rdl(intNum * 4));
|
|
// push current R_FLG... will be popped by IRET
|
|
push_word((u16) M.x86.R_FLG);
|
|
CLEAR_FLAG(F_IF);
|
|
CLEAR_FLAG(F_TF);
|
|
// push current CS:IP to the stack, will be popped by IRET
|
|
push_word(M.x86.R_CS);
|
|
push_word(M.x86.R_IP);
|
|
// set CS:IP to the interrupt handler address... so the next executed instruction will
|
|
// be the interrupt handler
|
|
M.x86.R_CS = my_rdw(intNum * 4 + 2);
|
|
M.x86.R_IP = my_rdw(intNum * 4);
|
|
}
|
|
|
|
// handle int10 (VGA BIOS Interrupt)
|
|
void
|
|
handleInt10(void)
|
|
{
|
|
// the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h
|
|
// function number in AH
|
|
//DEBUG_PRINTF_CS_IP("%s:\n", __func__);
|
|
//x86emu_dump_xregs();
|
|
//if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){
|
|
//X86EMU_trace_on();
|
|
//M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
|
|
//}
|
|
switch (M.x86.R_AH) {
|
|
case 0x00:
|
|
// set video mode
|
|
// BDA offset 49h is current video mode
|
|
my_wrb(0x449, M.x86.R_AL);
|
|
if (M.x86.R_AL > 7)
|
|
M.x86.R_AL = 0x20;
|
|
else if (M.x86.R_AL == 6)
|
|
M.x86.R_AL = 0x3f;
|
|
else
|
|
M.x86.R_AL = 0x30;
|
|
break;
|
|
case 0x01:
|
|
// set cursor shape
|
|
// ignore
|
|
break;
|
|
case 0x02:
|
|
// set cursor position
|
|
// BH: pagenumber, DX: cursor_pos (DH:row, DL:col)
|
|
// BDA offset 50h-60h are 8 cursor position words for
|
|
// eight possible video pages
|
|
my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX);
|
|
break;
|
|
case 0x03:
|
|
//get cursor position
|
|
// BH: pagenumber
|
|
// BDA offset 50h-60h are 8 cursor position words for
|
|
// eight possible video pages
|
|
M.x86.R_AX = 0;
|
|
M.x86.R_CH = 0; // start scan line ???
|
|
M.x86.R_CL = 0; // end scan line ???
|
|
M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2));
|
|
break;
|
|
case 0x05:
|
|
// set active page
|
|
// BDA offset 62h is current page number
|
|
my_wrb(0x462, M.x86.R_AL);
|
|
break;
|
|
case 0x06:
|
|
//scroll up windows
|
|
break;
|
|
case 0x07:
|
|
//scroll down windows
|
|
break;
|
|
case 0x08:
|
|
//read character and attribute at position
|
|
M.x86.R_AH = 0x07; // white-on-black
|
|
M.x86.R_AL = 0x20; // a space...
|
|
break;
|
|
case 0x09:
|
|
// write character and attribute
|
|
//AL: char, BH: page number, BL: attribute, CX: number of times to write
|
|
//BDA offset 62h is current page number
|
|
CHECK_DBG(DEBUG_PRINT_INT10) {
|
|
u32 i = 0;
|
|
if (M.x86.R_BH == my_rdb(0x462)) {
|
|
for (i = 0; i < M.x86.R_CX; i++)
|
|
printf("%c", M.x86.R_AL);
|
|
}
|
|
}
|
|
break;
|
|
case 0x0a:
|
|
// write character
|
|
//AL: char, BH: page number, BL: attribute, CX: number of times to write
|
|
//BDA offset 62h is current page number
|
|
CHECK_DBG(DEBUG_PRINT_INT10) {
|
|
u32 i = 0;
|
|
if (M.x86.R_BH == my_rdb(0x462)) {
|
|
for (i = 0; i < M.x86.R_CX; i++)
|
|
printf("%c", M.x86.R_AL);
|
|
}
|
|
}
|
|
break;
|
|
case 0x0e:
|
|
// teletype output: write character and advance cursor...
|
|
//AL: char, BH: page number, BL: attribute
|
|
//BDA offset 62h is current page number
|
|
CHECK_DBG(DEBUG_PRINT_INT10) {
|
|
// we ignore the pagenumber on this call...
|
|
//if (M.x86.R_BH == my_rdb(0x462))
|
|
{
|
|
printf("%c", M.x86.R_AL);
|
|
// for debugging, to read all lines
|
|
//if (M.x86.R_AL == 0xd) // carriage return
|
|
// printf("\n");
|
|
}
|
|
}
|
|
break;
|
|
case 0x0f:
|
|
// get video mode
|
|
// BDA offset 49h is current video mode
|
|
// BDA offset 62h is current page number
|
|
// BDA offset 4ah is columns on screen
|
|
M.x86.R_AH = 80; //number of character columns... we hardcode it to 80
|
|
M.x86.R_AL = my_rdb(0x449);
|
|
M.x86.R_BH = my_rdb(0x462);
|
|
break;
|
|
default:
|
|
printf("%s(): unknown function (%x) for int10 handler.\n",
|
|
__func__, M.x86.R_AH);
|
|
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
|
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
|
M.x86.R_DX);
|
|
HALT_SYS();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// this table translates ASCII chars into their XT scan codes:
|
|
static u8 keycode_table[256] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 - 7
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8 - 15
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 23
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 - 31
|
|
0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, // 32 - 39
|
|
0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35, // 40 - 47
|
|
0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 48 - 55
|
|
0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35, // 56 - 63
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64 - 71
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72 - 79
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 87
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 95
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 103
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 104 - 111
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112 - 119
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 - 127
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
}
|
|
|
|
;
|
|
|
|
void
|
|
translate_keycode(u64 * keycode)
|
|
{
|
|
u8 scan_code = 0;
|
|
u8 char_code = 0;
|
|
if (*keycode < 256) {
|
|
scan_code = keycode_table[*keycode];
|
|
char_code = (u8) * keycode & 0xff;
|
|
} else {
|
|
switch (*keycode) {
|
|
case 0x1b50:
|
|
// F1
|
|
scan_code = 0x3b;
|
|
char_code = 0x0;
|
|
break;
|
|
default:
|
|
printf("%s(): unknown multibyte keycode: %llx\n",
|
|
__func__, *keycode);
|
|
break;
|
|
}
|
|
}
|
|
//assemble scan/char code in keycode
|
|
*keycode = (u64) ((((u16) scan_code) << 8) | char_code);
|
|
}
|
|
|
|
// handle int16 (Keyboard BIOS Interrupt)
|
|
void
|
|
handleInt16(void)
|
|
{
|
|
// keyboard buffer is in BIOS Memory Area:
|
|
// offset 0x1a (WORD) pointer to next char in keybuffer
|
|
// offset 0x1c (WORD) pointer to next insert slot in keybuffer
|
|
// offset 0x1e-0x3e: 16 WORD Ring Buffer
|
|
// since we currently always read the char from the FW buffer,
|
|
// we misuse the ring buffer, we use it as pointer to a u64 that stores
|
|
// multi-byte keys (e.g. special keys in VT100 terminal)
|
|
// and as long as a key is available (not 0) we dont read further keys
|
|
u64 *keycode = (u64 *) (M.mem_base + 0x41e);
|
|
s8 c;
|
|
// function number in AH
|
|
DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n",
|
|
__func__, M.x86.R_AH);
|
|
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX,
|
|
M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
|
|
switch (M.x86.R_AH) {
|
|
case 0x00:
|
|
// get keystroke
|
|
if (*keycode) {
|
|
M.x86.R_AX = (u16) * keycode;
|
|
// clear keycode
|
|
*keycode = 0;
|
|
} else {
|
|
M.x86.R_AH = 0x61; // scancode for space key
|
|
M.x86.R_AL = 0x20; // a space
|
|
}
|
|
break;
|
|
case 0x01:
|
|
// check keystroke
|
|
// ZF set = no keystroke
|
|
// read first byte of key code
|
|
if (*keycode) {
|
|
// already read, but not yet taken
|
|
CLEAR_FLAG(F_ZF);
|
|
M.x86.R_AX = (u16) * keycode;
|
|
} else {
|
|
/* TODO: we need getchar... */
|
|
c = -1; //getchar();
|
|
if (c == -1) {
|
|
// no key available
|
|
SET_FLAG(F_ZF);
|
|
} else {
|
|
*keycode = c;
|
|
|
|
// since after an ESC it may take a while to receive the next char,
|
|
// we send something that is not shown on the screen, and then try to get
|
|
// the next char
|
|
// TODO: only after ESC?? what about other multibyte keys
|
|
printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace
|
|
|
|
/* TODO: we need getchar... */
|
|
while ((c = -1 /*getchar()*/) != -1) {
|
|
*keycode = (*keycode << 8) | c;
|
|
DEBUG_PRINTF(" key read: %0llx\n",
|
|
*keycode);
|
|
}
|
|
translate_keycode(keycode);
|
|
DEBUG_PRINTF(" translated key: %0llx\n",
|
|
*keycode);
|
|
if (*keycode == 0) {
|
|
//not found
|
|
SET_FLAG(F_ZF);
|
|
} else {
|
|
CLEAR_FLAG(F_ZF);
|
|
M.x86.R_AX = (u16) * keycode;
|
|
//X86EMU_trace_on();
|
|
//M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
printf("%s(): unknown function (%x) for int16 handler.\n",
|
|
__func__, M.x86.R_AH);
|
|
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
|
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
|
M.x86.R_DX);
|
|
HALT_SYS();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// handle int1a (PCI BIOS Interrupt)
|
|
void
|
|
handleInt1a(void)
|
|
{
|
|
// function number in AX
|
|
u8 bus, devfn, offs;
|
|
struct device* dev;
|
|
switch (M.x86.R_AX) {
|
|
case 0xb101:
|
|
// Installation check
|
|
CLEAR_FLAG(F_CF); // clear CF
|
|
M.x86.R_EDX = 0x20494350; // " ICP" endian swapped "PCI "
|
|
M.x86.R_AL = 0x1; // Config Space Mechanism 1 supported
|
|
M.x86.R_BX = 0x0210; // PCI Interface Level Version 2.10
|
|
M.x86.R_CL = 0xff; // number of last PCI Bus in system TODO: check!
|
|
break;
|
|
case 0xb102:
|
|
// Find PCI Device
|
|
// device_id in CX, vendor_id in DX
|
|
// device index in SI (i.e. if multiple devices with same vendor/device id
|
|
// are connected). We currently only support device index 0
|
|
//
|
|
DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n",
|
|
__func__, M.x86.R_AX);
|
|
/* FixME: support SI != 0 */
|
|
#if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
|
|
dev = dev_find_device(M.x86.R_DX, M.x86.R_CX, 0);
|
|
if (dev != 0) {
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: PCI Find Device --> 0x%04x\n",
|
|
__func__, M.x86.R_AX, M.x86.R_BX);
|
|
|
|
M.x86.R_BH = dev->bus->secondary;
|
|
M.x86.R_BL = dev->path.pci.devfn;
|
|
M.x86.R_AH = 0x00; // return code: success
|
|
CLEAR_FLAG(F_CF);
|
|
#else
|
|
// only allow the device to find itself...
|
|
if ((M.x86.R_CX == bios_device.pci_device_id)
|
|
&& (M.x86.R_DX == bios_device.pci_vendor_id)
|
|
// device index must be 0
|
|
&& (M.x86.R_SI == 0)) {
|
|
CLEAR_FLAG(F_CF);
|
|
M.x86.R_AH = 0x00; // return code: success
|
|
M.x86.R_BH = bios_device.bus;
|
|
M.x86.R_BL = bios_device.devfn;
|
|
#endif
|
|
} else {
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/00) \n",
|
|
__func__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX,
|
|
M.x86.R_SI, bios_device.pci_device_id,
|
|
bios_device.pci_vendor_id);
|
|
|
|
SET_FLAG(F_CF);
|
|
M.x86.R_AH = 0x86; // return code: device not found
|
|
}
|
|
break;
|
|
case 0xb108: //read configuration byte
|
|
case 0xb109: //read configuration word
|
|
case 0xb10a: //read configuration dword
|
|
bus = M.x86.R_BH;
|
|
devfn = M.x86.R_BL;
|
|
offs = M.x86.R_DI;
|
|
DEBUG_PRINTF_INTR("%s(): function: %x: PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
|
|
__func__, M.x86.R_AX, bus, devfn, offs);
|
|
#if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
|
|
dev = dev_find_slot(bus, devfn);
|
|
DEBUG_PRINTF_INTR("%s(): function: %x: dev_find_slot() returned: %s\n",
|
|
__func__, M.x86.R_AX, dev_path(dev));
|
|
if (dev == 0) {
|
|
// fail accesses to non-existent devices...
|
|
#else
|
|
dev = bios_device.dev;
|
|
if ((bus != bios_device.bus)
|
|
|| (devfn != bios_device.devfn)) {
|
|
// fail accesses to any device but ours...
|
|
#endif
|
|
printf
|
|
("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
|
|
__func__, bus, bios_device.bus, devfn,
|
|
bios_device.devfn, offs);
|
|
SET_FLAG(F_CF);
|
|
M.x86.R_AH = 0x87; //return code: bad pci register
|
|
HALT_SYS();
|
|
return;
|
|
} else {
|
|
switch (M.x86.R_AX) {
|
|
case 0xb108:
|
|
M.x86.R_CL =
|
|
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
|
pci_read_config8(dev, offs);
|
|
#else
|
|
(u8) rtas_pci_config_read(bios_device.
|
|
puid, 1,
|
|
bus, devfn,
|
|
offs);
|
|
#endif
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n",
|
|
__func__, M.x86.R_AX, offs,
|
|
M.x86.R_CL);
|
|
break;
|
|
case 0xb109:
|
|
M.x86.R_CX =
|
|
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
|
pci_read_config16(dev, offs);
|
|
#else
|
|
(u16) rtas_pci_config_read(bios_device.
|
|
puid, 2,
|
|
bus, devfn,
|
|
offs);
|
|
#endif
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n",
|
|
__func__, M.x86.R_AX, offs,
|
|
M.x86.R_CX);
|
|
break;
|
|
case 0xb10a:
|
|
M.x86.R_ECX =
|
|
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
|
pci_read_config32(dev, offs);
|
|
#else
|
|
(u32) rtas_pci_config_read(bios_device.
|
|
puid, 4,
|
|
bus, devfn,
|
|
offs);
|
|
#endif
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n",
|
|
__func__, M.x86.R_AX, offs,
|
|
M.x86.R_ECX);
|
|
break;
|
|
}
|
|
CLEAR_FLAG(F_CF);
|
|
M.x86.R_AH = 0x0; // return code: success
|
|
}
|
|
break;
|
|
case 0xb10b: //write configuration byte
|
|
case 0xb10c: //write configuration word
|
|
case 0xb10d: //write configuration dword
|
|
bus = M.x86.R_BH;
|
|
devfn = M.x86.R_BL;
|
|
offs = M.x86.R_DI;
|
|
if ((bus != bios_device.bus)
|
|
|| (devfn != bios_device.devfn)) {
|
|
// fail accesses to any device but ours...
|
|
printf
|
|
("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n",
|
|
__func__, bus, bios_device.bus, devfn,
|
|
bios_device.devfn, offs);
|
|
SET_FLAG(F_CF);
|
|
M.x86.R_AH = 0x87; //return code: bad pci register
|
|
HALT_SYS();
|
|
return;
|
|
} else {
|
|
switch (M.x86.R_AX) {
|
|
case 0xb10b:
|
|
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
|
pci_write_config8(bios_device.dev, offs, M.x86.R_CL);
|
|
#else
|
|
rtas_pci_config_write(bios_device.puid, 1, bus,
|
|
devfn, offs, M.x86.R_CL);
|
|
#endif
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n",
|
|
__func__, M.x86.R_AX, offs,
|
|
M.x86.R_CL);
|
|
break;
|
|
case 0xb10c:
|
|
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
|
pci_write_config16(bios_device.dev, offs, M.x86.R_CX);
|
|
#else
|
|
rtas_pci_config_write(bios_device.puid, 2, bus,
|
|
devfn, offs, M.x86.R_CX);
|
|
#endif
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n",
|
|
__func__, M.x86.R_AX, offs,
|
|
M.x86.R_CX);
|
|
break;
|
|
case 0xb10d:
|
|
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
|
pci_write_config32(bios_device.dev, offs, M.x86.R_ECX);
|
|
#else
|
|
rtas_pci_config_write(bios_device.puid, 4, bus,
|
|
devfn, offs, M.x86.R_ECX);
|
|
#endif
|
|
DEBUG_PRINTF_INTR
|
|
("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n",
|
|
__func__, M.x86.R_AX, offs,
|
|
M.x86.R_ECX);
|
|
break;
|
|
}
|
|
CLEAR_FLAG(F_CF);
|
|
M.x86.R_AH = 0x0; // return code: success
|
|
}
|
|
break;
|
|
default:
|
|
printf("%s(): unknown function (%x) for int1a handler.\n",
|
|
__func__, M.x86.R_AX);
|
|
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
|
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
|
M.x86.R_DX);
|
|
HALT_SYS();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// main Interrupt Handler routine, should be registered as x86emu interrupt handler
|
|
void
|
|
handleInterrupt(int intNum)
|
|
{
|
|
u8 int_handled = 0;
|
|
#ifndef DEBUG_PRINT_INT10
|
|
// this printf makes output by int 10 unreadable...
|
|
// so we only enable it, if int10 print is disabled
|
|
DEBUG_PRINTF_INTR("%s(%x)\n", __func__, intNum);
|
|
#endif
|
|
|
|
/* check wether this interrupt has a function pointer set in yabel_intFuncArray and run that */
|
|
if (yabel_intFuncArray[intNum]) {
|
|
DEBUG_PRINTF_INTR("%s(%x) intHandler overridden, calling it...\n", __func__, intNum);
|
|
int_handled = (*yabel_intFuncArray[intNum])();
|
|
} else {
|
|
switch (intNum) {
|
|
case 0x10: //BIOS video interrupt
|
|
case 0x42: // INT 10h relocated by EGA/VGA BIOS
|
|
case 0x6d: // INT 10h relocated by VGA BIOS
|
|
// get interrupt vector from IDT (4 bytes per Interrupt starting at address 0
|
|
if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address
|
|
(my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid
|
|
{
|
|
#if 0
|
|
// ignore interrupt...
|
|
DEBUG_PRINTF_INTR
|
|
("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n",
|
|
__func__, intNum, my_rdl(intNum * 4));
|
|
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
|
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
|
M.x86.R_DX);
|
|
//HALT_SYS();
|
|
#endif
|
|
handleInt10();
|
|
int_handled = 1;
|
|
}
|
|
break;
|
|
case 0x16:
|
|
// Keyboard BIOS Interrupt
|
|
handleInt16();
|
|
int_handled = 1;
|
|
break;
|
|
case 0x1a:
|
|
// PCI BIOS Interrupt
|
|
handleInt1a();
|
|
int_handled = 1;
|
|
break;
|
|
case PMM_INT_NUM:
|
|
/* the selfdefined PMM INT number, this is called by the code in PMM struct, it
|
|
* is handled by pmm_handleInt()
|
|
*/
|
|
pmm_handleInt();
|
|
int_handled = 1;
|
|
break;
|
|
default:
|
|
printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
|
|
my_rdl(intNum * 4));
|
|
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
|
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
|
M.x86.R_DX);
|
|
int_handled = 1;
|
|
HALT_SYS();
|
|
break;
|
|
}
|
|
}
|
|
// if we did not handle the interrupt, jump to the interrupt vector...
|
|
if (!int_handled) {
|
|
setupInt(intNum);
|
|
}
|
|
}
|
|
|
|
// prepare and execute Interrupt 10 (VGA Interrupt)
|
|
void
|
|
runInt10(void)
|
|
{
|
|
// Initialize stack and data segment
|
|
M.x86.R_SS = STACK_SEGMENT;
|
|
M.x86.R_DS = DATA_SEGMENT;
|
|
M.x86.R_SP = STACK_START_OFFSET;
|
|
|
|
// push a HLT instruction and a pointer to it onto the stack
|
|
// any return will pop the pointer and jump to the HLT, thus
|
|
// exiting (more or less) cleanly
|
|
push_word(0xf4f4); //F4=HLT
|
|
//push_word(M.x86.R_SS);
|
|
//push_word(M.x86.R_SP + 2);
|
|
|
|
// setupInt will push the current CS and IP to the stack to return to it,
|
|
// but we want to halt, so set CS:IP to the HLT instruction we just pushed
|
|
// to the stack
|
|
M.x86.R_CS = M.x86.R_SS;
|
|
M.x86.R_IP = M.x86.R_SP; // + 4;
|
|
|
|
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
|
X86EMU_trace_on();
|
|
}
|
|
CHECK_DBG(DEBUG_JMP) {
|
|
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
|
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
|
M.x86.debug |= DEBUG_TRACECALL_F;
|
|
M.x86.debug |= DEBUG_TRACECALL_REGS_F;
|
|
}
|
|
setupInt(0x10);
|
|
DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n",
|
|
__func__);
|
|
X86EMU_exec();
|
|
DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
|
|
}
|
|
|
|
// prepare and execute Interrupt 13 (Disk Interrupt)
|
|
void
|
|
runInt13(void)
|
|
{
|
|
// Initialize stack and data segment
|
|
M.x86.R_SS = STACK_SEGMENT;
|
|
M.x86.R_DS = DATA_SEGMENT;
|
|
M.x86.R_SP = STACK_START_OFFSET;
|
|
|
|
// push a HLT instruction and a pointer to it onto the stack
|
|
// any return will pop the pointer and jump to the HLT, thus
|
|
// exiting (more or less) cleanly
|
|
push_word(0xf4f4); //F4=HLT
|
|
//push_word(M.x86.R_SS);
|
|
//push_word(M.x86.R_SP + 2);
|
|
|
|
// setupInt will push the current CS and IP to the stack to return to it,
|
|
// but we want to halt, so set CS:IP to the HLT instruction we just pushed
|
|
// to the stack
|
|
M.x86.R_CS = M.x86.R_SS;
|
|
M.x86.R_IP = M.x86.R_SP;
|
|
|
|
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
|
X86EMU_trace_on();
|
|
}
|
|
CHECK_DBG(DEBUG_JMP) {
|
|
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
|
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
|
M.x86.debug |= DEBUG_TRACECALL_F;
|
|
M.x86.debug |= DEBUG_TRACECALL_REGS_F;
|
|
}
|
|
|
|
setupInt(0x13);
|
|
DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n",
|
|
__func__);
|
|
X86EMU_exec();
|
|
DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
|
|
}
|