rombios.c revision 7d903c47fb1da108843db85eca0ee09f353f2d41
/////////////////////////////////////////////////////////////////////////
// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
//
// MandrakeSoft S.A.
// 43, rue d'Aboukir
// 75002 Paris - France
//
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// ROM BIOS compatability entry points:
// ===================================
// $e05b ; POST Entry Point
// $e2c3 ; NMI Handler Entry Point
// $e3fe ; INT 13h Fixed Disk Services Entry Point
// $e401 ; Fixed Disk Parameter Table
// $e6f2 ; INT 19h Boot Load Service Entry Point
// $e6f5 ; Configuration Data Table
// $e729 ; Baud Rate Generator Table
// $e739 ; INT 14h Serial Communications Service Entry Point
// $e82e ; INT 16h Keyboard Service Entry Point
// $e987 ; INT 09h Keyboard Service Entry Point
// $ec59 ; INT 13h Diskette Service Entry Point
// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
// $efc7 ; Diskette Controller Parameter Table
// $efd2 ; INT 17h Printer Service Entry Point
// $f045 ; INT 10 Functions 0-Fh Entry Point
// $f065 ; INT 10h Video Support Service Entry Point
// $f841 ; INT 12h Memory Size Service Entry Point
// $f84d ; INT 11h Equipment List Service Entry Point
// $f859 ; INT 15h System Services Entry Point
// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
// $fe6e ; INT 1Ah Time-of-day Service Entry Point
// $fea5 ; INT 08h System Timer ISR Entry Point
// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
// $ff53 ; IRET Instruction for Dummy Interrupt Handler
// $ff54 ; INT 05h Print Screen Service Entry Point
// $fff0 ; Power-up Entry Point
// $fffe ; System Model ID
// Features
// - supports up to 4 ATA interfaces
// - 16bits/32bits device access
//
// NOTES for El-Torito Boot (cbbochs@free.fr)
// - Current code is only able to boot mono-session cds
// - Current code can not boot and emulate a hard-disk
// the bios will panic otherwise
// - Current code also use memory in EBDA segement.
// - I used cmos byte 0x3D to store extended information on boot-device
// - Code has to be modified modified to handle multiple cdrom drives
// - Here are the cdrom boot failure codes:
// 1 : no atapi device found
// 2 : no atapi cdrom found
// 3 : can not read cd - BRVD
// 4 : cd is not eltorito (BRVD)
// 5 : cd is not eltorito (ISO TAG)
// 6 : cd is not eltorito (ELTORITO TAG)
// 7 : can not read cd - boot catalog
// 8 : boot catalog : bad header
// 9 : boot catalog : bad platform
// 10 : boot catalog : bad signature
// 11 : boot catalog : bootable flag not set
// 12 : can not read cd - boot image
//
// ATA driver
// - EBDA segment.
// I used memory starting at 0x121 in the segment
#ifndef VBOX
// - the translation policy is defined in cmos regs 0x39 & 0x3a
#endif /* !VBOX */
//
// TODO :
//
// int74
// - needs to be reworked. Uses direct [bp] offsets. (?)
//
// int13:
// - f04 (verify sectors) isn't complete (?)
// - f02/03/04 should set current cyl,etc in BDA (?)
// - rewrite int13_relocated & clean up int13 entry code
//
// NOTES:
// - NMI access (bit7 of addr written to 70h)
//
// ATA driver
// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
//
// El-Torito
// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
// This is ok. But DL should be reincremented afterwards.
// - Fix all "FIXME ElTorito Various"
// - should be able to boot any cdrom instead of the first one
//
// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
#ifdef VBOX
#include "DevPcBios.h"
#endif
#define BX_ROMBIOS32 0
#define DEBUG_ROMBIOS 0
#define DEBUG_ATA 0
#define DEBUG_INT13_HD 0
#define DEBUG_INT13_CD 0
#define DEBUG_INT13_ET 0
#define DEBUG_INT13_FL 0
#define DEBUG_INT15 0
#define DEBUG_INT16 0
#define DEBUG_INT1A 0
#define DEBUG_INT74 0
#define DEBUG_APM 0
#define BX_CPU 3
#define BX_USE_PS2_MOUSE 1
#define BX_CALL_INT15_4F 1
#define BX_USE_EBDA 1
#define BX_SUPPORT_FLOPPY 1
#define BX_PCIBIOS 1
#define BX_APM 1
#define BX_USE_ATADRV 1
#define BX_ELTORITO_BOOT 1
#define BX_MAX_ATA_INTERFACES 4
#define BX_DEBUG_SERIAL 0 /* output to COM1 */
/* model byte 0xFC = AT */
#define SYS_MODEL_ID 0xFC
#define SYS_SUBMODEL_ID 0x00
#define BIOS_REVISION 1
#define BIOS_CONFIG_TABLE 0xe6f5
#ifndef BIOS_BUILD_DATE
# define BIOS_BUILD_DATE "06/23/99"
#endif
// 1K of base memory used for Extended Bios Data Area (EBDA)
// EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
#define EBDA_SEG 0x9FC0
#define ACPI_DATA_SIZE 0x00010000L
// Define the application NAME
#if defined(BX_QEMU)
# define BX_APPNAME "QEMU"
# define BX_APPNAME "Plex86"
#else
# define BX_APPNAME "Bochs"
#endif
// Sanity Checks
#endif
#if BX_USE_ATADRV && !BX_USE_EBDA
#endif
#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
#endif
#endif
#endif
#if defined(VBOX) && !BX_USE_ATADRV
#endif
#ifndef VBOX
#define PANIC_PORT 0x400
#define PANIC_PORT2 0x401
#define INFO_PORT 0x402
#define DEBUG_PORT 0x403
#else /* VBOX */
/* Redirect INFO output to backdoor logging port. */
#define PANIC_PORT 0x400
#define PANIC_PORT2 0x401
#define INFO_PORT 0x504
#define DEBUG_PORT 0x403
#endif /* VBOX */
// define this if you want to make PCIBIOS working on a specific bridge only
// undef enables PCIBIOS when at least one PCI device is found
// i440FX is emulated by Bochs and QEMU
// #20 is dec 20
// #$20 is hex 20 = 32
// #0x20 is hex 20 = 32
// LDA #$20
// JSR $E820
// LDD .i,S
// JSR $C682
// mov al, #$20
// all hex literals should be prefixed with '0x'
// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
// no mov SEG-REG, #value, must mov register into seg-reg
// grep -i "mov[ ]*.s" rombios.c
// This is for compiling with gcc2 and gcc3
#define ASM_START #asm
.rom
.org 0x0000
#if BX_CPU >= 3
use16 386
#else
use16 286
#endif
#if BX_VIRTUAL_PORTS
#else
#endif
db 0xea
dw ?2
dw ?1
typedef unsigned char Bit8u;
typedef unsigned short Bit16u;
typedef unsigned short bx_bool;
typedef unsigned long Bit32u;
#if BX_USE_ATADRV
// memset of count bytes
void
{
}
#if 0
// memcpy of count bytes
void
{
}
// memcpy of count dword
void
{
}
#endif
#endif //BX_USE_ATADRV
// read_dword and write_dword functions
static Bit32u read_dword();
static void write_dword();
{
}
void
{
}
// Bit32u (unsigned long) and long helper functions
lorl:
lsll:
// for access to RAM area which is used by interrupt vectors
// and BIOS Data Area
typedef struct {
unsigned char filler1[0x400];
unsigned char filler2[0x6c];
} bios_data_t;
#define BiosData ((bios_data_t *) 0)
#if BX_USE_ATADRV
typedef struct {
} chs_t;
// DPTE definition
typedef struct {
} dpte_t;
typedef struct {
typedef struct {
// Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
} ata_device_t;
typedef struct {
// ATA channels info
// ATA devices info
//
// map between (bios hd id - 0x80) and ata channels
// map between (bios cd id - 0xE0) and ata channels
// Buffer for DPTE table
// Count of transferred sectors and bytes
} ata_t;
#if BX_ELTORITO_BOOT
// ElTorito Device Emulation data
typedef struct {
// Virtual device
} cdemu_t;
#endif // BX_ELTORITO_BOOT
// for access to EBDA area
// The EBDA structure should conform to
// http://www.frontiernet.net/~fys/rombios.htm document
// I made the ata and cdemu structs begin at 0x121 in the EBDA seg
typedef struct {
unsigned char filler1[0x3D];
// FDPT - Can be splitted in data members if needed
unsigned char fdpt0[0x10];
unsigned char fdpt1[0x10];
unsigned char filler2[0xC4];
// ATA Driver data
#if BX_ELTORITO_BOOT
// El Torito Emulation data
#endif // BX_ELTORITO_BOOT
#ifdef VBOX
unsigned char uForceBootDrive;
unsigned char uForceBootDevice;
#endif /* VBOX */
} ebda_data_t;
#ifdef VBOX
// the last 16 bytes of the EBDA segment are used for the MPS floating
// pointer structure (only if an IOAPIC is present)
#endif
#define EbdaData ((ebda_data_t *) 0)
// for access to the int13ext structure
typedef struct {
} int13ext_t;
#define Int13Ext ((int13ext_t *) 0)
// Disk Physical Table definition
typedef struct {
} dpt_t;
#endif // BX_USE_ATADRV
typedef struct {
union {
struct {
} r16;
struct {
} r8;
} u;
} pusha_regs_t;
typedef struct {
union {
struct {
} r32;
struct {
} r16;
struct {
} r8;
} u;
typedef struct {
union {
struct {
} r16;
struct {
} r8;
} u;
} flags_t;
typedef struct {
} iret_addr_t;
static void outb();
static void outb_cmos();
static void outw();
static void init_rtc();
static bx_bool rtc_updating();
static void write_byte();
static void write_word();
static void bios_printf();
static Bit8u send_to_mouse_ctrl();
static Bit8u get_mouse_data();
static void set_kbd_command_byte();
static void int09_function();
static void int13_harddisk();
static void int13_cdrom();
static void int13_cdemu();
static void int13_eltorito();
static void int13_diskette_function();
static void int14_function();
static void int15_function();
static void int16_function();
static void int17_function();
static Bit32u int19_function();
static void int1a_function();
static void int70_function();
static void int74_function();
static void dummy_isr_function();
static unsigned int enqueue_key();
static unsigned int dequeue_key();
static void get_hd_geometry();
static void set_diskette_ret_status();
static void set_diskette_current_cyl();
static void determine_floppy_media();
static bx_bool floppy_drive_exists();
static bx_bool floppy_drive_recal();
static bx_bool floppy_media_known();
static bx_bool floppy_media_sense();
static bx_bool set_enable_a20();
static void debugger_on();
static void debugger_off();
static void keyboard_init();
static void keyboard_panic();
static void shutdown_status_panic();
static void nmi_handler_msg();
static void print_bios_banner();
static void print_boot_device();
static void print_boot_failure();
static void print_cdromboot_failure();
# if BX_USE_ATADRV
// ATA / ATAPI driver
void ata_init();
void ata_detect();
void ata_reset();
#endif // BX_USE_ATADRV
#if BX_ELTORITO_BOOT
void cdemu_init();
Bit16u cdrom_boot();
#endif // BX_ELTORITO_BOOT
#ifdef VBOX
static char bios_prefix_string[] = "BIOS: ";
/* Do not use build timestamps in this string. Otherwise even rebuilding the
* very same code will lead to compare errors when restoring saved state. */
#define BIOS_COPYRIGHT_STRING "innotek VirtualBox BIOS"
#else /* !VBOX */
static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
#endif /* !VBOX */
#define BIOS_PRINTF_HALT 1
#define BIOS_PRINTF_SCREEN 2
#define BIOS_PRINTF_INFO 4
#define BIOS_PRINTF_DEBUG 8
// Defines the output macros.
// BX_DEBUG goes to INFO port until we can easily choose debug info on a
// per-device basis. Debug info are sent only in debug mode
#if DEBUG_ROMBIOS
#else
#endif
#ifdef VBOX
#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
#else /* !VBOX */
#endif /* !VBOX */
#if DEBUG_ATA
# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_ATA(a...)
#endif
#if DEBUG_INT13_HD
# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT13_HD(a...)
#endif
#if DEBUG_INT13_CD
# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT13_CD(a...)
#endif
#if DEBUG_INT13_ET
# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT13_ET(a...)
#endif
#if DEBUG_INT13_FL
# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT13_FL(a...)
#endif
#if DEBUG_INT15
# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT15(a...)
#endif
#if DEBUG_INT16
# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT16(a...)
#endif
#if DEBUG_INT1A
# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT1A(a...)
#endif
#if DEBUG_INT74
# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
#else
# define BX_DEBUG_INT74(a...)
#endif
#define UNSUPPORTED_FUNCTION 0x86
#define none 0
#define MAX_SCAN_CODE 0x58
static struct {
{ 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
{ 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
{ 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
{ 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
{ 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
{ 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
{ 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
{ 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
{ 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
{ 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
{ 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
{ 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
{ 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
{ 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
{ 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
{ 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
{ 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
{ 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
{ 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
{ 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
{ 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
{ 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
{ 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
{ 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
{ 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
{ 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
#ifndef VBOX
#else
#endif
};
{
}
#if BX_USE_ATADRV
{
}
#endif
void
{
}
#if BX_USE_ATADRV
void
{
}
#endif
void
{
}
{
}
void
init_rtc()
{
inb_cmos(0x0c);
inb_cmos(0x0d);
}
{
// This function checks to see if the update-in-progress bit
// is set in CMOS Status Register A. If not, it returns 0.
// If it is set, it tries to wait until there is a transition
// to 0, and will return 0 if such a transition occurs. A 1
// is returned only after timing out. The maximum period
// that this bit should be set is constrained to 244useconds.
// The count I use below guarantees coverage or more than
// this time, with any reasonable IPS setting.
count = 25000;
while (--count != 0) {
return(0);
}
return(1); // update-in-progress never transitioned to 0
}
{
}
{
}
void
{
}
void
{
}
get_CS()
{
}
get_SS()
{
}
#if BX_DEBUG_SERIAL
/* serial debug port*/
#define BX_DEBUG_PORT 0x03f8
/* data */
#define UART_RBR 0x00
#define UART_THR 0x00
/* control */
#define UART_IER 0x01
#define UART_IIR 0x02
#define UART_FCR 0x02
#define UART_LCR 0x03
#define UART_MCR 0x04
#define UART_DLL 0x00
#define UART_DLM 0x01
/* status */
#define UART_LSR 0x05
#define UART_MSR 0x06
#define UART_SCR 0x07
{
}
{
while (!uart_can_tx_byte(base_port));
}
{
}
{
}
#endif
void
wrch(c)
Bit8u c;
{
int #0x10
}
void
Bit8u c;
{
#if BX_DEBUG_SERIAL
#endif
#if BX_VIRTUAL_PORTS
#endif
if (action & BIOS_PRINTF_SCREEN) {
wrch(c);
}
}
void
{
if (nval)
else {
}
}
void
unsigned short val;
short width;
{
if (nval)
else {
}
}
void
unsigned long val;
short width;
{
if (nval)
else {
}
}
#ifdef VBOX
Bit8u *s;
{
Bit8u c;
if (!s)
s = "<NULL>";
s++;
}
}
#endif /* VBOX */
//--------------------------------------------------------------------------
// bios_printf()
// A compact variable argument printf function which prints its output via
// Currently, only %x is supported (or %02x, %04x, etc).
//
// Supports %[format_width][format]
// where format can be d,x,c,s
//--------------------------------------------------------------------------
void
bios_printf(action, s)
Bit8u *s;
{
Bit8u c, format_char;
short i;
arg_ptr = &s;
in_format = 0;
format_width = 0;
#if BX_VIRTUAL_PORTS
#endif
}
if ( c == '%' ) {
in_format = 1;
format_width = 0;
}
else if (in_format) {
if ( (c>='0') && (c<='9') ) {
}
else {
arg_ptr++; // increment to next arg
if (c == 'x') {
if (format_width == 0)
format_width = 4;
for (i=format_width-1; i>=0; i--) {
}
}
else if (c == 'u') {
}
else if (c == 'l') {
s++;
arg_ptr++; /* increment to next arg */
}
else if (c == 'd') {
if (arg & 0x8000)
else
}
else if (c == 's') {
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
}
else if (c == 'c') {
}
else
BX_PANIC("bios_printf: unknown format\n");
in_format = 0;
}
}
else {
}
s ++;
}
if (action & BIOS_PRINTF_HALT) {
// freeze in a busy loop.
}
}
//--------------------------------------------------------------------------
// keyboard_init
//--------------------------------------------------------------------------
// this file is based on LinuxBIOS implementation of keyboard.c
// could convert to #asm to gain space
void
{
/* ------------------- Flush buffers ------------------------*/
/* Wait until buffer is empty */
max=0xffff;
/* flush incoming keys */
max=0x2000;
while (--max > 0) {
inb(0x60);
max = 0x2000;
}
}
// Due to timer issues, and if the IPS setting is > 15000000,
// the incoming keys might not be flushed here. That will
// cause a panic a few lines below. See sourceforge bug report :
// [ 642031 ] FATAL: Keyboard RESET error:993
/* ------------------- controller side ----------------------*/
/* send cmd = 0xAA, self test 8042 */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* read self-test result, 0x55 should be returned from 0x60 */
keyboard_panic(991);
}
/* send cmd = 0xAB, keyboard interface test */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* read keyboard interface test result, */
/* 0x00 should be returned form 0x60 */
keyboard_panic(992);
}
/* Enable Keyboard clock */
/* ------------------- keyboard side ------------------------*/
/* reset kerboard and self test (keyboard side) */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* keyboard should return ACK */
keyboard_panic(993);
}
/* Wait for data */
max=0xffff;
keyboard_panic(994);
}
/* Disable keyboard */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* keyboard should return ACK */
keyboard_panic(995);
}
/* Write Keyboard Mode */
/* Wait until buffer is empty */
max=0xffff;
/* send cmd: scan code convert, disable mouse, enable IRQ 1 */
/* Wait until buffer is empty */
max=0xffff;
/* Enable keyboard */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* keyboard should return ACK */
keyboard_panic(996);
}
}
//--------------------------------------------------------------------------
// keyboard_panic
//--------------------------------------------------------------------------
void
{
// If you're getting a 993 keyboard panic here,
// please see the comment in keyboard_init
}
//--------------------------------------------------------------------------
// shutdown_status_panic
// called when the shutdown statsu is not implemented, displays the status
//--------------------------------------------------------------------------
void
{
}
#ifdef VBOX
#include "logo.c"
#endif /* VBOX */
//--------------------------------------------------------------------------
// print_bios_banner
// displays a the bios version
//--------------------------------------------------------------------------
void
{
#ifdef VBOX
// Skip the logo if a warm boot is requested.
if (warm_boot == 0x1234)
return;
#ifndef DEBUG
/* show graphical logo */
show_logo();
#else
/* set text mode */
int #0x10
#endif /* !DEBUG */
#else /* !VBOX */
#if BX_APM
"apmbios "
#endif
#if BX_PCIBIOS
"pcibios "
#endif
#if BX_ELTORITO_BOOT
"eltorito "
#endif
#if BX_ROMBIOS32
"rombios32 "
#endif
"\n\n");
#endif /* VBOX */
}
//--------------------------------------------------------------------------
// print_boot_device
// displays the boot device
//--------------------------------------------------------------------------
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
#ifdef VBOX
void
#else /* !VBOX */
void
#endif /* !VBOX */
{
Bit8u i;
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
#ifdef VBOX
#endif /* VBOX */
else return;
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
}
//--------------------------------------------------------------------------
// print_boot_failure
// displays the reason why boot failed
//--------------------------------------------------------------------------
#ifdef VBOX
void
#else /* !VBOX */
void
#endif /* !VBOX */
{
// cdboot: 1 if boot from cd, 0 otherwise
#ifdef VBOX
// lanboot: 1 if boot from lan, 0 otherwise
#endif /* VBOX */
// drive : drive number
// reason: 0 signature check failed, 1 read error
// lastdrive: 1 boot drive is the last one in boot sequence
if (cdboot)
#ifndef VBOX
#else /* VBOX */
else if (lanboot)
#endif /* VBOX */
else if (drive & 0x80)
#ifndef VBOX
bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
#else /* VBOX */
#endif /* VBOX */
else
#ifndef VBOX
bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
#else /* VBOX */
#endif /* VBOX */
if (lastdrive==1) {
if (reason==0)
#ifndef VBOX
BX_PANIC("Not a bootable disk\n");
#else /* VBOX */
BX_PANIC("No bootable medium found! System halted.\n");
#endif /* VBOX */
else
#ifndef VBOX
BX_PANIC("Could not read the boot disk\n");
#else /* VBOX */
BX_PANIC("Could not read from the boot medium! System halted.\n");
#endif /* VBOX */
}
}
//--------------------------------------------------------------------------
// print_cdromboot_failure
// displays the reason why boot failed
//--------------------------------------------------------------------------
void
{
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
return;
}
void
{
BX_PANIC("NMI Handler called\n");
}
void
{
BX_PANIC("INT18: BOOT FAILURE\n");
}
void
{
#if BX_DEBUG_SERIAL
#endif
}
{
// Use PS2 System Control port A to set A20 enable
// get current setting first
// change A20 status
if (val)
else
return((oldval & 0x02) != 0);
}
void
{
}
void
{
}
#if BX_USE_ATADRV
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// Global defines -- ATA register and register bits.
// command block & control block regs
#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
// status reg (CB_STAT and CB_ASTAT) bits
// device control reg (CB_DC) bits
// Most mandtory and optional ATA commands (from ATA-3),
#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
#define ATA_CMD_CHECK_POWER_MODE1 0xE5
#define ATA_CMD_CHECK_POWER_MODE2 0x98
#define ATA_CMD_DEVICE_RESET 0x08
#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
#define ATA_CMD_FLUSH_CACHE 0xE7
#define ATA_CMD_FORMAT_TRACK 0x50
#define ATA_CMD_IDENTIFY_DEVICE 0xEC
#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
#define ATA_CMD_IDLE1 0xE3
#define ATA_CMD_IDLE2 0x97
#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
#define ATA_CMD_IDLE_IMMEDIATE2 0x95
#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
#define ATA_CMD_NOP 0x00
#define ATA_CMD_PACKET 0xA0
#define ATA_CMD_READ_BUFFER 0xE4
#define ATA_CMD_READ_DMA 0xC8
#define ATA_CMD_READ_DMA_QUEUED 0xC7
#define ATA_CMD_READ_MULTIPLE 0xC4
#define ATA_CMD_READ_SECTORS 0x20
#ifdef VBOX
#define ATA_CMD_READ_SECTORS_EXT 0x24
#endif /* VBOX */
#define ATA_CMD_READ_VERIFY_SECTORS 0x40
#define ATA_CMD_RECALIBRATE 0x10
#define ATA_CMD_SEEK 0x70
#define ATA_CMD_SET_FEATURES 0xEF
#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
#define ATA_CMD_SLEEP1 0xE6
#define ATA_CMD_SLEEP2 0x99
#define ATA_CMD_STANDBY1 0xE2
#define ATA_CMD_STANDBY2 0x96
#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
#define ATA_CMD_WRITE_BUFFER 0xE8
#define ATA_CMD_WRITE_DMA 0xCA
#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
#define ATA_CMD_WRITE_MULTIPLE 0xC5
#define ATA_CMD_WRITE_SECTORS 0x30
#ifdef VBOX
#define ATA_CMD_WRITE_SECTORS_EXT 0x34
#endif /* VBOX */
#define ATA_CMD_WRITE_VERIFY 0x3C
#define ATA_IFACE_NONE 0x00
#define ATA_IFACE_ISA 0x00
#define ATA_IFACE_PCI 0x01
#define ATA_TYPE_NONE 0x00
#define ATA_TYPE_UNKNOWN 0x01
#define ATA_TYPE_ATA 0x02
#define ATA_TYPE_ATAPI 0x03
#define ATA_DEVICE_NONE 0x00
#define ATA_DEVICE_HD 0xFF
#define ATA_DEVICE_CDROM 0x05
#define ATA_MODE_NONE 0x00
#define ATA_MODE_PIO16 0x00
#define ATA_MODE_PIO32 0x01
#define ATA_MODE_ISADMA 0x02
#define ATA_MODE_PCIDMA 0x03
#define ATA_MODE_USEIRQ 0x10
#define ATA_TRANSLATION_NONE 0
#define ATA_TRANSLATION_LBA 1
#define ATA_TRANSLATION_LARGE 2
#define ATA_TRANSLATION_RECHS 3
#define ATA_DATA_NO 0x00
#define ATA_DATA_IN 0x01
#define ATA_DATA_OUT 0x02
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void ata_init( )
{
// Channels info init.
}
// Devices info init.
}
// hdidmap and cdidmap init.
}
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void ata_detect( )
{
#if BX_MAX_ATA_INTERFACES > 0
#endif
#if BX_MAX_ATA_INTERFACES > 1
#endif
#if BX_MAX_ATA_INTERFACES > 2
#endif
#if BX_MAX_ATA_INTERFACES > 3
#endif
#if BX_MAX_ATA_INTERFACES > 4
#endif
// Device detection
// Disable interrupts
// Look for device
// If we found something
// reset the channel
// check for ATA or ATAPI
}
}
}
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
// Now we send a IDENTIFY command to ATA device
if(type == ATA_TYPE_ATA) {
#ifdef VBOX
#endif /* VBOX */
//Temporary values to do the transfer
BX_PANIC("ata-detect: Failed to detect ATA device\n");
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
#ifdef VBOX
/** @todo update sectors to be a 64 bit number (also lba...). */
if (sectors == 268435455)
switch (device)
{
case 0:
chsgeo_base = 0x1e;
break;
case 1:
chsgeo_base = 0x26;
break;
case 2:
chsgeo_base = 0x67;
break;
case 3:
chsgeo_base = 0x70;
break;
case 4:
chsgeo_base = 0x40;
break;
case 5:
chsgeo_base = 0x48;
break;
case 6:
chsgeo_base = 0x50;
break;
case 7:
chsgeo_base = 0x58;
break;
default:
chsgeo_base = 0;
}
if (chsgeo_base != 0)
{
}
else
{
lcylinders = 0;
lheads = 0;
lspt = 0;
}
BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
#endif /* VBOX */
#ifdef VBOX
if (device < 2)
{
unsigned char *fdpt;
if (device == 0)
else
/* Update the DPT for drive 0/1 pointed to by Int41/46. This used
* to be done at POST time with lots of ugly assembler code, which
* isn't worth the effort of converting from AMI to Award CMOS
* format. Just do it here. */
sum = 0;
for (i = 0; i < 0xf; i++)
}
#else /* !VBOX */
translation &= 0x03;
switch (translation) {
case ATA_TRANSLATION_NONE:
BX_INFO("none");
break;
case ATA_TRANSLATION_LBA:
BX_INFO("lba");
break;
case ATA_TRANSLATION_LARGE:
BX_INFO("large");
break;
case ATA_TRANSLATION_RECHS:
BX_INFO("r-echs");
break;
}
switch (translation) {
case ATA_TRANSLATION_NONE:
break;
case ATA_TRANSLATION_LBA:
spt = 63;
sectors /= 63;
else heads=16;
break;
case ATA_TRANSLATION_RECHS:
// Take care not to overflow
if (heads==16) {
heads=15;
}
// then go through the large bitshift process
case ATA_TRANSLATION_LARGE:
while(cylinders > 1024) {
cylinders >>= 1;
heads <<= 1;
// If we max out the head count
if (heads > 127) break;
}
break;
}
// clip to 1024 cylinders in lchs
#endif /* VBOX */
// fill hdidmap
hdcount++;
}
// Now we send a IDENTIFY command to ATAPI device
if(type == ATA_TYPE_ATAPI) {
//Temporary values to do the transfer
BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
blksize = 2048;
// fill cdidmap
cdcount++;
}
{
switch (type) {
case ATA_TYPE_ATA:
sizeinmb >>= 11;
case ATA_TYPE_ATAPI:
break;
}
// Read model name
for(i=0;i<20;i++){
}
// Reformat
for(i=39;i>0;i--){
else break;
}
break;
}
#ifdef VBOX
// we don't want any noisy output for now
#else /* !VBOX */
switch (type) {
case ATA_TYPE_ATA:
break;
case ATA_TYPE_ATAPI:
else
break;
case ATA_TYPE_UNKNOWN:
break;
}
#endif /* !VBOX */
}
}
// Store the devices counts
#ifdef VBOX
// we don't want any noisy output for now
#else /* !VBOX */
printf("\n");
#endif /* !VBOX */
// FIXME : should use bios=cmos|auto|disable bits
// FIXME : should know about translation bits
// FIXME : move hard_drive_post here
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ATA-3
// 8.2.1 Software reset - Device 0
{
#ifdef VBOX
#endif /* VBOX */
// Reset
// 8.2.1 (a) -- set SRST in DC
// 8.2.1 (b) -- wait for BSY
max=0xff;
while(--max>0) {
if ((status & ATA_CB_STAT_BSY) != 0) break;
}
// 8.2.1 (f) -- clear SRST
// 8.2.1 (g) -- check for sc==sn==0x01
// select device
// 8.2.1 (h) -- wait for not BSY
#ifdef VBOX
#else /* !VBOX */
max=0xff;
#endif /* !VBOX */
while(--max>0) {
if ((status & ATA_CB_STAT_BSY) == 0) break;
#ifdef VBOX
pdelay=0xffff;
while (--pdelay>0) {
/* nothing */
}
#endif /* VBOX */
}
}
}
// 8.2.1 (i) -- wait for DRDY
#ifdef VBOX
#else /* !VBOX */
max=0xfff;
#endif /* !VBOX */
while(--max>0) {
if ((status & ATA_CB_STAT_RDY) != 0) break;
}
// Enable interrupts
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
{return 0;}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// returns
// 0 : no error
// 1 : BUSY bit set
// 2 : read error
// 3 : expected DRQ=1
// 6 : no sectors left to write
// 7 : more sectors to write
{
else blksize>>=1;
#ifdef VBOX
if (status & ATA_CB_STAT_BSY)
{
// Enable interrupts
return 1;
}
#endif /* VBOX */
// sector will be 0 only on lba access. Convert to lba-chs
if (sector == 0) {
#ifdef VBOX
{
cylinder = 0; /* The parameter lba is just a 32 bit value. */
/* Leave the bottom 24 bits as is, they are treated correctly by the
* LBA28 code path. */
lba &= 0xffffff;
}
#endif /* VBOX */
lba >>= 8;
lba >>= 16;
}
// Reset count of transferred data
current = 0;
#ifndef VBOX
#endif /* !VBOX */
while (1) {
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
if (status & ATA_CB_STAT_ERR) {
BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 2;
} else if ( !(status & ATA_CB_STAT_DRQ) ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 3;
}
while (1) {
current++;
count--;
#ifdef VBOX
while (1) {
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
#else /* !VBOX */
#endif /* !VBOX */
if (count == 0) {
!= ATA_CB_STAT_RDY ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 4;
}
break;
}
else {
!= (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 5;
}
continue;
}
}
// Enable interrupts
return 0;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// returns
// 0 : no error
// 1 : BUSY bit set
// 2 : read error
// 3 : expected DRQ=1
// 6 : no sectors left to write
// 7 : more sectors to write
{
else blksize>>=1;
#ifdef VBOX
if (status & ATA_CB_STAT_BSY)
{
// Enable interrupts
return 1;
}
#endif /* VBOX */
// sector will be 0 only on lba access. Convert to lba-chs
if (sector == 0) {
#ifdef VBOX
{
cylinder = 0; /* The parameter lba is just a 32 bit value. */
/* Leave the bottom 24 bits as is, they are treated correctly by the
* LBA28 code path. */
lba &= 0xffffff;
}
#endif /* VBOX */
lba >>= 8;
lba >>= 16;
}
// Reset count of transferred data
current = 0;
#ifndef VBOX
#endif /* !VBOX */
while (1) {
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
if (status & ATA_CB_STAT_ERR) {
BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 2;
} else if ( !(status & ATA_CB_STAT_DRQ) ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 3;
}
while (1) {
current++;
count--;
#ifdef VBOX
while (1) {
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
#else /* !VBOX */
#endif /* VBOX */
if (count == 0) {
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
!= ATA_CB_STAT_RDY ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 6;
}
break;
}
else {
!= (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 7;
}
continue;
}
}
// Enable interrupts
return 0;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// returns
// 0 : no error
// 1 : error in parameters
// 2 : BUSY bit set
// 3 : error
// 4 : not ready
{
// Data out is not supported yet
if (inout == ATA_DATA_OUT) {
BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
return 1;
}
// The header length must be even
if (header & 1) {
return 1;
}
transfer= 0L;
cmdlen>>=1;
// Reset count of transferred data
// outb(iobase1 + ATA_CB_FR, 0x00);
// outb(iobase1 + ATA_CB_SC, 0x00);
// outb(iobase1 + ATA_CB_SN, 0x00);
// Device should ok to receive command
while (1) {
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
if (status & ATA_CB_STAT_ERR) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 3;
} else if ( !(status & ATA_CB_STAT_DRQ) ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 4;
}
// Normalize address
cmdoff %= 16;
// Send command to device
if (inout == ATA_DATA_NO) {
}
else {
while (1) {
#ifdef VBOX
while (1) {
if ( !(status & ATA_CB_STAT_BSY) ) break;
}
#else /* VBOX */
#endif /* VBOX */
// Check if command completed
if (status & ATA_CB_STAT_ERR) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 3;
}
// Device must be ready to send data
!= (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 4;
}
// Normalize address
bufoff %= 16;
// Get the byte count
// adjust to read what we want
lcount=0;
}
else {
header=0;
}
length=0;
}
else {
lafter=0;
}
// Save byte count
BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
// If counts not dividable by 4, use 16bits mode
// adds an extra byte if count are odd. before is always even
if (lcount & 0x01) {
lcount+=1;
lafter-=1;
}
}
if (lmode == ATA_MODE_PIO32) {
}
else {
}
; // FIXME bcc bug
// Compute new buffer address
// Save transferred bytes count
}
}
// Final check, device must be ready
if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
!= ATA_CB_STAT_RDY ) {
#ifdef VBOX
// Enable interrupts
#endif /* VBOX */
return 4;
}
// Enable interrupts
return 0;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
{
Bit8u i;
// Request SENSE
atacmd[0]=0x03;
return 0x0002;
}
return 0;
}
{
// Test Unit Ready
return 0x000f;
if (atapi_get_sense(device) !=0 ) {
// try to send Test Unit Ready again
return 0x000f;
return atapi_get_sense(device);
}
return 0;
}
{
if (device >= BX_MAX_ATA_DEVICES)
return 0;
return 0;
return 0;
return 1;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
#endif // BX_USE_ATADRV
#if BX_ELTORITO_BOOT
// ---------------------------------------------------------------------------
// Start of El-Torito boot functions
// ---------------------------------------------------------------------------
void
{
// the only important data is this one for now
}
{
}
{
}
//
// Returns ah: emulated drive, al: error code
//
{
// Find out the first cdrom
if (atapi_is_cdrom(device)) break;
}
// if not found
// Read the Boot Record Volume Descriptor
if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
return 3;
// Validity checks
if(buffer[0]!=0)return 4;
for(i=0;i<5;i++){
}
for(i=0;i<23;i++)
// ok, now we calculate the Boot catalog address
// And we read the Boot Catalog
if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
return 7;
// Validation entry
if(buffer[0x21]==0){
// FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
// Win2000 cd boot needs to know it booted from cd
}
else
// And we read the image in memory
if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
return 12;
// Remember the media type
case 0x01: // 1.2M floppy
break;
case 0x02: // 1.44M floppy
break;
case 0x03: // 2.88M floppy
break;
case 0x04: // Harddrive
break;
}
// Increase bios installed hardware number of devices
else
}
// everything is ok, so from now on, the emulation is active
// return the boot drive + no error
}
// ---------------------------------------------------------------------------
// End of El-Torito boot functions
// ---------------------------------------------------------------------------
#endif // BX_ELTORITO_BOOT
void
{
case 0:
} else {
}
break;
case 1:
timeout--;
}
}
break;
case 2:
timeout--;
}
}
if (timeout) {
} else {
}
break;
case 3:
break;
default:
}
} else {
}
}
void
{
#ifdef VBOX
case 0x00: /* assorted functions */
goto undecoded;
/* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
* which we don't support, but logging that event is annoying. In fact
* it is likely that they just misread some specs, because there is a
* int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
* wants to achieve. */
SET_CF();
break;
#endif
case 0x24: /* A20 Control */
case 0x00:
set_enable_a20(0);
CLEAR_CF();
break;
case 0x01:
set_enable_a20(1);
CLEAR_CF();
break;
case 0x02:
CLEAR_CF();
break;
case 0x03:
CLEAR_CF();
break;
default:
BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
SET_CF();
}
break;
case 0x41:
SET_CF();
break;
case 0x4f:
/* keyboard intercept */
#if BX_CPU < 2
#else
// nop
#endif
SET_CF();
break;
case 0x52: // removable media eject
CLEAR_CF();
break;
case 0x83: {
// Set Interval requested.
// Interval not already set.
CLEAR_CF( );
} else {
// Interval already set.
BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
SET_CF();
}
// Clear Interval requested
CLEAR_CF( );
} else {
BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
SET_CF();
}
break;
}
case 0x87:
#if BX_CPU < 3
# error "Int15 function 87h not supported on < 80386"
#endif
// +++ should probably have descriptor checks
// +++ should have exception handlers
// turn off interrupts
// 128K max of transfer on 386+ ???
// source == destination ???
// ES:SI points to descriptor table
// offset use initially comments
// ==============================================
// 00..07 Unused zeros Null descriptor
// 08..0f GDT zeros filled in by BIOS
// 10..17 source ssssssss source of data
// 18..1f dest dddddddd destination of data
// 20..27 CS zeros filled in by BIOS
// 28..2f SS zeros filled in by BIOS
//es:si
//eeee0
//0ssss
//-----
// check for access rights of source & dest here
// Initialize GDT descriptor
base23_16++;
// Initialize CS descriptor
// Initialize SS descriptor
// Compile generates locals offset info relative to SP.
// Get CX (word count) from stack.
// since we need to set SS:SP, save them to the BDA
// for future restore
// restore SS:SP from the BDA
// turn back on interrupts
CLEAR_CF();
break;
case 0x88:
// Get the amount of extended memory (above 1M)
#if BX_CPU < 2
SET_CF();
#else
// According to Ralf Brown's interrupt the limit should be 15M,
// but real machines mostly return max. 63M.
CLEAR_CF();
#endif
break;
#ifdef VBOX
case 0x89:
// Switch to Protected Mode.
// ES:DI points to user-supplied GDT
// This subfunction does not return!
// turn off interrupts
// Initialize CS descriptor for BIOS
// Compiler generates locals offset info relative to SP.
// Get BX (PIC offsets) from stack.
// Program PICs
// Load GDT and IDT from supplied data
// set PE bit in CR0
// far jump to flush CPU queue after transition to protected mode
// unwind the stack - this will break if calling sequence changes!
// return to caller - note that we do not use IRET because
// we cannot enable interrupts
break;
#endif
case 0x90:
/* Device busy interrupt. Called by Int 16h when no key available */
break;
case 0x91:
/* Interrupt complete. Called by Int 16h when key becomes available */
break;
case 0xbf:
BX_INFO("*** int 15h function AH=bf not yet supported!\n");
SET_CF();
break;
case 0xC0:
#if 0
SET_CF();
break;
#endif
CLEAR_CF();
ES = 0xF000;
break;
case 0xc1:
CLEAR_CF();
break;
case 0xd8:
SET_CF();
break;
#ifdef VBOX
/* Make the BIOS warning for pretty much every Linux kernel start
* disappear - it calls with ax=0xe980 to figure out SMI info. */
case 0xe9: /* SMI functions (SpeedStep and similar things) */
SET_CF();
break;
#endif /* VBOX */
default:
BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
SET_CF();
break;
}
}
#if BX_USE_PS2_MOUSE
void
{
case 0xC2:
// Return Codes status in AH
// =========================
// 00: success
// 01: invalid subfunction (AL > 7)
// 02: invalid input value (out of allowable range)
// 03: interface error
// 04: resend command received from mouse controller,
// device driver should attempt command again
// 05: cannot enable mouse, since no far call has been installed
// 80/86: mouse service not implemented
BX_DEBUG_INT15("unsupported subfn\n");
// invalid function
SET_CF();
break;
}
// Valid subfn; disable AUX input and IRQ12, assume no error
set_kbd_command_byte(0x65);
CLEAR_CF();
BX_DEBUG_INT15("case 0: ");
// invalid subfunction
SET_CF();
break;
}
if ( (mouse_flags_2 & 0x80) == 0 ) {
BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
SET_CF();
break;
}
BX_DEBUG_INT15("Disable Mouse\n");
} else {
BX_DEBUG_INT15("Enable Mouse\n");
}
if (ret == 0) {
// success
break;
}
}
// interface error
SET_CF();
break;
case 5: // Initialize Mouse
// Valid package sizes are 1 to 8
SET_CF();
break;
}
// fall through!
case 1: // Reset Mouse
BX_DEBUG_INT15("case 1 or 5:\n");
// clear current package byte index
if (ret == 0) {
// if no mouse attached, it will return RESEND
if (mouse_data3 == 0xfe) {
SET_CF();
break;
}
if (mouse_data3 != 0xfa)
if ( ret == 0 ) {
if ( ret == 0 ) {
if ( ret == 0 ) {
// success
break;
}
}
}
}
// interface error
SET_CF();
break;
case 2: // Set Sample Rate
BX_DEBUG_INT15("case 2:\n");
default: mouse_data1 = 0;
}
if (mouse_data1 > 0) {
if (ret == 0) {
// success
} else {
// interface error
SET_CF();
}
} else {
// invalid input
SET_CF();
}
break;
case 3: // Set Resolution
BX_DEBUG_INT15("case 3:\n");
// BX:
// 0 = 25 dpi, 1 count per millimeter
// 1 = 50 dpi, 2 counts per millimeter
// 2 = 100 dpi, 4 counts per millimeter
// 3 = 200 dpi, 8 counts per millimeter
if (ret == 0) {
if (mouse_data1 != 0xfa)
if (mouse_data1 != 0xfa)
// success
} else {
// interface error
SET_CF();
}
} else {
// invalid input
SET_CF();
}
break;
case 4: // Get Device ID
BX_DEBUG_INT15("case 4:\n");
if (ret == 0) {
// success
} else {
// interface error
SET_CF();
}
break;
case 6: // Return Status & Set Scaling Factor...
BX_DEBUG_INT15("case 6:\n");
case 0: // Return Status
if (ret == 0) {
if (mouse_data1 != 0xfa)
if (ret == 0) {
if ( ret == 0 ) {
if ( ret == 0 ) {
if ( ret == 0 ) {
// success
break;
}
}
}
}
}
// interface error
SET_CF();
break;
case 1: // Set Scaling Factor to 1:1
case 2: // Set Scaling Factor to 2:1
} else {
}
if (ret == 0) {
}
if (ret != 0) {
// interface error
SET_CF();
}
break;
default:
// invalid subfunction
SET_CF();
}
break;
case 7: // Set Mouse Handler Address
BX_DEBUG_INT15("case 7:\n");
if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
/* remove handler */
if ( (mouse_flags_2 & 0x80) != 0 ) {
mouse_flags_2 &= ~0x80;
}
}
else {
/* install handler */
mouse_flags_2 |= 0x80;
}
break;
default:
BX_PANIC("INT 15h C2 default case entered\n");
// invalid subfunction
SET_CF();
}
// Re-enable AUX input and IRQ12
set_kbd_command_byte(0x47);
break;
default:
BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
SET_CF();
break;
}
}
#endif
{
#ifdef VBOX
if (end == 0)
else
#else /* !VBOX */
#endif /* !VBOX */
}
void
{
case 0x86:
// Wait for CX:DX microseconds. currently using the
// refresh request port 0x61 bit4, toggling every 15usec
break;
case 0xe8:
{
case 0x20: // coded by osmaker aka K.J.
{
extended_memory_size <<= 8;
extended_memory_size *= 64;
// greater than EFF00000???
if(extended_memory_size > 0x3bc000) {
extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
}
extended_memory_size *= 1024;
extended_memory_size <<= 8;
extended_memory_size *= 1024;
}
{
case 0:
0x0000000L, 0x0009fc00L, 1);
CLEAR_CF();
return;
break;
case 1:
0x0009fc00L, 0x000a0000L, 2);
CLEAR_CF();
return;
break;
case 2:
#ifdef VBOX
/* Mark the BIOS as reserved. VBox doesn't currently
* use the 0xe0000-0xeffff area. It does use the
* 0xd0000-0xdffff area for the BIOS logo, but it's
* not worth marking it as reserved. Note that various
* Windows versions don't accept (read: in debug builds
* they trigger the "Too many similar traps" assertion)
* a single reserved range from 0xd0000 to 0xffffff.
* A 128K area starting from 0xd0000 works. */
0x000f0000L, 0x00100000L, 2);
#else /* !VBOX */
0x000e8000L, 0x00100000L, 2);
#endif /* !VBOX */
CLEAR_CF();
return;
break;
case 3:
0x00100000L,
CLEAR_CF();
return;
break;
case 4:
CLEAR_CF();
return;
break;
case 5:
/* 256KB BIOS area at the end of 4 GB */
0xfffc0000L, 0x00000000L, 2);
CLEAR_CF();
return;
default: /* AX=E820, DX=534D4150, BX unrecognized */
goto int15_unimplemented;
break;
}
} else {
// if DX != 0x534D4150)
goto int15_unimplemented;
}
break;
case 0x01:
// do we have any reason to fail here ?
CLEAR_CF();
// my real system sets ax and bx to 0
// this is confirmed by Ralph Brown list
// but syslinux v1.48 is known to behave
// strangely if ax is set to 0
// regs.u.r16.ax = 0;
// regs.u.r16.bx = 0;
// Get the amount of extended memory (above 1M)
// limit to 15M
{
}
// Get the amount of extended memory above 16M in 64k blocs
// Set configured memory equal to extended memory
break;
default: /* AH=0xE8?? but not implemented */
goto int15_unimplemented;
}
break;
// fall into the default
default:
BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
SET_CF();
break;
}
}
void
{
led_flags &= 0xf8;
inb(0x60);
}
}
switch (GET_AH()) {
case 0x00: /* read keyboard input */
BX_PANIC("KBD: int16h: out of keyboard input\n");
}
break;
case 0x01: /* check keyboard status */
SET_ZF();
return;
}
CLEAR_ZF();
break;
case 0x02: /* get shift flag status */
break;
case 0x05: /* store key-stroke into buffer */
SET_AL(1);
}
else {
SET_AL(0);
}
break;
case 0x09: /* GET KEYBOARD FUNCTIONALITY */
// bit Bochs Description
// 7 0 reserved
// 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
// 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
// 4 1 INT 16/AH=0Ah supported
// 3 0 INT 16/AX=0306h supported
// 2 0 INT 16/AX=0305h supported
// 1 0 INT 16/AX=0304h supported
// 0 0 INT 16/AX=0300h supported
//
SET_AL(0x30);
break;
case 0x0A: /* GET KEYBOARD ID */
count = 2;
kbd_code = 0x0;
/* Wait for data */
max=0xffff;
if (max>0x0) {
do {
max=0xffff;
if (max>0x0) {
kbd_code >>= 8;
}
} while (--count>0);
}
}
break;
case 0x10: /* read MF-II keyboard input */
BX_PANIC("KBD: int16h: out of keyboard input\n");
}
break;
case 0x11: /* check MF-II keyboard status */
SET_ZF();
return;
}
CLEAR_ZF();
break;
case 0x12: /* get extended keyboard status */
break;
case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
break;
case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
// don't change AH : function int16 ah=0x20-0x22 NOT supported
break;
case 0x6F:
if (GET_AL() == 0x08)
default:
}
}
unsigned int
unsigned int incr;
{
#if BX_CPU < 2
buffer_start = 0x001E;
buffer_end = 0x003E;
#else
#endif
if (buffer_head != buffer_tail) {
if (incr) {
buffer_head += 2;
if (buffer_head >= buffer_end)
}
return(1);
}
else {
return(0);
}
}
static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
{
// wait for chance to write to ctrl
return(0);
}
{
}
return(0);
}
void
{
}
void
{
//
// DS has been set to F000 before call
//
if (scancode == 0) {
BX_INFO("KBD: int09 handler: AL=0\n");
return;
}
asciicode = 0;
switch (scancode) {
case 0x3a: /* Caps Lock press */
shift_flags ^= 0x40;
mf2_flags |= 0x40;
break;
case 0xba: /* Caps Lock release */
mf2_flags &= ~0x40;
break;
case 0x2a: /* L Shift press */
shift_flags |= 0x02;
break;
case 0xaa: /* L Shift release */
shift_flags &= ~0x02;
break;
case 0x36: /* R Shift press */
shift_flags |= 0x01;
break;
case 0xb6: /* R Shift release */
shift_flags &= ~0x01;
break;
case 0x1d: /* Ctrl press */
if ((mf2_state & 0x01) == 0) {
shift_flags |= 0x04;
if (mf2_state & 0x02) {
mf2_state |= 0x04;
} else {
mf2_flags |= 0x01;
}
}
break;
case 0x9d: /* Ctrl release */
if ((mf2_state & 0x01) == 0) {
shift_flags &= ~0x04;
if (mf2_state & 0x02) {
mf2_state &= ~0x04;
} else {
mf2_flags &= ~0x01;
}
}
break;
case 0x38: /* Alt press */
shift_flags |= 0x08;
if (mf2_state & 0x02) {
mf2_state |= 0x08;
} else {
mf2_flags |= 0x02;
}
break;
case 0xb8: /* Alt release */
shift_flags &= ~0x08;
if (mf2_state & 0x02) {
mf2_state &= ~0x08;
} else {
mf2_flags &= ~0x02;
}
break;
case 0x45: /* Num Lock press */
if ((mf2_state & 0x03) == 0) {
mf2_flags |= 0x20;
shift_flags ^= 0x20;
}
break;
case 0xc5: /* Num Lock release */
if ((mf2_state & 0x03) == 0) {
mf2_flags &= ~0x20;
}
break;
case 0x46: /* Scroll Lock press */
mf2_flags |= 0x10;
shift_flags ^= 0x10;
break;
case 0xc6: /* Scroll Lock release */
mf2_flags &= ~0x10;
break;
default:
if (scancode & 0x80) {
break; /* toss key releases ... */
}
if (scancode > MAX_SCAN_CODE) {
return;
}
/* extended keys handling */
asciicode = 0xe0;
/* check if lock state should be ignored
* because a SHIFT key are pressed */
} else {
}
} else {
/* check if lock is on */
} else {
}
}
BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
}
break;
}
mf2_state &= ~0x01;
}
mf2_state &= ~0x02;
}
unsigned int
{
#if BX_CPU < 2
buffer_start = 0x001E;
buffer_end = 0x003E;
#else
#endif
buffer_tail += 2;
if (buffer_tail >= buffer_end)
if (buffer_tail == buffer_head) {
return(0);
}
return(1);
}
void
{
BX_DEBUG_INT74("entering int74_function\n");
make_farcall = 0;
return;
}
return;
}
if ( index >= package_count ) {
BX_DEBUG_INT74("int74_function: make_farcall=1\n");
Z = 0;
mouse_flags_1 = 0;
// check if far call handler installed
if (mouse_flags_2 & 0x80)
make_farcall = 1;
}
else {
}
}
#if BX_USE_ATADRV
void
{
// basic check : device has to be defined
goto int13_fail;
}
// Get the ata channel
// basic check : device has to be valid
if (device >= BX_MAX_ATA_DEVICES) {
goto int13_fail;
}
switch (GET_AH()) {
case 0x00: /* disk controller reset */
goto int13_success;
break;
case 0x01: /* read disk status */
/* set CF if error status read */
if (status) goto int13_fail_nostatus;
else goto int13_success_noah;
break;
case 0x02: // read disk sectors
case 0x03: // write disk sectors
case 0x04: // verify disk sectors
goto int13_fail;
}
// sanity check on cyl heads, sec
BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
goto int13_fail;
}
// FIXME verify
// if needed, translate lchs to lba, and execute command
sector = 0; // this forces the command to be lba
}
if ( GET_AH() == 0x02 )
status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
else
status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
// Set nb of sector transferred
if (status != 0) {
SET_AH(0x0c);
goto int13_fail_noah;
}
goto int13_success;
break;
case 0x05: /* format disk track */
BX_INFO("format disk track called\n");
goto int13_success;
return;
break;
case 0x08: /* read disk drive parameters */
// Get logical geometry from table
#ifndef VBOX
#else /* VBOX */
/* Maximum cylinder number is just one less than the number of cylinders. */
#endif /* VBOX */
SET_AL(0);
// FIXME should set ES & DI
goto int13_success;
break;
case 0x10: /* check drive ready */
// should look at 40:8E also???
// Read the status from controller
goto int13_success;
}
else {
SET_AH(0xAA);
goto int13_fail_noah;
}
break;
case 0x15: /* read disk drive size */
// Get physical geometry from table
// Compute sector count seen by int13
#ifndef VBOX
#else /* VBOX */
/* Is it so hard to multiply a couple of counts (without introducing
* arbitrary off by one errors)? */
#endif /* VBOX */
goto int13_success_noah;
break;
goto int13_success_noah;
break;
// Can't use 64 bits lba
if (lba != 0L) {
goto int13_fail;
}
// Get 32 bits lba and check
goto int13_fail;
}
// If verify or seek
goto int13_success;
// Execute the command
if ( GET_AH() == 0x42 )
#ifdef VBOX
{
else
}
#else /* !VBOX */
#endif /* VBOX */
else
#ifdef VBOX
{
else
}
#else /* !VBOX */
#endif /* VBOX */
if (status != 0) {
SET_AH(0x0c);
goto int13_fail_noah;
}
goto int13_success;
break;
goto int13_success; // Always success for HD
break;
goto int13_fail_noah; // Always fail for HD
break;
// Buffer is too small
if(size < 0x1a)
goto int13_fail;
// EDD 1.x
if(size >= 0x1a) {
}
// EDD 2.x
if(size >= 0x1e) {
// Fill in dpte
checksum=0;
}
// EDD 3.x
if(size >= 0x42) {
if (iface==ATA_IFACE_ISA) {
}
else {
// FIXME PCI
}
if (iface==ATA_IFACE_ISA) {
}
else {
// FIXME PCI
}
checksum=0;
}
goto int13_success;
break;
// DMA, prefetch, PIO maximum not supported
switch (GET_AL()) {
case 0x01:
case 0x03:
case 0x04:
case 0x06:
goto int13_success;
break;
default :
goto int13_fail;
}
break;
case 0x09: /* initialize drive parameters */
case 0x0c: /* seek to specified cylinder */
case 0x0d: /* alternate disk reset */
case 0x11: /* recalibrate */
case 0x14: /* controller internal diagnostic */
goto int13_success;
break;
case 0x0a: /* read disk sectors with ECC */
case 0x0b: /* write disk sectors with ECC */
case 0x18: // set media type for format
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
// ---------------------------------------------------------------------------
// Start of int13 for cdrom
// ---------------------------------------------------------------------------
void
{
SET_DISK_RET_STATUS(0x00);
/* basic check : device should be 0xE0+ */
goto int13_fail;
}
// Get the ata channel
/* basic check : device has to be valid */
if (device >= BX_MAX_ATA_DEVICES) {
goto int13_fail;
}
switch (GET_AH()) {
// all those functions return SUCCESS
case 0x00: /* disk controller reset */
case 0x09: /* initialize drive parameters */
case 0x0c: /* seek to specified cylinder */
case 0x0d: /* alternate disk reset */
case 0x10: /* check drive ready */
case 0x11: /* recalibrate */
case 0x14: /* controller internal diagnostic */
case 0x16: /* detect disk change */
goto int13_success;
break;
// all those functions return disk write-protected
case 0x03: /* write disk sectors */
case 0x05: /* format disk track */
SET_AH(0x03);
goto int13_fail_noah;
break;
case 0x01: /* read disk status */
/* set CF if error status read */
if (status) goto int13_fail_nostatus;
else goto int13_success_noah;
break;
case 0x15: /* read disk drive size */
SET_AH(0x02);
goto int13_fail_noah;
break;
goto int13_success_noah;
break;
// Can't use 64 bits lba
if (lba != 0L) {
goto int13_fail;
}
// Get 32 bits lba
// If verify or seek
goto int13_success;
if (status != 0) {
SET_AH(0x0c);
goto int13_fail_noah;
}
goto int13_success;
break;
switch (GET_AL()) {
case 0 : // lock
if (locks == 0xff) {
SET_AH(0xb4);
SET_AL(1);
goto int13_fail_noah;
}
SET_AL(1);
break;
case 1 : // unlock
if (locks == 0x00) {
SET_AH(0xb0);
SET_AL(0);
goto int13_fail_noah;
}
break;
case 2 : // status
break;
}
goto int13_success;
break;
if (locks != 0) {
goto int13_fail_noah;
}
// FIXME should handle 0x31 no media in device
// FIXME should handle 0xb5 valid request failed
// Call removable media eject
int 15
if (status != 0) {
goto int13_fail_noah;
}
goto int13_success;
break;
// Buffer is too small
if(size < 0x1a)
goto int13_fail;
// EDD 1.x
if(size >= 0x1a) {
}
// EDD 2.x
if(size >= 0x1e) {
// Fill in dpte
// FIXME atapi device
checksum=0;
}
// EDD 3.x
if(size >= 0x42) {
if (iface==ATA_IFACE_ISA) {
}
else {
// FIXME PCI
}
if (iface==ATA_IFACE_ISA) {
}
else {
// FIXME PCI
}
checksum=0;
}
goto int13_success;
break;
// always send changed ??
SET_AH(06);
goto int13_fail_nostatus;
break;
// DMA, prefetch, PIO maximum not supported
switch (GET_AL()) {
case 0x01:
case 0x03:
case 0x04:
case 0x06:
goto int13_success;
break;
default :
goto int13_fail;
}
break;
// all those functions return unimplemented
case 0x02: /* read sectors */
case 0x04: /* verify sectors */
case 0x08: /* read disk drive parameters */
case 0x0a: /* read disk sectors with ECC */
case 0x0b: /* write disk sectors with ECC */
case 0x18: /* set media type for format */
case 0x50: // ? - send packet command
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
// ---------------------------------------------------------------------------
// End of int13 for cdrom
// ---------------------------------------------------------------------------
#if BX_ELTORITO_BOOT
// ---------------------------------------------------------------------------
// Start of int13 for eltorito functions
// ---------------------------------------------------------------------------
void
{
// BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
switch (GET_AH()) {
// FIXME ElTorito Various. Should be implemented
case 0x4a: // ElTorito - Initiate disk emu
case 0x4c: // ElTorito - Initiate disk emu and boot
case 0x4d: // ElTorito - Return Boot catalog
goto int13_fail;
break;
case 0x4b: // ElTorito - Terminate disk emu
// FIXME ElTorito Hardcoded
// If we have to terminate emulation
if(GET_AL() == 0x00) {
// FIXME ElTorito Various. Should be handled accordingly to spec
}
goto int13_success;
break;
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
// ---------------------------------------------------------------------------
// End of int13 for eltorito functions
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// Start of int13 when emulating a device from the cd
// ---------------------------------------------------------------------------
void
{
// Recompute the device number
SET_DISK_RET_STATUS(0x00);
/* basic checks : emulation should be active, dl should equal the emulated drive */
goto int13_fail;
}
switch (GET_AH()) {
// all those functions return SUCCESS
case 0x00: /* disk controller reset */
case 0x09: /* initialize drive parameters */
case 0x0c: /* seek to specified cylinder */
case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
case 0x11: /* recalibrate */
case 0x14: /* controller internal diagnostic */
case 0x16: /* detect disk change */
goto int13_success;
break;
// all those functions return disk write-protected
case 0x03: /* write disk sectors */
case 0x05: /* format disk track */
SET_AH(0x03);
goto int13_fail_noah;
break;
case 0x01: /* read disk status */
/* set CF if error status read */
if (status) goto int13_fail_nostatus;
else goto int13_success_noah;
break;
case 0x02: // read disk sectors
case 0x04: // verify disk sectors
// no sector to read ?
if(nbsectors==0) goto int13_success;
// sanity checks sco openserver needs this!
|| (cylinder >= vcylinders)
goto int13_fail;
}
// After controls, verify do nothing
// calculate the virtual lba inside the image
// In advance so we don't loose the count
// start lba on cd
// end lba on cd
if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
SET_AH(0x02);
SET_AL(0);
goto int13_fail_noah;
}
goto int13_success;
break;
case 0x08: /* read disk drive parameters */
SET_AL( 0x00 );
SET_BL( 0x00 );
// FIXME ElTorito Harddisk. should send the HD count
}
goto int13_success;
break;
case 0x15: /* read disk drive size */
// FIXME ElTorito Harddisk. What geometry to send ?
SET_AH(0x03);
goto int13_success_noah;
break;
// all those functions return unimplemented
case 0x0a: /* read disk sectors with ECC */
case 0x0b: /* write disk sectors with ECC */
case 0x18: /* set media type for format */
// FIXME ElTorito Harddisk. Darwin would like to use EDD
case 0x4e: // ? - set hardware configuration
case 0x50: // ? - send packet command
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
// ---------------------------------------------------------------------------
// End of int13 when emulating a device from the cd
// ---------------------------------------------------------------------------
#endif // BX_ELTORITO_BOOT
#else //BX_USE_ATADRV
void
{
}
void
{
unsigned int i;
/* at this point, DL is >= 0x80 to be passed from the floppy int13h
handler code */
/* check how many disks first (cmos reg 0x12), return an error if
drive not present */
SET_AH(0x01);
SET_DISK_RET_STATUS(0x01);
SET_CF(); /* error occurred */
return;
}
switch (GET_AH()) {
case 0x00: /* disk controller reset */
BX_DEBUG_INT13_HD("int13_f00\n");
SET_AH(0);
set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
CLEAR_CF(); /* successful */
return;
break;
case 0x01: /* read disk status */
BX_DEBUG_INT13_HD("int13_f01\n");
/* set CF if error status read */
else CLEAR_CF();
return;
break;
case 0x04: // verify disk sectors
case 0x02: // read disk sectors
num_sectors = GET_AL();
if (hd_cylinders > 1024) {
if (hd_cylinders <= 2048) {
cylinder <<= 1;
}
else if (hd_cylinders <= 4096) {
cylinder <<= 2;
}
else if (hd_cylinders <= 8192) {
cylinder <<= 3;
}
else { // hd_cylinders <= 16384
cylinder <<= 4;
}
}
if ( (cylinder >= hd_cylinders) ||
(sector > hd_sectors) ||
SET_AH(1);
SET_CF(); /* error occurred */
return;
}
BX_PANIC("int13_harddisk: num_sectors out of range!\n");
if (head > 15)
if ( GET_AH() == 0x04 ) {
SET_AH(0);
CLEAR_CF();
return;
}
if (status & 0x80) {
}
/* activate LBA? (tomv) */
if (hd_heads > 16) {
}
else {
}
while (1) {
if ( !(status & 0x80) ) break;
}
if (status & 0x01) {
} else if ( !(status & 0x08) ) {
}
sector_count = 0;
while (1) {
sector_count++;
num_sectors--;
if (num_sectors == 0) {
break;
}
else {
continue;
}
}
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x03: /* write disk sectors */
BX_DEBUG_INT13_HD("int13_f03\n");
num_sectors = GET_AL();
if (hd_cylinders > 1024) {
if (hd_cylinders <= 2048) {
cylinder <<= 1;
}
else if (hd_cylinders <= 4096) {
cylinder <<= 2;
}
else if (hd_cylinders <= 8192) {
cylinder <<= 3;
}
else { // hd_cylinders <= 16384
cylinder <<= 4;
}
}
if ( (cylinder >= hd_cylinders) ||
(sector > hd_sectors) ||
SET_AH( 1);
SET_CF(); /* error occurred */
return;
}
BX_PANIC("int13_harddisk: num_sectors out of range!\n");
if (head > 15)
BX_PANIC("hard drive BIOS:(read) head > 15\n");
if (status & 0x80) {
BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
}
// should check for Drive Ready Bit also in status reg
/* activate LBA? (tomv) */
if (hd_heads > 16) {
}
else {
}
// wait for busy bit to turn off after seeking
while (1) {
if ( !(status & 0x80) ) break;
}
if ( !(status & 0x08) ) {
BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
}
sector_count = 0;
while (1) {
sector_count++;
num_sectors--;
if (num_sectors == 0) {
break;
}
else {
continue;
}
}
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x05: /* format disk track */
BX_DEBUG_INT13_HD("int13_f05\n");
BX_PANIC("format disk track called\n");
/* nop */
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x08: /* read disk drive parameters */
BX_DEBUG_INT13_HD("int13_f08\n");
// translate CHS
//
if (hd_cylinders <= 1024) {
// hd_cylinders >>= 0;
// hd_heads <<= 0;
}
else if (hd_cylinders <= 2048) {
hd_cylinders >>= 1;
hd_heads <<= 1;
}
else if (hd_cylinders <= 4096) {
hd_cylinders >>= 2;
hd_heads <<= 2;
}
else if (hd_cylinders <= 8192) {
hd_cylinders >>= 3;
hd_heads <<= 3;
}
else { // hd_cylinders <= 16384
hd_cylinders >>= 4;
hd_heads <<= 4;
}
SET_AL(0);
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x09: /* initialize drive parameters */
BX_DEBUG_INT13_HD("int13_f09\n");
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x0a: /* read disk sectors with ECC */
BX_DEBUG_INT13_HD("int13_f0a\n");
case 0x0b: /* write disk sectors with ECC */
BX_DEBUG_INT13_HD("int13_f0b\n");
BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
return;
break;
case 0x0c: /* seek to specified cylinder */
BX_DEBUG_INT13_HD("int13_f0c\n");
BX_INFO("int13h function 0ch (seek) not implemented!\n");
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x0d: /* alternate disk reset */
BX_DEBUG_INT13_HD("int13_f0d\n");
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x10: /* check drive ready */
BX_DEBUG_INT13_HD("int13_f10\n");
//SET_AH(0);
//SET_DISK_RET_STATUS(0);
//CLEAR_CF(); /* successful */
//return;
//break;
// should look at 40:8E also???
SET_AH(0);
CLEAR_CF(); // drive ready
return;
}
else {
SET_AH(0xAA);
SET_DISK_RET_STATUS(0xAA);
SET_CF(); // not ready
return;
}
break;
case 0x11: /* recalibrate */
BX_DEBUG_INT13_HD("int13_f11\n");
SET_AH(0);
CLEAR_CF(); /* successful */
return;
break;
case 0x14: /* controller internal diagnostic */
BX_DEBUG_INT13_HD("int13_f14\n");
SET_AH(0);
CLEAR_CF(); /* successful */
SET_AL(0);
return;
break;
case 0x15: /* read disk drive size */
SET_DISK_RET_STATUS(0); // ??? should this be 0
CLEAR_CF(); // successful
return;
break;
case 0x18: // set media type for format
default:
SET_CF(); /* unsuccessful */
return;
break;
}
}
static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
void
{
if (drive == 0x80) {
if (hd_type != 0xf0)
if (hd_type != 47)
iobase = 0x1b;
} else {
if (hd_type != 0x0f)
if (hd_type != 47)
iobase = 0x24;
}
// cylinders
// heads
// sectors per track
}
#endif //else BX_USE_ATADRV
//////////////////////
// FLOPPY functions //
//////////////////////
void floppy_reset_controller()
{
// Reset controller
// Wait for controller to come out of reset
do {
}
{
// set 40:3e bit 7 to 0
val8 &= 0x7f;
// turn on motor of selected drive, DMA & int enabled, normal operation
if (drive)
dor = 0x20;
else
dor = 0x10;
dor |= 0x0c;
// reset the disk motor timeout value of INT 08
#ifdef VBOX
// program data rate
val8 >>= 6;
#endif
// wait for drive readiness
do {
if (prev_reset == 0) {
// turn on interrupts
// wait on 40:3e bit 7 to become 1
do {
} while ( (val8 & 0x80) == 0 );
val8 &= 0x7f;
}
}
{
if (drive)
val8 >>= 1;
val8 &= 0x01;
if (val8 == 0)
return(0);
media_state_offset = 0x0090;
if (drive)
media_state_offset += 1;
if (val8 == 0)
return(0);
// check pass, return KNOWN
return(1);
}
{
if (floppy_drive_recal(drive) == 0) {
return(0);
}
// for now cheat and get drive type from CMOS,
// assume media is same as drive type
// ** config_data **
// Bitfields for diskette media control:
// Bit(s) Description (Table M0028)
// 7-6 last data rate set by controller
// 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
// 5-4 last diskette drive step rate selected
// 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
// 3-2 {data rate at start of operation}
// 1-0 reserved
// ** media_state **
// Bitfields for diskette drive media state:
// Bit(s) Description (Table M0030)
// 7-6 data rate
// 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
// 5 double stepping required (e.g. 360kB in 1.2MB)
// 4 media type established
// 3 drive capable of supporting 4MB media
// 2-0 on exit from BIOS, contains
// 000 trying 360kB in 360kB
// 001 trying 360kB in 1.2MB
// 010 trying 1.2MB in 1.2MB
// 011 360kB in 360kB established
// 100 360kB in 1.2MB established
// 101 1.2MB in 1.2MB established
// 110 reserved
if (drive == 0)
drive_type >>= 4;
else
drive_type &= 0x0f;
if ( drive_type == 1 ) {
// 360K 5.25" drive
retval = 1;
}
else if ( drive_type == 2 ) {
// 1.2 MB 5.25" drive
retval = 1;
}
else if ( drive_type == 3 ) {
// 720K 3.5" drive
retval = 1;
}
else if ( drive_type == 4 ) {
// 1.44 MB 3.5" drive
retval = 1;
}
else if ( drive_type == 5 ) {
// 2.88 MB 3.5" drive
retval = 1;
}
//
// Extended floppy size uses special cmos setting
else if ( drive_type == 6 ) {
// 160k 5.25" drive
retval = 1;
}
else if ( drive_type == 7 ) {
// 180k 5.25" drive
retval = 1;
}
else if ( drive_type == 8 ) {
// 320k 5.25" drive
retval = 1;
}
else {
// not recognized
retval = 0;
}
if (drive == 0)
media_state_offset = 0x90;
else
media_state_offset = 0x91;
return(retval);
}
{
// send Recalibrate command (2 bytes) to controller
// turn on interrupts
// wait on 40:3e bit 7 to become 1
do {
} while ( val8 == 0 );
val8 = 0; // separate asm from while() loop
// turn off interrupts
// set 40:3e bit 7 to 0, and calibrated bit
val8 &= 0x7f;
if (drive) {
curr_cyl_offset = 0x0095;
} else {
curr_cyl_offset = 0x0094;
}
return(1);
}
{
// check CMOS to see if drive exists
if (drive == 0)
drive_type >>= 4;
else
drive_type &= 0x0f;
if ( drive_type == 0 )
return(0);
else
return(1);
}
void
{
switch ( ah ) {
case 0x00: // diskette controller reset
BX_DEBUG_INT13_FL("floppy f00\n");
if (drive > 1) {
SET_CF();
return;
}
if (drive == 0)
drive_type >>= 4;
else
drive_type &= 0x0f;
if (drive_type == 0) {
set_diskette_ret_status(0x80);
SET_CF();
return;
}
SET_AH(0);
CLEAR_CF(); // successful
return;
case 0x01: // Read Diskette Status
CLEAR_CF();
if (val8) {
SET_CF();
}
return;
case 0x02: // Read Diskette Sectors
case 0x03: // Write Diskette Sectors
case 0x04: // Verify Diskette Sectors
num_sectors = GET_AL();
BX_INFO("floppy: drive>1 || head>1 ...\n");
SET_AH(1);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
// see if drive exists
if (floppy_drive_exists(drive) == 0) {
set_diskette_ret_status(0x80);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
// see if media in drive, and type is known
if (floppy_media_known(drive) == 0) {
if (floppy_media_sense(drive) == 0) {
set_diskette_ret_status(0x0C);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
}
if (ah == 0x02) {
// Read Diskette Sectors
//-----------------------------------
// set up DMA controller for transfer
//-----------------------------------
// es:bx = pointer to where to place information from diskette
// port 04: DMA-1 base and current address, channel 2
// port 05: DMA-1 base and current count, channel 2
// contributed by ES:BX
if ( base_address < base_es ) {
// in case of carry, adjust page by 1
page++;
}
// check for 64K boundary overrun
if (last_addr < base_address) {
SET_AH(0x09);
set_diskette_ret_status(0x09);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
BX_DEBUG_INT13_FL("clear flip-flop\n");
BX_DEBUG_INT13_FL("clear flip-flop\n");
// port 0b: DMA-1 Mode Register
// transfer type=write, channel 2
BX_DEBUG_INT13_FL("setting mode register\n");
BX_DEBUG_INT13_FL("setting page register\n");
// port 81: DMA-1 Page Register, channel 2
BX_DEBUG_INT13_FL("unmask chan 2\n");
BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
//--------------------------------------
// set up floppy controller for transfer
//--------------------------------------
// send read-normal-data command (9 bytes) to controller
// turn on interrupts
// wait on 40:3e bit 7 to become 1
do {
if (val8 == 0) {
set_diskette_ret_status(0x80);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
} while ( val8 == 0 );
val8 = 0; // separate asm from while() loop
// turn off interrupts
// set 40:3e bit 7 to 0
val8 &= 0x7f;
// check port 3f4 for accessibility to status bytes
BX_PANIC("int13_diskette: ctrl not ready\n");
// read 7 return status bytes from controller
// using loop index broken, have to unroll...
// record in BIOS Data Area
if ( (return_status[0] & 0xc0) != 0 ) {
SET_AH(0x20);
set_diskette_ret_status(0x20);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
// ??? should track be new val from return_status[3] ?
// AL = number of sectors read (same value as passed)
CLEAR_CF(); // success
return;
} else if (ah == 0x03) {
// Write Diskette Sectors
//-----------------------------------
// set up DMA controller for transfer
//-----------------------------------
// es:bx = pointer to where to place information from diskette
// port 04: DMA-1 base and current address, channel 2
// port 05: DMA-1 base and current count, channel 2
// contributed by ES:BX
if ( base_address < base_es ) {
// in case of carry, adjust page by 1
page++;
}
// check for 64K boundary overrun
if (last_addr < base_address) {
SET_AH(0x09);
set_diskette_ret_status(0x09);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
// port 0b: DMA-1 Mode Register
// transfer type=read, channel 2
// port 81: DMA-1 Page Register, channel 2
BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
//--------------------------------------
// set up floppy controller for transfer
//--------------------------------------
// send write-normal-data command (9 bytes) to controller
// turn on interrupts
// wait on 40:3e bit 7 to become 1
do {
if (val8 == 0) {
set_diskette_ret_status(0x80);
SET_AL(0); // no sectors written
SET_CF(); // error occurred
return;
}
} while ( val8 == 0 );
val8 = 0; // separate asm from while() loop
// turn off interrupts
// set 40:3e bit 7 to 0
val8 &= 0x7f;
// check port 3f4 for accessibility to status bytes
BX_PANIC("int13_diskette: ctrl not ready\n");
// read 7 return status bytes from controller
// using loop index broken, have to unroll...
// record in BIOS Data Area
if ( (return_status[0] & 0xc0) != 0 ) {
// diskette not writable.
// AH=status code=0x03 (tried to write on write-protected disk)
// AL=number of sectors written=0
AX = 0x0300;
SET_CF();
return;
} else {
BX_PANIC("int13_diskette_function: read error\n");
}
}
// ??? should track be new val from return_status[3] ?
// AL = number of sectors read (same value as passed)
CLEAR_CF(); // success
return;
} else { // if (ah == 0x04)
// Verify Diskette Sectors
// ??? should track be new val from return_status[3] ?
// AL = number of sectors verified (same value as passed)
CLEAR_CF(); // success
return;
}
break;
case 0x05: // format diskette track
BX_DEBUG_INT13_FL("floppy f05\n");
num_sectors = GET_AL();
SET_AH(1);
SET_CF(); // error occurred
}
// see if drive exists
if (floppy_drive_exists(drive) == 0) {
set_diskette_ret_status(0x80);
SET_CF(); // error occurred
return;
}
// see if media in drive, and type is known
if (floppy_media_known(drive) == 0) {
if (floppy_media_sense(drive) == 0) {
set_diskette_ret_status(0x0C);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
}
// set up DMA controller for transfer
// contributed by ES:BX
if ( base_address < base_es ) {
// in case of carry, adjust page by 1
page++;
}
// check for 64K boundary overrun
if (last_addr < base_address) {
SET_AH(0x09);
set_diskette_ret_status(0x09);
SET_AL(0); // no sectors read
SET_CF(); // error occurred
return;
}
// transfer type=read, channel 2
// port 81: DMA-1 Page Register, channel 2
// set up floppy controller for transfer
// send format-track command (6 bytes) to controller
// turn on interrupts
// wait on 40:3e bit 7 to become 1
do {
if (val8 == 0) {
set_diskette_ret_status(0x80);
SET_CF(); // error occurred
return;
}
} while ( val8 == 0 );
val8 = 0; // separate asm from while() loop
// turn off interrupts
// set 40:3e bit 7 to 0
val8 &= 0x7f;
// check port 3f4 for accessibility to status bytes
BX_PANIC("int13_diskette: ctrl not ready\n");
// read 7 return status bytes from controller
// using loop index broken, have to unroll...
// record in BIOS Data Area
if ( (return_status[0] & 0xc0) != 0 ) {
// diskette not writable.
// AH=status code=0x03 (tried to write on write-protected disk)
// AL=number of sectors written=0
AX = 0x0300;
SET_CF();
return;
} else {
BX_PANIC("int13_diskette_function: write error\n");
}
}
SET_AH(0);
CLEAR_CF(); // successful
return;
case 0x08: // read diskette drive parameters
BX_DEBUG_INT13_FL("floppy f08\n");
if (drive > 1) {
AX = 0;
BX = 0;
CX = 0;
DX = 0;
ES = 0;
DI = 0;
SET_CF();
return;
}
num_floppies = 0;
if (drive_type & 0xf0)
num_floppies++;
if (drive_type & 0x0f)
num_floppies++;
if (drive == 0)
drive_type >>= 4;
else
drive_type &= 0x0f;
SET_BH(0);
SET_AH(0);
SET_AL(0);
switch (drive_type) {
case 0: // none
CX = 0;
SET_DH(0); // max head #
break;
case 1: // 360KB, 5.25"
break;
case 2: // 1.2MB, 5.25"
break;
case 3: // 720KB, 3.5"
break;
case 4: // 1.44MB, 3.5"
break;
case 5: // 2.88MB, 3.5"
break;
case 6: // 160k, 5.25"
SET_DH(0); // max head #
break;
case 7: // 180k, 5.25"
SET_DH(0); // max head #
break;
case 8: // 320k, 5.25"
break;
default: // ?
BX_PANIC("floppy: int13: bad floppy type\n");
}
/* set es & di to point to 11 byte diskette param table in ROM */
CLEAR_CF(); // success
/* disk status not changed upon success */
return;
case 0x15: // read diskette drive type
BX_DEBUG_INT13_FL("floppy f15\n");
if (drive > 1) {
SET_AH(0); // only 2 drives supported
// set_diskette_ret_status here ???
SET_CF();
return;
}
if (drive == 0)
drive_type >>= 4;
else
drive_type &= 0x0f;
CLEAR_CF(); // successful, not present
if (drive_type==0) {
SET_AH(0); // drive not present
}
else {
}
return;
case 0x16: // get diskette change line status
BX_DEBUG_INT13_FL("floppy f16\n");
if (drive > 1) {
set_diskette_ret_status(0x01);
SET_CF();
return;
}
set_diskette_ret_status(0x06);
SET_CF();
return;
case 0x17: // set diskette type for format(old)
BX_DEBUG_INT13_FL("floppy f17\n");
/* not used for 1.44M floppies */
SET_CF();
return;
case 0x18: // set diskette type for format(new)
BX_DEBUG_INT13_FL("floppy f18\n");
SET_CF();
return;
default:
// if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
SET_CF();
return;
// }
}
}
#else // #if BX_SUPPORT_FLOPPY
void
{
switch ( GET_AH() ) {
case 0x01: // Read Diskette Status
CLEAR_CF();
if (val8) {
SET_CF();
}
return;
default:
SET_CF();
SET_AH(0x01);
}
}
#endif // #if BX_SUPPORT_FLOPPY
void
{
}
void
{
if (drive > 1)
BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
}
void
{
#if 0
if (drive==1)
ctrl_info >>= 4;
else
ctrl_info &= 0x0f;
#if 0
if (drive == 0) {
}
else {
}
#endif
// Drive not determined means no drive exists, done.
return;
}
#if 0
// check Main Status Register for readiness
if (val8 != 0x80)
BX_PANIC("d_f_m: MRQ bit not set\n");
// change line
// existing BDA values
// turn on drive motor
//
#endif
BX_PANIC("d_f_m: OK so far\n");
#endif
}
void
{
timeout--;
}
}
}
} else {
}
}
// returns bootsegment in ax, drive in bl
{
#ifdef VBOX
#endif /* VBOX */
// if BX_ELTORITO_BOOT is not defined, old behavior
// check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
// in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
// 0: system boot sequence, first drive C: then A:
// 1: system boot sequence, first drive A: then C:
// else BX_ELTORITO_BOOT is defined
// CMOS regs 0x3D and 0x38 contain the boot sequence:
// CMOS reg 0x3D & 0x0f : 1st boot device
// CMOS reg 0x3D & 0xf0 : 2nd boot device
// CMOS reg 0x38 & 0xf0 : 3rd boot device
#ifdef VBOX
// CMOS reg 0x3C & 0x0f : 4th boot device
#endif /* VBOX */
// boot device codes:
// 0x00 : not defined
// 0x01 : first floppy
// 0x02 : first harddrive
// 0x03 : first cdrom
#ifdef VBOX
// 0x04 : local area network
#endif /* VBOX */
// else : boot failure
// Get the boot sequence
#if BX_ELTORITO_BOOT
#ifdef VBOX
/* Boot delay hack. */
if (bseqnr == 1)
#endif /* VBOX */
#ifdef VBOX
#endif /* VBOX */
#ifdef VBOX
bootlan=0;
#endif /* VBOX */
switch(bootseq & 0x0f) {
case 0x01:
bootdrv=0x00;
bootcd=0;
break;
case 0x02:
{
// Get the Boot drive.
bootcd=0;
break;
}
case 0x03:
bootdrv=0x00;
bootcd=1;
break;
#ifdef VBOX
#endif /* VBOX */
default: return 0x00000000;
}
#else
if (bseqnr==2) {
bootseq ^= 0x20;
lastdrive = 1;
}
#endif // BX_ELTORITO_BOOT
#if BX_ELTORITO_BOOT
// We have to boot from cd
if (bootcd != 0) {
status = cdrom_boot();
// If failure
if ( (status & 0x00ff) !=0 ) {
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
return 0x00000000;
}
}
#endif // BX_ELTORITO_BOOT
#ifdef VBOX
// Check for boot from LAN first
if (bootlan == 1) {
// This is NOT a generic PnP implementation, but an Etherboot-specific hack.
// Found PnP signature
if (manuf == 0x65687445) {
// Found Etherboot ROM
} else if (manuf == 0x65746E49) {
// Found Intel PXE ROM
}
}
}
// boot from LAN will not return if successful.
return 0x00000000;
}
#endif /* VBOX */
// We have to boot from harddisk or floppy
#ifdef VBOX
#else /* !VBOX */
if (bootcd == 0) {
#endif /* !VBOX */
bootseg=0x07c0;
if (status != 0) {
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
return 0x00000000;
}
}
#ifdef VBOX
// Don't check boot sectors on floppies and don't read CMOS - byte
// 0x38 in CMOS always has the low bit clear.
// There is *no* requirement whatsoever for a valid boot sector to
// have a 55AAh signature. UNIX boot floppies typically have no such
// signature. In general, it is impossible to tell a valid bootsector
// from an invalid one.
// NB: It is somewhat common for failed OS installs to have the
// 0x55AA signature and a valid partition table but zeros in the
// rest of the boot sector. We do a quick check by comparing the first
// two words of boot sector; if identical, the boot sector is
// extremely unlikely to be valid.
#endif
// check signature if instructed by cmos reg 0x38, only for floppy
// bootchk = 1 : signature check disabled
// bootchk = 0 : signature check enabled
#ifdef VBOX
#else
#endif
#if BX_ELTORITO_BOOT
// if boot from cd, no signature check
if (bootcd != 0)
bootchk = 1;
#endif // BX_ELTORITO_BOOT
if (bootchk == 0) {
#ifdef VBOX
#else /* !VBOX */
#endif /* VBOX */
return 0x00000000;
}
}
#if BX_ELTORITO_BOOT
// Print out the boot string
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
#else // BX_ELTORITO_BOOT
#ifdef VBOX
#else /* !VBOX */
print_boot_device(0, bootdrv);
#endif /* !VBOX */
#endif // BX_ELTORITO_BOOT
// return the boot segment
}
void
{
BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
case 0: // get current clock count
// AH already 0
break;
case 1: // Set Current Clock Count
break;
case 2: // Read CMOS Time
if (rtc_updating()) {
break;
}
break;
case 3: // Set CMOS Time
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3
// before 1111 1101 0111 1101 0000 0000
// after 0110 0010 0110 0010 0000 0010
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = ((RegB & 01100000b) | 00000010b)
if (rtc_updating()) {
init_rtc();
// fall through as if an update were not in progress
}
// Set Daylight Savings time enabled bit to requested value
// (reg B already selected)
break;
case 4: // Read CMOS Date
if (rtc_updating()) {
break;
}
break;
case 5: // Set CMOS Date
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3 try#4
// before 1111 1101 0111 1101 0000 0010 0000 0000
// after 0110 1101 0111 1101 0000 0010 0000 0000
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = (RegB & 01111111b)
if (rtc_updating()) {
init_rtc();
break;
}
break;
case 6: // Set Alarm Time in CMOS
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3
// before 1101 1111 0101 1111 0000 0000
// after 0110 1111 0111 1111 0010 0000
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = ((RegB & 01111111b) | 00100000b)
if (val8 & 0x20) {
// Alarm interrupt enabled already
break;
}
if (rtc_updating()) {
init_rtc();
// fall through as if an update were not in progress
}
// enable Status Reg B alarm bit, clear halt clock bit
break;
case 7: // Turn off Alarm
// of bits in Status Register B, by setting Reg B to
// a few values and getting its value after INT 1A was called.
//
// try#1 try#2 try#3 try#4
// before 1111 1101 0111 1101 0010 0000 0010 0010
// after 0100 0101 0101 0101 0000 0000 0000 0010
//
// Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
// My assumption: RegB = (RegB & 01010111b)
// clear clock-halt bit, disable alarm bit
break;
#if BX_PCIBIOS
case 0xb1:
// real mode PCI BIOS functions now handled in assembler code
// this C code handles the error code for information only
BX_INFO("PCI BIOS: PCI not present\n");
BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
} else {
BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", regs.u.r8.cl, regs.u.r16.dx, regs.u.r16.si);
}
}
break;
#endif
default:
}
}
void
{
// INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
// Check which modes are enabled and have occurred.
if( ( registerB & 0x60 ) != 0 ) {
if( ( registerC & 0x20 ) != 0 ) {
// Handle Alarm Interrupt.
int #0x4a
}
if( ( registerC & 0x40 ) != 0 ) {
// Handle Periodic Interrupt.
// Wait Interval (Int 15, AH=83) active.
if( time < 0x3D1 ) {
// Done waiting.
} else {
// Continue waiting.
time -= 0x3D1;
}
}
}
}
}
void
{
// Interrupt handler for unexpected hardware interrupts. We have to clear
// the PIC because if we don't, the next EOI will clear the wrong interrupt
// and all hell will break loose! This routine also masks the unexpected
// interrupt so it will generally be called only once for each unexpected
// interrupt level.
if (isrA) {
if (isrB) {
} else {
}
}
}
;------------------------------------------
;------------------------------------------
push #0x00
//CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
;----------------------
;----------------------
;
;
#if BX_ELTORITO_BOOT
#endif // BX_ELTORITO_BOOT
#if BX_USE_ATADRV
// ebx is modified: BSD 5.2.1 boot loader problem
// someone should figure out which 32 bit register that actually are used
#endif
;----------
;- INT18h -
;----------
;----------
;- INT19h -
;----------
#ifdef VBOX
// If an already booted OS calls int 0x19 to reboot, it is not sufficient
// just to try booting from the configured drives. All BIOS variables and
// interrupt vectors need to be reset, otherwise strange things may happen.
// The approach used is faking a warm reboot (which just skips showing the
// logo), which is a bit more than what we need, but hey, it's fast.
#endif /* VBOX */
#ifdef VBOX
#endif /* VBOX */
;----------
;- INT1Ch -
;----------
;----------------------
;----------------------
;; -----------------------------------------------------------------
;;
;; -----------------------------------------------------------------
;--------------------
;--------------------
// IRQ 14 = INT 76h
// INT 76h calls INT 15h function ax=9100
#ifndef VBOX /* This is done later (and the CMOS format is now different). */
;; checksum
;; checksum
#endif /* !VBOX */
;--------------------
;--------------------
#if BX_USE_EBDA
#endif
ret;;
;--------------------
;--------------------
;--------------------
;--------------------
;--------------------
;;
;;
;; arithmatic, I use:
;--------------------
;--------------------
#if BX_APM
use32 386
#define APM_PROT32
#include "apmbios.S"
use16 386
#define APM_PROT16
#include "apmbios.S"
#define APM_REAL
#include "apmbios.S"
#endif
;--------------------
#if BX_PCIBIOS
use32 386
.align 16
& 0xff) << 8) + 0x01
.align 16
#ifdef PCI_FIXED_HOST_BRIDGE
#else
#endif
#ifdef BX_QEMU
#endif
.align 16
#ifdef BX_QEMU
#endif
#ifdef BX_QEMU
#endif
use16 386
#ifdef PCI_FIXED_HOST_BRIDGE
#else
#endif
.align 16
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
#ifdef VBOX
#else /* !VBOX */
#endif /* !VBOX */
#ifdef VBOX
#endif /* VBOX */
#if !BX_ROMBIOS32
#ifndef VBOX /* This currently breaks restoring a previously saved state. */
#endif /* !VBOX */
#ifdef VBOX
#endif /* VBOX */
#endif // BX_ROMBIOS32
#endif // BX_PCIBIOS
#if BX_ROMBIOS32
dw 0x0010
use32 386
db 0xea
dw 0x20
use16 386
dw 0x30
dw 0x000f
dw 0, 0, 0, 0
dw 0, 0, 0, 0
#endif
;;
;; Header:
;; 0 0x55
;; 1 0xAA
db 0x5e
db 0
.align 16
dd 0xaafb4442
;--------
;- POST -
;--------
post:
#if 0
;
;#if 0
; 0xb0, 0x20, /* mov al, #0x20 */
; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
;#endif
;
#endif
#ifndef VBOX
#else /* VBOX */
#endif
SET_INT_VECTOR(0x79, #0, #0)
#ifndef VBOX
#endif /* !VBOX */
;; Keyboard
/* keyboard head of buffer pointer */
/* keyboard end of buffer pointer */
/* keyboard pointer to start of buffer */
/* keyboard pointer to end of buffer */
/* init the keyboard */
;; PIC
#if BX_USE_PS2_MOUSE
#else
#endif
#if BX_ROMBIOS32
#else
#endif
#if BX_USE_ATADRV
;;
;;
;;
#endif
;;
;;
;;
;;
#if BX_ELTORITO_BOOT
;;
;;
;;
#endif // BX_ELTORITO_BOOT
int #0x19
nmi:
int 2 // legacy nmi call
;-------------------------------------------
;-------------------------------------------
//JMPL(int13_relocated)
;----------
;- INT19h -
;----------
;-------------------------------------------
;-------------------------------------------
db (0 << 7) | \
(1 << 6) | \
(1 << 5) | \
(BX_CALL_INT15_4F << 4) | \
(0 << 3) | \
(BX_USE_EBDA << 2) | \
(0 << 1) | \
(0 << 0)
db (0 << 7) | \
(1 << 6) | \
(0 << 5) | \
(0 << 4) | \
(0 << 3) | \
(0 << 2) | \
(0 << 1) | \
(0 << 0)
db 0x00
db 0x00
db 0x00
;----------
;- INT14h -
;----------
;----------------------------------------
;----------------------------------------
.org 0xe82e
//SEG SS
//SEG SS
#if 0
/* no key yet, call int 15h, function AX=9002 */
0x50, /* push AX */
0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
0xcd, 0x15, /* int 15h */
0x58, /* pop AX */
0xeb, 0xea, /* jmp WAIT_FOR_KEY */
#endif
#if 0
/* notify int16 complete w/ int 15h, function AX=9102 */
0x50, /* push AX */
0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
0xcd, 0x15, /* int 15h */
0x58, /* pop AX */
#endif
;-------------------------------------------------
;-------------------------------------------------
.org 0xe987
#ifdef BX_CALL_INT15_4F
int #0x15
#endif
;----------------------------------------
;----------------------------------------
.org 0xec59
;---------------------------------------------
;---------------------------------------------
db 0xAF
db 0x25
db 0x02
db 18
db 0x1B
db 0xFF
db 0x6C
db 0xF6
db 0x0F
db 0x08
;----------------------------------------
;----------------------------------------
.org 0xefd2
db 0xAF
db 0x25
db 0x02
db 18
db 0x1B
db 0xFF
db 0x6C
db 0xF6
db 0x0F
db 0x08
;----------
;- INT10h -
;----------
;----------
;- INT12h -
;----------
;----------
;- INT11h -
;----------
;----------
;- INT15h -
;----------
#if BX_APM
#endif
#if BX_USE_PS2_MOUSE
#endif
#if BX_APM
#endif
#if BX_USE_PS2_MOUSE
#endif
;;
;; transfers.
;;
;;
;; base = 000000
;; limit = 03ff
;;
;;
;----------
;- INT1Ah -
;----------
#if BX_PCIBIOS
retf 2
#endif
;;
;;
;---------
;- INT08 -
;---------
//pushf
//;; call_ep [ds:loc]
//CALL_EP( 0x1c << 2 )
int #0x1c
.org 0xff00
#ifdef VBOX
// The DMI header
.org 0xff40
.align 16
)) & 0xff
#endif
;------------------------------------------------
;------------------------------------------------
/*
* This font comes from the fntcol16.zip package (c) by Joseph Gil
* This font is public domain
*/
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
};
.org 0xcc00
// bcc-generated data will be placed here