[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [Patch][RFC] Update rombios.c
Hi, all This patch update rombios to the latest Bochs's. I'd like to corabolate bochs community to enhance the guest bios. I'm not familiar around TCGBIOS. So could you review the patch? I tested boot/shutdown, S3 suspend/resume with linux guest. Any comments are welcome :-) Best Regards, Akio Takebe diff -r a76b4e00e186 tools/firmware/rombios/rombios.c --- a/tools/firmware/rombios/rombios.c Tue Dec 16 13:14:25 2008 +0000 +++ b/tools/firmware/rombios/rombios.c Wed Dec 17 23:38:15 2008 +0900 @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $ +// $Id: rombios.c,v 1.221 2008/12/07 17:32:29 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2002 MandrakeSoft S.A. @@ -22,9 +22,9 @@ // // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -// ROM BIOS for use with Bochs/Plex x86 emulation environment +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment #define uint8_t unsigned char #define uint16_t unsigned short @@ -81,10 +81,10 @@ // // NOTES for El-Torito Boot (cbbochs@xxxxxxx) // - CD-ROM booting is only available if ATA/ATAPI Driver is available -// - Current code is only able to boot mono-session cds +// - 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. +// - 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: @@ -102,13 +102,13 @@ // 12 : can not read cd - boot image // // ATA driver -// - EBDA segment. +// - EBDA segment. // I used memory starting at 0x121 in the segment // - the translation policy is defined in cmos regs 0x39 & 0x3a // // TODO : // -// int74 +// int74 // - needs to be reworked. Uses direct [bp] offsets. (?) // // int13: @@ -128,13 +128,13 @@ // - 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. +// 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) -#define DEBUG_ROMBIOS 0 +#include "rombios.h" #define DEBUG_ATA 0 #define DEBUG_INT13_HD 0 @@ -159,7 +159,7 @@ #define BX_USE_ATADRV 1 #define BX_ELTORITO_BOOT 1 -#define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */ +#define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */ #define BX_MAX_ATA_INTERFACES 4 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2) @@ -181,7 +181,6 @@ // EBDA is used for PS/2 mouse support, and IDE BIOS, etc. #define EBDA_SEG 0x9FC0 #define EBDA_SIZE 1 // In KiB -#define EBDA_SEG_PTR 0x40E /* Find true EBDA segment at 0:40E */ #define BASE_MEM_IN_K (640 - EBDA_SIZE) /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */ @@ -189,15 +188,13 @@ #define IPL_TABLE_ENTRIES 8 #define IPL_COUNT_OFFSET 0x0380 /* u16: number of valid table entries */ #define IPL_SEQUENCE_OFFSET 0x0382 /* u16: next boot device */ - - // Define the application NAME -#ifdef HVMASSIST -# define BX_APPNAME "HVMAssist" -#elif PLEX86 -# define BX_APPNAME "Plex86" -#else -# define BX_APPNAME "Bochs" -#endif +#define IPL_BOOTFIRST_OFFSET 0x0384 /* u16: user selected device */ +#define IPL_SIZE 0xff +#define IPL_TYPE_FLOPPY 0x01 +#define IPL_TYPE_HARDDISK 0x02 +#define IPL_TYPE_CDROM 0x03 +#define IPL_TYPE_BEV 0x80 + // Sanity Checks #if BX_USE_ATADRV && BX_CPU<3 @@ -216,15 +213,10 @@ # error APM BIOS can only be used with 386+ cpu #endif -#ifndef BX_SMP_PROCESSORS -#define BX_SMP_PROCESSORS 1 -# warning BX_SMP_PROCESSORS not defined, defaulting to 1 -#endif - -#define PANIC_PORT 0x400 -#define PANIC_PORT2 0x401 -#define INFO_PORT 0x402 -#define DEBUG_PORT 0x403 +// 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 +#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge // #20 is dec 20 // #$20 is hex 20 = 32 @@ -257,7 +249,7 @@ MACRO HALT ;; the HALT macro is called with the line number of the HALT call. - ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex + ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex ;; to print a BX_PANIC message. This will normally halt the simulation ;; with a message such as "BIOS panic at rombios.c, line 4091". ;; However, users can choose to make panics non-fatal and continue. @@ -296,9 +288,9 @@ void memsetb(seg,offset,value,count); void memcpyb(dseg,doffset,sseg,soffset,count); void memcpyd(dseg,doffset,sseg,soffset,count); - + // memset of count bytes - void + void memsetb(seg,offset,value,count) Bit16u seg; Bit16u offset; @@ -308,14 +300,14 @@ ASM_START push bp mov bp, sp - + push ax push cx push es push di - + mov cx, 10[bp] ; count - cmp cx, #0x00 + test cx, cx je memsetb_end mov ax, 4[bp] ; segment mov es, ax @@ -325,19 +317,19 @@ cld rep stosb - + memsetb_end: pop di pop es pop cx pop ax - + pop bp ASM_END } - + // memcpy of count bytes - void + void memcpyb(dseg,doffset,sseg,soffset,count) Bit16u dseg; Bit16u doffset; @@ -348,16 +340,16 @@ ASM_START push bp mov bp, sp - + push ax push cx push es push di push ds push si - + mov cx, 12[bp] ; count - cmp cx, #0x0000 + test cx, cx je memcpyb_end mov ax, 4[bp] ; dsegment mov es, ax @@ -370,7 +362,7 @@ cld rep movsb - + memcpyb_end: pop si pop ds @@ -378,14 +370,13 @@ pop es pop cx pop ax - + pop bp ASM_END } -#if 0 // memcpy of count dword - void + void memcpyd(dseg,doffset,sseg,soffset,count) Bit16u dseg; Bit16u doffset; @@ -396,16 +387,16 @@ ASM_START push bp mov bp, sp - + push ax push cx push es push di push ds push si - + mov cx, 12[bp] ; count - cmp cx, #0x0000 + test cx, cx je memcpyd_end mov ax, 4[bp] ; dsegment mov es, ax @@ -418,7 +409,7 @@ cld rep movsd - + memcpyd_end: pop si pop ds @@ -426,16 +417,15 @@ pop es pop cx pop ax - + pop bp ASM_END } -#endif // read_dword and write_dword functions static Bit32u read_dword(); static void write_dword(); - + Bit32u read_dword(seg, offset) Bit16u seg; @@ -444,25 +434,24 @@ ASM_START push bp mov bp, sp - + push bx push ds mov ax, 4[bp] ; segment mov ds, ax mov bx, 6[bp] ; offset mov ax, [bx] - inc bx - inc bx + add bx, #2 mov dx, [bx] ;; ax = return value (word) ;; dx = return value (word) pop ds pop bx - + pop bp ASM_END } - + void write_dword(seg, offset, data) Bit16u seg; @@ -472,7 +461,7 @@ ASM_START push bp mov bp, sp - + push ax push bx push ds @@ -481,50 +470,49 @@ mov bx, 6[bp] ; offset mov ax, 8[bp] ; data word mov [bx], ax ; write data word - inc bx - inc bx + add bx, #2 mov ax, 10[bp] ; data word mov [bx], ax ; write data word pop ds pop bx pop ax - + pop bp ASM_END } - + // Bit32u (unsigned long) and long helper functions ASM_START - + ;; and function landl: landul: - SEG SS + SEG SS and ax,[di] - SEG SS + SEG SS and bx,2[di] ret - + ;; add function laddl: laddul: - SEG SS + SEG SS add ax,[di] - SEG SS + SEG SS adc bx,2[di] ret - + ;; cmp function lcmpl: lcmpul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx shr ebx, #16 SEG SS cmp eax, dword ptr [di] ret - + ;; sub function lsubl: lsubul: @@ -533,26 +521,26 @@ SEG SS sbb bx,2[di] ret - + ;; mul function lmull: lmulul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx SEG SS mul eax, dword ptr [di] mov ebx, eax shr ebx, #16 ret - + ;; dec function ldecl: ldecul: SEG SS dec dword ptr [bx] ret - + ;; or function lorl: lorul: @@ -561,31 +549,31 @@ SEG SS or bx,2[di] ret - + ;; inc function lincl: lincul: SEG SS inc dword ptr [bx] ret - + ;; tst function ltstl: ltstul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx shr ebx, #16 test eax, eax ret - + ;; sr function lsrul: mov cx,di jcxz lsr_exit and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx lsr_loop: shr eax, #1 loop lsr_loop @@ -593,7 +581,7 @@ shr ebx, #16 lsr_exit: ret - + ;; sl function lsll: lslul: @@ -601,15 +589,15 @@ jcxz lsl_exit and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx - lsl_loop: + or eax, ebx + lsl_loop: shl eax, #1 loop lsl_loop mov ebx, eax shr ebx, #16 lsl_exit: ret - + idiv_: cwd idiv bx @@ -623,7 +611,7 @@ ldivul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx xor edx, edx SEG SS mov bx, 2[di] @@ -672,7 +660,7 @@ Bit8u revision; Bit8u checksum; } dpte_t; - + typedef struct { Bit8u iface; // ISA or PCI Bit16u iobase1; // IO Base 1 @@ -685,15 +673,15 @@ Bit8u device; // Detected type of attached devices (hd/cd/none) Bit8u removable; // Removable device flag Bit8u lock; // Locks for removable devices - // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices - Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA + Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA Bit16u blksize; // block size Bit8u translation; // type of translation chs_t lchs; // Logical CHS chs_t pchs; // Physical CHS - Bit32u sectors; // Total sectors count + Bit32u sectors_low; // Total sectors count + Bit32u sectors_high; } ata_device_t; typedef struct { @@ -704,10 +692,10 @@ ata_device_t devices[BX_MAX_ATA_DEVICES]; // // map between (bios hd id - 0x80) and ata channels - Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES]; + Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES]; // map between (bios cd id - 0xE0) and ata channels - Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES]; + Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES]; // Buffer for DPTE table dpte_t dpte; @@ -717,9 +705,9 @@ Bit32u trsfbytes; } ata_t; - -#if BX_ELTORITO_BOOT - // ElTorito Device Emulation data + +#if BX_ELTORITO_BOOT + // ElTorito Device Emulation data typedef struct { Bit8u active; Bit8u media; @@ -730,20 +718,20 @@ Bit16u buffer_segment; Bit16u load_segment; Bit16u sector_count; - + // Virtual device chs_t vdevice; } cdemu_t; #endif // BX_ELTORITO_BOOT - + #include "32bitgateway.h" // for access to EBDA area - // The EBDA structure should conform to - // http://www.cybertrails.com/~fys/rombios.htm document + // 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 - // EBDA must be at most 768 bytes; it lives at 0x9fc00, and the boot - // device tables are at 0x9ff00 -- 0x9ffff + // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot + // device tables are at EBDA_SEG:IPL_TABLE_OFFSET typedef struct { unsigned char ebda_size; unsigned char cmos_shutdown_status; @@ -765,7 +753,7 @@ upcall_t upcall; } ebda_data_t; - + #define EBDA_CMOS_SHUTDOWN_STATUS_OFFSET 1 #define EbdaData ((ebda_data_t *) 0) @@ -779,7 +767,7 @@ Bit32u lba1; Bit32u lba2; } int13ext_t; - + #define Int13Ext ((int13ext_t *) 0) // Disk Physical Table definition @@ -805,7 +793,7 @@ Bit8u reserved3; Bit8u checksum; } dpt_t; - + #define Int13DPT ((dpt_t *) 0) #endif // BX_USE_ATADRV @@ -835,9 +823,9 @@ } r16; struct { Bit32u filler[4]; - Bit8u bl, bh; + Bit8u bl, bh; Bit16u filler1; - Bit8u dl, dh; + Bit8u dl, dh; Bit16u filler2; Bit8u cl, ch; Bit16u filler3; @@ -870,6 +858,14 @@ Bit16u cs; flags_t flags; } iret_addr_t; + +typedef struct { + Bit16u type; + Bit16u flags; + Bit32u vector; + Bit32u description; + Bit32u reserved; + } ipl_entry_t; @@ -910,8 +906,6 @@ static void int70_function(); static void int74_function(); static Bit16u get_CS(); -//static Bit16u get_DS(); -//static void set_DS(); static Bit16u get_SS(); static unsigned int enqueue_key(); static unsigned int dequeue_key(); @@ -930,7 +924,10 @@ static void keyboard_panic(); static void shutdown_status_panic(); static void nmi_handler_msg(); - +static void delay_ticks(); +static void delay_ticks_and_check_for_keystroke(); + +static void interactive_bootkey(); static void print_bios_banner(); static void print_boot_device(); static void print_boot_failure(); @@ -964,33 +961,9 @@ #endif // BX_ELTORITO_BOOT -static char bios_cvs_version_string[] = "$Revision: 1.138 $"; -static char bios_date_string[] = "$Date: 2005/05/07 15:55:26 $"; - -static char CVSID[] = "$Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $"; - -/* Offset to skip the CVS $Id: prefix */ -#define bios_version_string (CVSID + 4) - -#define BIOS_PRINTF_HALT 1 -#define BIOS_PRINTF_SCREEN 2 -#define BIOS_PRINTF_INFO 4 -#define BIOS_PRINTF_DEBUG 8 -#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO) -#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT) - -#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p) - -// 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 -# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) -#else -# define BX_DEBUG(format, p...) -#endif -#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) -#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p) +static char bios_cvs_version_string[] = "$Revision: 1.221 $ $Date: 2008/12/07 17:32:29 $"; + +#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team." #if DEBUG_ATA # define BX_DEBUG_ATA(a...) BX_DEBUG(a) @@ -1163,9 +1136,9 @@ { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */ { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */ { 0x5300, 0x532e, none, none, 0x20 }, /* Del */ - { none, none, none, none, none }, /* ??? */ - { none, none, none, none, none }, /* ??? */ - { none, none, none, none, none }, /* ??? */ + { none, none, none, none, none }, + { none, none, none, none, none }, + { 0x565c, 0x567c, none, none, none }, /* \| */ { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */ { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */ }; @@ -1422,31 +1395,6 @@ ASM_END } -// Bit16u -//get_DS() -//{ -//ASM_START -// mov ax, ds -//ASM_END -//} -// -// void -//set_DS(ds_selector) -// Bit16u ds_selector; -//{ -//ASM_START -// push bp -// mov bp, sp -// -// push ax -// mov ax, 4[bp] ; ds_selector -// mov ds, ax -// pop ax -// -// pop bp -//ASM_END -//} - Bit16u get_SS() { @@ -1462,7 +1410,7 @@ Bit8u nr_entries = read_byte(0x9000, 0x1e8); Bit32u base_mem; if (nr_entries > 32) - nr_entries = 32; + nr_entries = 32; write_word(0xe000, 0x8, nr_entries); memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14); /* Report the proper base memory size at address 0x0413: otherwise @@ -1570,7 +1518,7 @@ pop bp ASM_END } - + void send(action, c) Bit16u action; @@ -1626,14 +1574,121 @@ send(action, val - (nval * 10) + '0'); } + void +put_luint(action, val, width, neg) + Bit16u action; + unsigned long val; + short width; + bx_bool neg; +{ + unsigned long nval = val / 10; + if (nval) + put_luint(action, nval, width - 1, neg); + else { + while (--width > 0) send(action, ' '); + if (neg) send(action, '-'); + } + send(action, val - (nval * 10) + '0'); +} + +void put_str(action, segment, offset) + Bit16u action; + Bit16u segment; + Bit16u offset; +{ + Bit8u c; + + while (c = read_byte(segment, offset)) { + send(action, c); + offset++; + } +} + + void +delay_ticks(ticks) + Bit16u ticks; +{ + long ticks_to_wait, delta; + Bit32u prev_ticks, t; + + /* + * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock. + * We also have to be careful about interrupt storms. + */ +ASM_START + pushf + sti +ASM_END + ticks_to_wait = ticks; + prev_ticks = read_dword(0x0, 0x46c); + do + { +ASM_START + hlt +ASM_END + t = read_dword(0x0, 0x46c); + if (t > prev_ticks) + { + delta = t - prev_ticks; /* The temp var is required or bcc screws up. */ + ticks_to_wait -= delta; + } + else if (t < prev_ticks) + { + ticks_to_wait -= t; /* wrapped */ + } + + prev_ticks = t; + } while (ticks_to_wait > 0); +ASM_START + cli + popf +ASM_END +} + + Bit8u +check_for_keystroke() +{ +ASM_START + mov ax, #0x100 + int #0x16 + jz no_key + mov al, #1 + jmp done +no_key: + xor al, al +done: +ASM_END +} + + Bit8u +get_keystroke() +{ +ASM_START + mov ax, #0x0 + int #0x16 + xchg ah, al +ASM_END +} + + void +delay_ticks_and_check_for_keystroke(ticks, count) + Bit16u ticks, count; +{ + Bit16u i; + for (i = 1; i <= count; i++) { + delay_ticks(ticks); + if (check_for_keystroke()) + break; + } +} + //-------------------------------------------------------------------------- // bios_printf() -// A compact variable argument printf function which prints its output via -// an I/O port so that it can be logged by Bochs/Plex. -// Currently, only %x is supported (or %02x, %04x, etc). -// -// Supports %[format_width][format] -// where format can be d,x,c,s +// A compact variable argument printf function. +// +// Supports %[format_width][length]format +// where format can be x,X,u,d,s,S,c +// and the optional length modifier is l (ell) //-------------------------------------------------------------------------- void bios_printf(action, s) @@ -1644,7 +1699,7 @@ bx_bool in_format; short i; Bit16u *arg_ptr; - Bit16u arg_seg, arg, nibble, shift_count, format_width; + Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd; arg_ptr = &s; arg_seg = get_SS(); @@ -1671,16 +1726,48 @@ else { arg_ptr++; // increment to next arg arg = read_word(arg_seg, arg_ptr); - if (c == 'x') { + if (c == 'x' || c == 'X') { if (format_width == 0) format_width = 4; + if (c == 'x') + hexadd = 'a'; + else + hexadd = 'A'; for (i=format_width-1; i>=0; i--) { nibble = (arg >> (4 * i)) & 0x000f; - send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A')); + send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd)); } } else if (c == 'u') { put_uint(action, arg, format_width, 0); + } + else if (c == 'l') { + s++; + c = read_byte(get_CS(), s); /* is it ld,lx,lu? */ + arg_ptr++; /* increment to next arg */ + hibyte = read_word(arg_seg, arg_ptr); + if (c == 'd') { + if (hibyte & 0x8000) + put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1); + else + put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0); + } + else if (c == 'u') { + put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0); + } + else if (c == 'x' || c == 'X') + { + if (format_width == 0) + format_width = 8; + if (c == 'x') + hexadd = 'a'; + else + hexadd = 'A'; + for (i=format_width-1; i>=0; i--) { + nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f; + send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd)); + } + } } else if (c == 'd') { if (arg & 0x8000) @@ -1689,7 +1776,13 @@ put_int(action, arg, format_width, 0); } else if (c == 's') { - bios_printf(action & (~BIOS_PRINTF_HALT), arg); + put_str(action, get_CS(), arg); + } + else if (c == 'S') { + hibyte = arg; + arg_ptr++; + arg = read_word(arg_seg, arg_ptr); + put_str(action, hibyte, arg); } else if (c == 'c') { send(action, arg); @@ -1706,7 +1799,7 @@ } if (action & BIOS_PRINTF_HALT) { - // freeze in a busy loop. + // freeze in a busy loop. ASM_START cli halt2_loop: @@ -1740,8 +1833,8 @@ max = 0x2000; } } - - // Due to timer issues, and if the IPS setting is > 15000000, + + // 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 @@ -1878,12 +1971,11 @@ keyboard_panic(status) Bit16u status; { - // If you're getting a 993 keyboard panic here, + // If you're getting a 993 keyboard panic here, // please see the comment in keyboard_init - + BX_PANIC("Keyboard error:%u\n",status); } - #define CMOS_SHUTDOWN_S3 0xFE //-------------------------------------------------------------------------- @@ -1939,6 +2031,11 @@ BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status); } +void s3_resume_panic() +{ + BX_PANIC("Returned from s3_resume.\n"); +} + //-------------------------------------------------------------------------- // print_bios_banner // displays a the bios version @@ -1946,74 +2043,84 @@ void print_bios_banner() { - printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":""); - printf("%s %s\n", bios_cvs_version_string, bios_date_string); + printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", + BIOS_BUILD_DATE, bios_cvs_version_string); + printf( +#if BX_APM + "apmbios " +#endif +#if BX_PCIBIOS + "pcibios " +#endif +#if BX_ELTORITO_BOOT + "eltorito " +#endif +#if BX_ROMBIOS32 + "rombios32 " +#endif #if BX_TCGBIOS - printf("TCG-enabled BIOS.\n"); -#endif - printf("\n"); -} - + "TCG-enabled" +#endif + "\n\n"); +} //-------------------------------------------------------------------------- // BIOS Boot Specification 1.0.1 compatibility // -// Very basic support for the BIOS Boot Specification, which allows expansion -// ROMs to register themselves as boot devices, instead of just stealing the +// Very basic support for the BIOS Boot Specification, which allows expansion +// ROMs to register themselves as boot devices, instead of just stealing the // INT 19h boot vector. -// +// // This is a hack: to do it properly requires a proper PnP BIOS and we aren't -// one; we just lie to the option ROMs to make them behave correctly. -// We also don't support letting option ROMs register as bootable disk -// drives (BCVs), only as bootable devices (BEVs). +// one; we just lie to the option ROMs to make them behave correctly. +// We also don't support letting option ROMs register as bootable disk +// drives (BCVs), only as bootable devices (BEVs). // // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm //-------------------------------------------------------------------------- -struct ipl_entry { - Bit16u type; - Bit16u flags; - Bit32u vector; - Bit32u description; - Bit32u reserved; -}; - -static void -init_boot_vectors() -{ - struct ipl_entry e; +static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"}; + +static void +init_boot_vectors() +{ + ipl_entry_t e; Bit16u count = 0; Bit16u ss = get_SS(); + Bit16u ebda_seg = read_word(0x0040, 0x000E); /* Clear out the IPL table. */ - memsetb(EBDA_SEG, IPL_TABLE_OFFSET, 0, 0xff); + memsetb(ebda_seg, IPL_TABLE_OFFSET, 0, IPL_SIZE); + + /* User selected device not set */ + write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF); /* Floppy drive */ - e.type = 1; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; - memcpyb(EBDA_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); + e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; + memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); count++; /* First HDD */ - e.type = 2; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; - memcpyb(EBDA_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); + e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; + memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); count++; #if BX_ELTORITO_BOOT /* CDROM */ - e.type = 3; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; - memcpyb(EBDA_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); + e.type = IPL_TYPE_CDROM; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; + memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); count++; -#endif +#endif /* Remember how many devices we have */ - write_word(EBDA_SEG, IPL_COUNT_OFFSET, count); + write_word(ebda_seg, IPL_COUNT_OFFSET, count); /* Not tried booting anything yet */ - write_word(EBDA_SEG, IPL_SEQUENCE_OFFSET, 0xffff); + write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xffff); } static Bit8u get_boot_vector(i, e) -Bit16u i; struct ipl_entry *e; +Bit16u i; ipl_entry_t *e; { Bit16u count; Bit16u ss = get_SS(); @@ -2026,22 +2133,107 @@ return 1; } +#if BX_ELTORITO_BOOT + void +interactive_bootkey() +{ + ipl_entry_t e; + Bit16u count; + char description[33]; + Bit8u scan_code; + Bit8u i; + Bit16u ss = get_SS(); + Bit16u valid_choice = 0; + Bit16u ebda_seg = read_word(0x0040, 0x000E); + + while (check_for_keystroke()) + get_keystroke(); + + printf("\nPress F12 for boot menu.\n\n"); + + delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */ + if (check_for_keystroke()) + { + scan_code = get_keystroke(); + if (scan_code == 0x86) /* F12 */ + { + while (check_for_keystroke()) + get_keystroke(); + + printf("Select boot device:\n\n"); + + count = read_word(ebda_seg, IPL_COUNT_OFFSET); + for (i = 0; i < count; i++) + { + memcpyb(ss, &e, ebda_seg, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e)); + printf("%d. ", i+1); + switch(e.type) + { + case IPL_TYPE_FLOPPY: + case IPL_TYPE_HARDDISK: + case IPL_TYPE_CDROM: + printf("%s\n", drivetypes[e.type]); + break; + case IPL_TYPE_BEV: + printf("%s", drivetypes[4]); + if (e.description != 0) + { + memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32); + description[32] = 0; + printf(" [%S]", ss, description); + } + printf("\n"); + break; + } + } + + count++; + while (!valid_choice) { + scan_code = get_keystroke(); + if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */ + { + valid_choice = 1; + } + else if (scan_code <= count) + { + valid_choice = 1; + scan_code -= 1; + /* Set user selected device */ + write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, scan_code); + } + } + printf("\n"); + } + } +} +#endif // BX_ELTORITO_BOOT //-------------------------------------------------------------------------- // print_boot_device // displays the boot device //-------------------------------------------------------------------------- -static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"}; - void -print_boot_device(type) +print_boot_device(e) + ipl_entry_t *e; +{ Bit16u type; -{ - /* NIC appears as type 0x80 */ - if (type == 0x80 ) type = 0x4; - if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n"); - printf("Booting from %s...\n", drivetypes[type]); + char description[33]; + Bit16u ss = get_SS(); + type = e->type; + /* NIC appears as type 0x80 */ + if (type == IPL_TYPE_BEV) type = 0x4; + if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n"); + printf("Booting from %s", drivetypes[type]); + /* print product string if BEV */ + if (type == 4 && e->description != 0) { + /* first 32 bytes are significant */ + memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32); + /* terminate string */ + description[32] = 0; + printf(" [%S]", ss, description); + } + printf("...\n"); } //-------------------------------------------------------------------------- @@ -2052,17 +2244,17 @@ print_boot_failure(type, reason) Bit16u type; Bit8u reason; { - if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n"); + if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n"); printf("Boot from %s failed", drivetypes[type]); if (type < 4) { /* Report the reason too */ - if (reason==0) - printf(": not a bootable disk"); - else - printf(": could not read the boot disk"); - } - printf("\n"); + if (reason==0) + printf(": not a bootable disk"); + else + printf(": could not read the boot disk"); + } + printf("\n\n"); } //-------------------------------------------------------------------------- @@ -2074,219 +2266,9 @@ Bit16u code; { bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code); - + return; } - -#define WAIT_HZ 18 -/** - * Check for keystroke. - * @returns True if keystroke available, False if not. - */ -Bit8u check_for_keystroke() -{ -ASM_START - mov ax, #0x100 - int #0x16 - jz no_key - mov al, #1 - jmp done -no_key: - xor al, al -done: -ASM_END -} - -/** - * Get keystroke. - * @returns BIOS scan code. - */ -Bit8u get_keystroke() -{ -ASM_START - mov ax, #0x0 - int #0x16 - xchg ah, al -ASM_END -} - -/** - * Waits (sleeps) for the given number of ticks. - * Checks for keystroke. - * - * @returns BIOS scan code if available, 0 if not. - * @param ticks Number of ticks to sleep. - * @param stop_on_key Whether to stop immediately upon keypress. - */ -Bit8u wait(ticks, stop_on_key) - Bit16u ticks; - Bit8u stop_on_key; -{ - long ticks_to_wait, delta; - Bit32u prev_ticks, t; - Bit8u scan_code = 0; - - /* - * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock. - * We also have to be careful about interrupt storms. - */ - ticks_to_wait = ticks; - prev_ticks = read_dword(0x0, 0x46c); - do - { - t = read_dword(0x0, 0x46c); - if (t > prev_ticks) - { - delta = t - prev_ticks; /* The temp var is required or bcc screws up. */ - ticks_to_wait -= delta; - } - else if (t < prev_ticks) - ticks_to_wait -= t; /* wrapped */ - prev_ticks = t; - - if (check_for_keystroke()) - { - scan_code = get_keystroke(); - bios_printf(BIOS_PRINTF_DEBUG, "Key pressed: %x\n", scan_code); - if (stop_on_key) - return scan_code; - } - } while (ticks_to_wait > 0); - return scan_code; -} - -static void clearscreen() { - /* Hide cursor, clear screen and move cursor to starting position */ -ASM_START - push bx - push cx - push dx - - mov ax, #0x100 - mov cx, #0x1000 - int #0x10 - - mov ax, #0x700 - mov bh, #7 - xor cx, cx - mov dx, #0x184f - int #0x10 - - mov ax, #0x200 - xor bx, bx - xor dx, dx - int #0x10 - - pop dx - pop cx - pop bx -ASM_END -} - -int bootmenu(selected) - int selected; -{ - Bit8u scode; - int max; - Bit16u ebda_seg = read_word(0x0040, 0x000E); - - /* get the number of boot devices */ - max = read_word(ebda_seg, IPL_COUNT_OFFSET); - - for(;;) { - if (selected > max || selected < 1) selected = 1; - clearscreen(); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n\n\n\n\n\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " Select boot device\n\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 1. Floppy\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 2. Hard drive\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 3. CD-ROM\n"); - if (max == 4) - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 4. Network\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n Currently selected: %d\n", selected); - - do { - scode = wait(WAIT_HZ, 1); - } while (scode == 0); - switch(scode) { - case 0x02: - case 0x03: - case 0x04: - selected = scode - 1; - break; - case 0x05: - if (max == 4) - selected = scode -1 ; - else - scode = 0; - break; - case 0x48: - selected -= 1; - if (selected < 1) - selected = 1; - scode = 0; - break; - case 0x50: - selected += 1; - if (selected > max) - selected = max; - scode = 0; - break; - case 0x1c: - break; - default: - scode = 0; - break; - } - if (scode != 0) - break; - } - - switch (selected) { - case 1: - return 0x3D; - case 2: - return 0x3E; - case 3: - return 0x3F; - case 4: - return 0x58; - default: - return 0; - } -} - -void interactive_bootkey() -{ - Bit16u i; - Bit8u scan = 0; - - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, - "\n\nPress F10 to select boot device.\n"); - - scan = wait(1, 0); - if (scan == 0x44) - scan = bootmenu(inb_cmos(0x3d) & 0x0f); - - /* set the default based on the keypress or menu */ - switch(scan) { - case 0x3D: - outb_cmos(0x3d, 0x01); - break; - case 0x3E: - outb_cmos(0x3d, 0x02); - break; - case 0x3F: - outb_cmos(0x3d, 0x03); - break; - case 0x58: - outb_cmos(0x3d, 0x04); - break; - default: - break; - } -} - void nmi_handler_msg() @@ -2306,7 +2288,7 @@ #if BX_DEBUG_SERIAL outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */ #endif - BX_INFO("%s\n", bios_version_string); + BX_INFO("%s\n", bios_cvs_version_string); } bx_bool @@ -2341,41 +2323,35 @@ outb(0xfedc, 0x00); } -void +int s3_resume() { Bit32u s3_wakeup_vector; - Bit16u s3_wakeup_ip, s3_wakeup_cs; - Bit8u cmos_shutdown_status; - -ASM_START - push ds - push ax - xor ax, ax - mov ds, ax - mov ax, word ptr [EBDA_SEG_PTR] - mov ds, ax - mov al, [EBDA_CMOS_SHUTDOWN_STATUS_OFFSET] - mov .s3_resume.cmos_shutdown_status[bp], al - pop ax - pop ds -ASM_END - - if (cmos_shutdown_status != CMOS_SHUTDOWN_S3) - return; - + Bit8u s3_resume_flag; + + s3_resume_flag = read_byte(0x40, 0xb0); +#ifdef HVMASSIST s3_wakeup_vector = get_s3_waking_vector(); - if (!s3_wakeup_vector) - return; - - s3_wakeup_ip = s3_wakeup_vector & 0xF; - s3_wakeup_cs = s3_wakeup_vector >> 4; - -ASM_START - push .s3_resume.s3_wakeup_cs[bp] - push .s3_resume.s3_wakeup_ip[bp] - retf -ASM_END +#else + s3_wakeup_vector = read_dword(0x40, 0xb2); +#endif + + BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag, s3_wakeup_vector); + if (s3_resume_flag != CMOS_SHUTDOWN_S3 || !s3_wakeup_vector) + return 0; + + write_byte(0x40, 0xb0, 0); + + /* setup wakeup vector */ + write_word(0x40, 0xb6, (s3_wakeup_vector & 0xF)); /* IP */ + write_word(0x40, 0xb8, (s3_wakeup_vector >> 4)); /* CS */ + + BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector >> 4), + (s3_wakeup_vector & 0xF)); +ASM_START + jmpf [0x04b6] +ASM_END + return 1; } #if BX_USE_ATADRV @@ -2425,6 +2401,7 @@ // bits 7-4 of the device/head (CB_DH) reg #define ATA_CB_DH_DEV0 0xa0 // select device 0 #define ATA_CB_DH_DEV1 0xb0 // select device 1 +#define ATA_CB_DH_LBA 0x40 // use LBA // status reg (CB_STAT and CB_ASTAT) bits #define ATA_CB_STAT_BSY 0x80 // busy @@ -2474,6 +2451,7 @@ #define ATA_CMD_READ_SECTORS 0x20 #define ATA_CMD_READ_VERIFY_SECTORS 0x40 #define ATA_CMD_RECALIBRATE 0x10 +#define ATA_CMD_REQUEST_SENSE 0x03 #define ATA_CMD_SEEK 0x70 #define ATA_CMD_SET_FEATURES 0xEF #define ATA_CMD_SET_MULTIPLE_MODE 0xC6 @@ -2518,7 +2496,7 @@ #define ATA_DATA_NO 0x00 #define ATA_DATA_IN 0x01 #define ATA_DATA_OUT 0x02 - + // --------------------------------------------------------------------------- // ATA/ATAPI driver : initialization // --------------------------------------------------------------------------- @@ -2527,7 +2505,7 @@ Bit16u ebda_seg=read_word(0x0040,0x000E); Bit8u channel, device; - // Channels info init. + // Channels info init. for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) { write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE); write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0); @@ -2535,7 +2513,7 @@ write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0); } - // Devices info init. + // Devices info init. for (device=0; device<BX_MAX_ATA_DEVICES; device++) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE); write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE); @@ -2550,11 +2528,12 @@ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0); - - write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L); - } - - // hdidmap and cdidmap init. + + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low,0L); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high,0L); + } + + // hdidmap and cdidmap init. for (device=0; device<BX_MAX_ATA_DEVICES; device++) { write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES); write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES); @@ -2562,6 +2541,58 @@ write_byte(ebda_seg,&EbdaData->ata.hdcount,0); write_byte(ebda_seg,&EbdaData->ata.cdcount,0); +} + +#define TIMEOUT 0 +#define BSY 1 +#define NOT_BSY 2 +#define NOT_BSY_DRQ 3 +#define NOT_BSY_NOT_DRQ 4 +#define NOT_BSY_RDY 5 + +#define IDE_TIMEOUT 32000u //32 seconds max for IDE ops + +int await_ide(); +static int await_ide(when_done,base,timeout) + Bit8u when_done; + Bit16u base; + Bit16u timeout; +{ + Bit32u time=0,last=0; + Bit16u status; + Bit8u result; + status = inb(base + ATA_CB_STAT); // for the times you're supposed to throw one away + for(;;) { + status = inb(base+ATA_CB_STAT); + time++; + if (when_done == BSY) + result = status & ATA_CB_STAT_BSY; + else if (when_done == NOT_BSY) + result = !(status & ATA_CB_STAT_BSY); + else if (when_done == NOT_BSY_DRQ) + result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ); + else if (when_done == NOT_BSY_NOT_DRQ) + result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ); + else if (when_done == NOT_BSY_RDY) + result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY); + else if (when_done == TIMEOUT) + result = 0; + + if (result) return 0; + if (time>>16 != last) // mod 2048 each 16 ms + { + last = time >>16; + BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout); + } + if (status & ATA_CB_STAT_ERR) + { + BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout); + return -1; + } + if ((timeout == 0) || ((time>>11) > timeout)) break; + } + BX_INFO("IDE time out\n"); + return -1; } // --------------------------------------------------------------------------- @@ -2604,7 +2635,7 @@ // Device detection hdcount=cdcount=0; - + for(device=0; device<BX_MAX_ATA_DEVICES; device++) { Bit16u iobase1, iobase2; Bit8u channel, slave, shift; @@ -2634,33 +2665,34 @@ if ( (sc == 0x55) && (sn == 0xaa) ) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN); - + // reset the channel - ata_reset (device); - + ata_reset(device); + // check for ATA or ATAPI outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0); sc = inb(iobase1+ATA_CB_SC); sn = inb(iobase1+ATA_CB_SN); - if ( (sc==0x01) && (sn==0x01) ) { + if ((sc==0x01) && (sn==0x01)) { cl = inb(iobase1+ATA_CB_CL); ch = inb(iobase1+ATA_CB_CH); st = inb(iobase1+ATA_CB_STAT); - if ( (cl==0x14) && (ch==0xeb) ) { + if ((cl==0x14) && (ch==0xeb)) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI); - } - else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) { + } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA); - } - } - } + } else if ((cl==0xff) && (ch==0xff)) { + write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE); + } + } + } type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type); - - // Now we send a IDENTIFY command to ATA device + + // Now we send a IDENTIFY command to ATA device if(type == ATA_TYPE_ATA) { - Bit32u sectors; + Bit32u sectors_low, sectors_high; Bit16u cylinders, heads, spt, blksize; Bit8u translation, removable, mode; @@ -2671,21 +2703,26 @@ write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD); write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16); - if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 ) + if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) !=0 ) BX_PANIC("ata-detect: Failed to detect ATA device\n"); removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; -#ifndef NO_PIO32 +#ifndef NO_PIO32 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; #endif - blksize = read_word(get_SS(),buffer+10); - + cylinders = read_word(get_SS(),buffer+(1*2)); // word 1 heads = read_word(get_SS(),buffer+(3*2)); // word 3 spt = read_word(get_SS(),buffer+(6*2)); // word 6 - sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61 + if (read_word(get_SS(),buffer+(83*2)) & (1 << 10)) { // word 83 - lba48 support + sectors_low = read_dword(get_SS(),buffer+(100*2)); // word 100 and word 101 + sectors_high = read_dword(get_SS(),buffer+(102*2)); // word 102 and word 103 + } else { + sectors_low = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61 + sectors_high = 0; + } write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD); write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable); @@ -2694,7 +2731,8 @@ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt); - write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors_low); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high, sectors_high); BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt); translation = inb_cmos(0x39 + channel/2); @@ -2722,14 +2760,14 @@ break; case ATA_TRANSLATION_LBA: spt = 63; - sectors /= 63; - heads = sectors / 1024; + sectors_low /= 63; + heads = sectors_low / 1024; if (heads>128) heads = 255; else if (heads>64) heads = 128; else if (heads>32) heads = 64; else if (heads>16) heads = 32; else heads=16; - cylinders = sectors / heads; + cylinders = sectors_low / heads; break; case ATA_TRANSLATION_RECHS: // Take care not to overflow @@ -2756,15 +2794,15 @@ write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads); write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders); write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt); - - // fill hdidmap + + // fill hdidmap write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device); hdcount++; } - + // Now we send a IDENTIFY command to ATAPI device if(type == ATA_TYPE_ATAPI) { - + Bit8u type, removable, mode; Bit16u blksize; @@ -2775,12 +2813,12 @@ write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM); write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16); - if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0) + if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) != 0) BX_PANIC("ata-detect: Failed to detect ATAPI device\n"); type = read_byte(get_SS(),buffer+1) & 0x1f; removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; -#ifndef NO_PIO32 +#ifndef NO_PIO32 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; #endif blksize = 2048; @@ -2790,24 +2828,24 @@ write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode); write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize); - // fill cdidmap + // fill cdidmap write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device); cdcount++; } - + { Bit32u sizeinmb; Bit16u ataversion; Bit8u c, i, version, model[41]; - + switch (type) { case ATA_TYPE_ATA: - sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors); - sizeinmb >>= 11; + sizeinmb = (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high) << 21) + | (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low) >> 11); case ATA_TYPE_ATAPI: // Read ATA/ATAPI version ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160); - for(version=15;version>0;version--) { + for(version=15;version>0;version--) { if((ataversion&(1<<version))!=0) break; } @@ -2816,7 +2854,7 @@ for(i=0;i<20;i++){ write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1)); write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54)); - } + } // Reformat write_byte(get_SS(),model+40,0x00); @@ -2824,7 +2862,13 @@ if(read_byte(get_SS(),model+i)==0x20) write_byte(get_SS(),model+i,0x00); else break; - } + } + if (i>36) { + write_byte(get_SS(),model+36,0x00); + for(i=35;i>32;i--){ + write_byte(get_SS(),model+i,0x2E); + } + } break; } @@ -2832,10 +2876,10 @@ case ATA_TYPE_ATA: printf("ata%d %s: ",channel,slave?" slave":"master"); i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c); - if (sizeinmb < 1UL<<16) - printf(" ATA-%d Hard-Disk (%04u MBytes)\n",version,(Bit16u)sizeinmb); - else - printf(" ATA-%d Hard-Disk (%04u GBytes)\n",version,(Bit16u)(sizeinmb>>10)); + if (sizeinmb < (1UL<<16)) + printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (Bit16u)sizeinmb); + else + printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (Bit16u)(sizeinmb>>10)); break; case ATA_TYPE_ATAPI: printf("ata%d %s: ",channel,slave?" slave":"master"); @@ -2856,17 +2900,17 @@ write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount); write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount); write_byte(0x40,0x75, hdcount); - + printf("\n"); // FIXME : should use bios=cmos|auto|disable bits // FIXME : should know about translation bits - // FIXME : move hard_drive_post here - -} - -// --------------------------------------------------------------------------- -// ATA/ATAPI driver : software reset + // FIXME : move hard_drive_post here + +} + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : software reset // --------------------------------------------------------------------------- // ATA-3 // 8.2.1 Software reset - Device 0 @@ -2876,7 +2920,8 @@ { Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u iobase1, iobase2; - Bit8u channel, slave, sn, sc; + Bit8u channel, slave, sn, sc; + Bit8u type; Bit16u max; channel = device / 2; @@ -2891,16 +2936,13 @@ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST); // 8.2.1 (b) -- wait for BSY - max=0xff; - while(--max>0) { - Bit8u status = inb(iobase1+ATA_CB_STAT); - if ((status & ATA_CB_STAT_BSY) != 0) break; - } + await_ide(BSY, iobase1, 20); // 8.2.1 (f) -- clear SRST outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); - if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) { + type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type); + if (type != ATA_TYPE_NONE) { // 8.2.1 (g) -- check for sc==sn==0x01 // select device @@ -2909,21 +2951,14 @@ sn = inb(iobase1+ATA_CB_SN); if ( (sc==0x01) && (sn==0x01) ) { + if (type == ATA_TYPE_ATA) //ATA + await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT); + else //ATAPI + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); + } // 8.2.1 (h) -- wait for not BSY - max=0xff; - while(--max>0) { - Bit8u status = inb(iobase1+ATA_CB_STAT); - if ((status & ATA_CB_STAT_BSY) == 0) break; - } - } - } - -// 8.2.1 (i) -- wait for DRDY - max=0xfff; - while(--max>0) { - Bit8u status = inb(iobase1+ATA_CB_STAT); - if ((status & ATA_CB_STAT_RDY) != 0) break; + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); } // Enable interrupts @@ -2931,7 +2966,7 @@ } // --------------------------------------------------------------------------- -// ATA/ATAPI driver : execute a non data command +// ATA/ATAPI driver : execute a non data command // --------------------------------------------------------------------------- Bit16u ata_cmd_non_data() @@ -2949,9 +2984,9 @@ // 5 : more sectors to read/verify // 6 : no sectors left to write // 7 : more sectors to write -Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset) +Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset) Bit16u device, command, count, cylinder, head, sector, segment, offset; -Bit32u lba; +Bit32u lba_low, lba_high; { Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u iobase1, iobase2, blksize; @@ -2980,22 +3015,20 @@ // sector will be 0 only on lba access. Convert to lba-chs if (sector == 0) { - if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) { + if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) { outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff); - outb(iobase1 + ATA_CB_SN, lba >> 24); - outb(iobase1 + ATA_CB_CL, 0); - outb(iobase1 + ATA_CB_CH, 0); + outb(iobase1 + ATA_CB_SN, lba_low >> 24); + outb(iobase1 + ATA_CB_CL, lba_high & 0xff); + outb(iobase1 + ATA_CB_CH, lba_high >> 8); command |= 0x04; count &= (1UL << 8) - 1; - lba &= (1UL << 24) - 1; - } - sector = (Bit16u) (lba & 0x000000ffL); - lba >>= 8; - cylinder = (Bit16u) (lba & 0x0000ffffL); - lba >>= 16; - head = ((Bit16u) (lba & 0x0000000fL)) | 0x40; - } + lba_low &= (1UL << 24) - 1; + } + sector = (Bit16u) (lba_low & 0x000000ffL); + cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL); + head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA; + } outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, count); @@ -3005,10 +3038,8 @@ outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head ); outb(iobase1 + ATA_CB_CMD, command); - while (1) { - status = inb(iobase1 + ATA_CB_STAT); - if ( !(status & ATA_CB_STAT_BSY) ) break; - } + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_data_in : read error\n"); @@ -3029,12 +3060,12 @@ ASM_START push bp mov bp, sp - mov di, _ata_cmd_data_in.offset + 2[bp] - mov ax, _ata_cmd_data_in.segment + 2[bp] - mov cx, _ata_cmd_data_in.blksize + 2[bp] + mov di, _ata_cmd_data_in.offset + 2[bp] + mov ax, _ata_cmd_data_in.segment + 2[bp] + mov cx, _ata_cmd_data_in.blksize + 2[bp] ;; adjust if there will be an overrun. 2K max sector size - cmp di, #0xf800 ;; + cmp di, #0xf800 ;; jbe ata_in_no_adjust ata_in_adjust: @@ -3046,7 +3077,7 @@ mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port - mov ah, _ata_cmd_data_in.mode + 2[bp] + mov ah, _ata_cmd_data_in.mode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_in_32 @@ -3068,9 +3099,10 @@ current++; write_word(ebda_seg, &EbdaData->ata.trsfsectors,current); count--; + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); status = inb(iobase1 + ATA_CB_STAT); if (count == 0) { - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != ATA_CB_STAT_RDY ) { BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status); return 4; @@ -3078,7 +3110,7 @@ break; } else { - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status); return 5; @@ -3103,9 +3135,9 @@ // 5 : more sectors to read/verify // 6 : no sectors left to write // 7 : more sectors to write -Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset) +Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset) Bit16u device, command, count, cylinder, head, sector, segment, offset; -Bit32u lba; +Bit32u lba_low, lba_high; { Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u iobase1, iobase2, blksize; @@ -3134,22 +3166,20 @@ // sector will be 0 only on lba access. Convert to lba-chs if (sector == 0) { - if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) { + if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) { outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff); - outb(iobase1 + ATA_CB_SN, lba >> 24); - outb(iobase1 + ATA_CB_CL, 0); - outb(iobase1 + ATA_CB_CH, 0); + outb(iobase1 + ATA_CB_SN, lba_low >> 24); + outb(iobase1 + ATA_CB_CL, lba_high & 0xff); + outb(iobase1 + ATA_CB_CH, lba_high >> 8); command |= 0x04; count &= (1UL << 8) - 1; - lba &= (1UL << 24) - 1; - } - sector = (Bit16u) (lba & 0x000000ffL); - lba >>= 8; - cylinder = (Bit16u) (lba & 0x0000ffffL); - lba >>= 16; - head = ((Bit16u) (lba & 0x0000000fL)) | 0x40; - } + lba_low &= (1UL << 24) - 1; + } + sector = (Bit16u) (lba_low & 0x000000ffL); + cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL); + head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA; + } outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, count); @@ -3159,10 +3189,8 @@ outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head ); outb(iobase1 + ATA_CB_CMD, command); - while (1) { - status = inb(iobase1 + ATA_CB_STAT); - if ( !(status & ATA_CB_STAT_BSY) ) break; - } + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_data_out : read error\n"); @@ -3183,12 +3211,12 @@ ASM_START push bp mov bp, sp - mov si, _ata_cmd_data_out.offset + 2[bp] - mov ax, _ata_cmd_data_out.segment + 2[bp] - mov cx, _ata_cmd_data_out.blksize + 2[bp] + mov si, _ata_cmd_data_out.offset + 2[bp] + mov ax, _ata_cmd_data_out.segment + 2[bp] + mov cx, _ata_cmd_data_out.blksize + 2[bp] ;; adjust if there will be an overrun. 2K max sector size - cmp si, #0xf800 ;; + cmp si, #0xf800 ;; jbe ata_out_no_adjust ata_out_adjust: @@ -3200,7 +3228,7 @@ mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port - mov ah, _ata_cmd_data_out.mode + 2[bp] + mov ah, _ata_cmd_data_out.mode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_out_32 @@ -3226,7 +3254,7 @@ count--; status = inb(iobase1 + ATA_CB_STAT); 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) ) + 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 ) { BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status); return 6; @@ -3234,7 +3262,7 @@ break; } else { - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status); return 7; @@ -3301,19 +3329,17 @@ if (status & ATA_CB_STAT_BSY) return 2; outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); - // outb(iobase1 + ATA_CB_FR, 0x00); - // outb(iobase1 + ATA_CB_SC, 0x00); - // outb(iobase1 + ATA_CB_SN, 0x00); + outb(iobase1 + ATA_CB_FR, 0x00); + outb(iobase1 + ATA_CB_SC, 0x00); + outb(iobase1 + ATA_CB_SN, 0x00); outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff); outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8); outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0); outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET); // Device should ok to receive command - while (1) { - status = inb(iobase1 + ATA_CB_STAT); - if ( !(status & ATA_CB_STAT_BSY) ) break; - } + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status); @@ -3330,13 +3356,13 @@ // Send command to device ASM_START sti ;; enable higher priority interrupts - + push bp mov bp, sp - - mov si, _ata_cmd_packet.cmdoff + 2[bp] - mov ax, _ata_cmd_packet.cmdseg + 2[bp] - mov cx, _ata_cmd_packet.cmdlen + 2[bp] + + mov si, _ata_cmd_packet.cmdoff + 2[bp] + mov ax, _ata_cmd_packet.cmdseg + 2[bp] + mov cx, _ata_cmd_packet.cmdlen + 2[bp] mov es, ax ;; segment in es mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port @@ -3349,32 +3375,38 @@ ASM_END if (inout == ATA_DATA_NO) { + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); status = inb(iobase1 + ATA_CB_STAT); } else { + Bit16u loops = 0; + Bit8u sc; while (1) { + if (loops == 0) {//first time through + status = inb(iobase2 + ATA_CB_ASTAT); + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + } + else + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); + loops++; + status = inb(iobase1 + ATA_CB_STAT); + sc = inb(iobase1 + ATA_CB_SC); // Check if command completed - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break; + if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) && + ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) break; if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status); return 3; } - // Device must be ready to send data - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) - != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { - BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status); - return 4; - } - // Normalize address bufseg += (bufoff / 16); bufoff %= 16; - + // Get the byte count lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL); @@ -3435,10 +3467,10 @@ mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port - mov cx, _ata_cmd_packet.lbefore + 2[bp] + mov cx, _ata_cmd_packet.lbefore + 2[bp] jcxz ata_packet_no_before - mov ah, _ata_cmd_packet.lmode + 2[bp] + mov ah, _ata_cmd_packet.lmode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_packet_in_before_32 @@ -3455,14 +3487,14 @@ pop eax ata_packet_no_before: - mov cx, _ata_cmd_packet.lcount + 2[bp] + mov cx, _ata_cmd_packet.lcount + 2[bp] jcxz ata_packet_after - mov di, _ata_cmd_packet.bufoff + 2[bp] - mov ax, _ata_cmd_packet.bufseg + 2[bp] + mov di, _ata_cmd_packet.bufoff + 2[bp] + mov ax, _ata_cmd_packet.bufseg + 2[bp] mov es, ax - mov ah, _ata_cmd_packet.lmode + 2[bp] + mov ah, _ata_cmd_packet.lmode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_packet_in_32 @@ -3476,10 +3508,10 @@ insd ;; CX dwords transfered to port(DX) to ES:[DI] ata_packet_after: - mov cx, _ata_cmd_packet.lafter + 2[bp] + mov cx, _ata_cmd_packet.lafter + 2[bp] jcxz ata_packet_done - mov ah, _ata_cmd_packet.lmode + 2[bp] + mov ah, _ata_cmd_packet.lmode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_packet_in_after_32 @@ -3509,7 +3541,7 @@ } // 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) ) + 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 ) { BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status); return 4; @@ -3528,55 +3560,108 @@ // Start of ATA/ATAPI generic functions // --------------------------------------------------------------------------- - Bit16u -atapi_get_sense(device) + Bit16u +atapi_get_sense(device, seg, asc, ascq) Bit16u device; { Bit8u atacmd[12]; - Bit8u buffer[16]; + Bit8u buffer[18]; Bit8u i; memsetb(get_SS(),atacmd,0,12); - // Request SENSE - atacmd[0]=0x03; - atacmd[4]=0x20; - if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0) + // Request SENSE + atacmd[0]=ATA_CMD_REQUEST_SENSE; + atacmd[4]=sizeof(buffer); + if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 18L, ATA_DATA_IN, get_SS(), buffer) != 0) return 0x0002; - if ((buffer[0] & 0x7e) == 0x70) { - return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12]; - } + write_byte(seg,asc,buffer[12]); + write_byte(seg,ascq,buffer[13]); return 0; } - Bit16u + Bit16u atapi_is_ready(device) Bit16u device; { - Bit8u atacmd[12]; - Bit8u buffer[]; - - memsetb(get_SS(),atacmd,0,12); - - // Test Unit Ready - if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) - return 0x000f; - - if (atapi_get_sense(device) !=0 ) { - memsetb(get_SS(),atacmd,0,12); - - // try to send Test Unit Ready again - if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) - return 0x000f; - - return atapi_get_sense(device); - } + Bit8u packet[12]; + Bit8u buf[8]; + Bit32u block_len; + Bit32u sectors; + Bit32u timeout; //measured in ms + Bit32u time; + Bit8u asc, ascq; + Bit8u in_progress; + Bit16u ebda_seg = read_word(0x0040,0x000E); + if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) { + printf("not implemented for non-ATAPI device\n"); + return -1; + } + + BX_DEBUG_ATA("ata_detect_medium: begin\n"); + memsetb(get_SS(),packet, 0, sizeof packet); + packet[0] = 0x25; /* READ CAPACITY */ + + /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT + * is reported by the device. If the device reports "IN PROGRESS", + * 30 seconds is added. */ + timeout = 5000; + time = 0; + in_progress = 0; + while (time < timeout) { + if (ata_cmd_packet(device, sizeof(packet), get_SS(), packet, 0, 8L, ATA_DATA_IN, get_SS(), buf) == 0) + goto ok; + + if (atapi_get_sense(device, get_SS(), &asc, &ascq) == 0) { + if (asc == 0x3a) { /* MEDIUM NOT PRESENT */ + BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n"); + return -1; + } + + if (asc == 0x04 && ascq == 0x01 && !in_progress) { + /* IN PROGRESS OF BECOMING READY */ + printf("Waiting for device to detect medium... "); + /* Allow 30 seconds more */ + timeout = 30000; + in_progress = 1; + } + } + time += 100; + } + BX_DEBUG_ATA("read capacity failed\n"); + return -1; +ok: + + block_len = (Bit32u) buf[4] << 24 + | (Bit32u) buf[5] << 16 + | (Bit32u) buf[6] << 8 + | (Bit32u) buf[7] << 0; + BX_DEBUG_ATA("block_len=%u\n", block_len); + + if (block_len!= 2048 && block_len!= 512) + { + printf("Unsupported sector size %u\n", block_len); + return -1; + } + write_dword(ebda_seg,&EbdaData->ata.devices[device].blksize, block_len); + + sectors = (Bit32u) buf[0] << 24 + | (Bit32u) buf[1] << 16 + | (Bit32u) buf[2] << 8 + | (Bit32u) buf[3] << 0; + + BX_DEBUG_ATA("sectors=%u\n", sectors); + if (block_len == 2048) + sectors <<= 2; /* # of sectors in 512-byte "soft" sector */ + if (sectors != read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low)) + printf("%dMB medium detected\n", sectors>>(20-9)); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors); return 0; } - Bit16u + Bit16u atapi_is_cdrom(device) Bit8u device; { @@ -3636,7 +3721,7 @@ // // Returns ah: emulated drive, al: error code // - Bit16u + Bit16u cdrom_boot() { Bit16u ebda_seg=read_word(0x0040,0x000E); @@ -3649,9 +3734,12 @@ for (device=0; device<BX_MAX_ATA_DEVICES;device++) { if (atapi_is_cdrom(device)) break; } - + // if not found if(device >= BX_MAX_ATA_DEVICES) return 2; + + if(error = atapi_is_ready(device) != 0) + BX_INFO("ata_is_ready returned %d\n",error); // Read the Boot Record Volume Descriptor memsetb(get_SS(),atacmd,0,12); @@ -3672,7 +3760,7 @@ } for(i=0;i<23;i++) if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6; - + // ok, now we calculate the Boot catalog address lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47]; @@ -3687,7 +3775,7 @@ atacmd[5]=(lba & 0x000000ff); 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[0x00]!=0x01)return 8; // Header if(buffer[0x01]!=0x00)return 9; // Platform @@ -3706,10 +3794,10 @@ write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]); if(buffer[0x21]==0){ - // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0. + // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0. // Win2000 cd boot needs to know it booted from cd write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0); - } + } else if(buffer[0x21]<4) write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00); else @@ -3723,7 +3811,7 @@ write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment); write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000); - + nbsectors=buffer[0x27]*0x100+buffer[0x26]; write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors); @@ -3748,7 +3836,6 @@ tcpa_ipl((Bit32u)1L,(Bit32u)boot_segment,(Bit32u)0L,(Bit32u)512L); #endif - // Remember the media type switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) { case 0x01: // 1.2M floppy @@ -3769,7 +3856,7 @@ case 0x04: // Harddrive write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f); write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders, - (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1); + (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1); write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1); break; } @@ -3782,7 +3869,7 @@ write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1); } - + // everything is ok, so from now on, the emulation is active if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) write_byte(ebda_seg,&EbdaData->cdemu.active,0x01); @@ -4128,9 +4215,10 @@ regs.u.r8.al = inb_cmos(0x30); regs.u.r8.ah = inb_cmos(0x31); - // limit to 15M - if(regs.u.r16.ax > 0x3c00) - regs.u.r16.ax = 0x3c00; + // According to Ralf Brown's interrupt the limit should be 15M, + // but real machines mostly return max. 63M. + if(regs.u.r16.ax > 0xffc0) + regs.u.r16.ax = 0xffc0; CLEAR_CF(); #endif @@ -4348,13 +4436,35 @@ case 3: // Set Resolution BX_DEBUG_INT15("case 3:\n"); - // BX: + // BH: // 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 - CLEAR_CF(); - regs.u.r8.ah = 0; + comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets + if (regs.u.r8.bh < 4) { + ret = send_to_mouse_ctrl(0xE8); // set resolution command + if (ret == 0) { + ret = get_mouse_data(&mouse_data1); + if (mouse_data1 != 0xfa) + BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1); + ret = send_to_mouse_ctrl(regs.u.r8.bh); + ret = get_mouse_data(&mouse_data1); + if (mouse_data1 != 0xfa) + BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1); + CLEAR_CF(); + regs.u.r8.ah = 0; + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable break; case 4: // Get Device ID @@ -4476,7 +4586,30 @@ break; } } -#endif +#endif // BX_USE_PS2_MOUSE + + +void set_e820_range(ES, DI, start, end, type) + Bit16u ES; + Bit16u DI; + Bit32u start; + Bit32u end; + Bit16u type; +{ + write_word(ES, DI, start); + write_word(ES, DI+2, start >> 16); + write_word(ES, DI+4, 0x00); + write_word(ES, DI+6, 0x00); + + end -= start; + write_word(ES, DI+8, end); + write_word(ES, DI+10, end >> 16); + write_word(ES, DI+12, 0x0000); + write_word(ES, DI+14, 0x0000); + + write_word(ES, DI+16, type); + write_word(ES, DI+18, 0x0); +} void int15_function32(regs, ES, DS, FLAGS) @@ -4490,17 +4623,20 @@ switch (regs.u.r8.ah) { case 0x86: - // Wait for CX:DX microseconds. currently using the - // refresh request port 0x61 bit4, toggling every 15usec + // Wait for CX:DX microseconds. currently using the + // refresh request port 0x61 bit4, toggling every 15usec CX = regs.u.r16.cx; DX = regs.u.r16.dx; ASM_START + sti + ;; Get the count in eax - mov ax, .int15_function32.CX [bp] + mov bx, sp + mov ax, _int15_function32.CX [bx] shl eax, #16 - mov ax, .int15_function32.DX [bp] + mov ax, _int15_function32.DX [bx] ;; convert to numbers of 15usec ticks mov ebx, #15 @@ -4531,7 +4667,8 @@ case 0xe8: switch(regs.u.r8.al) { - case 0x20: { +#ifdef HVMASSIST + case 0x20: { Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14; if (regs.u.r32.edx != 0x534D4150) /* SMAP */ @@ -4579,7 +4716,7 @@ // Get the amount of extended memory (above 1M) regs.u.r8.cl = inb_cmos(0x30); regs.u.r8.ch = inb_cmos(0x31); - + // limit to 15M if (regs.u.r16.cx > (15*1024)) regs.u.r16.cx = 15*1024; @@ -4607,7 +4744,7 @@ regs.u.r16.bx = regs.u.r16.dx; break; } - default: /* AH=0xE8?? but not implemented */ + default: /* AH=0xE8?? but not implemented */ goto int15_unimplemented; } break; @@ -4620,16 +4757,178 @@ regs.u.r8.ah = UNSUPPORTED_FUNCTION; break; } +#else + case 0x20: // coded by osmaker aka K.J. + if(regs.u.r32.edx == 0x534D4150) + { + extended_memory_size = inb_cmos(0x35); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x34); + 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 += (16L * 1024 * 1024); + + if(extended_memory_size <= (16L * 1024 * 1024)) { + extended_memory_size = inb_cmos(0x31); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x30); + extended_memory_size *= 1024; + extended_memory_size += (1L * 1024 * 1024); + } + + switch(regs.u.r16.bx) + { + case 0: + set_e820_range(ES, regs.u.r16.di, + 0x0000000L, 0x0009f000L, 1); + regs.u.r32.ebx = 1; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 1: + set_e820_range(ES, regs.u.r16.di, + 0x0009f000L, 0x000a0000L, 2); + regs.u.r32.ebx = 2; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 2: + set_e820_range(ES, regs.u.r16.di, + 0x000e8000L, 0x00100000L, 2); + regs.u.r32.ebx = 3; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 3: +#if BX_ROMBIOS32 + set_e820_range(ES, regs.u.r16.di, + 0x00100000L, + extended_memory_size - ACPI_DATA_SIZE, 1); + regs.u.r32.ebx = 4; +#else + set_e820_range(ES, regs.u.r16.di, + 0x00100000L, + extended_memory_size, 1); + regs.u.r32.ebx = 5; +#endif + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 4: + set_e820_range(ES, regs.u.r16.di, + extended_memory_size - ACPI_DATA_SIZE, + extended_memory_size, 3); // ACPI RAM + regs.u.r32.ebx = 5; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 5: + /* 256KB BIOS area at the end of 4 GB */ + set_e820_range(ES, regs.u.r16.di, + 0xfffc0000L, 0x00000000L, 2); + regs.u.r32.ebx = 0; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + 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) + regs.u.r8.cl = inb_cmos(0x30); + regs.u.r8.ch = inb_cmos(0x31); + + // limit to 15M + if(regs.u.r16.cx > 0x3c00) + { + regs.u.r16.cx = 0x3c00; + } + + // Get the amount of extended memory above 16M in 64k blocs + regs.u.r8.dl = inb_cmos(0x34); + regs.u.r8.dh = inb_cmos(0x35); + + // Set configured memory equal to extended memory + regs.u.r16.ax = regs.u.r16.cx; + regs.u.r16.bx = regs.u.r16.dx; + break; + default: /* AH=0xE8?? but not implemented */ + goto int15_unimplemented; + } + break; + int15_unimplemented: + // fall into the default + default: + BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n", + (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + } +#endif /* HVMASSIST */ } void int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS) Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS; { - Bit8u scan_code, ascii_code, shift_flags, count; + Bit8u scan_code, ascii_code, shift_flags, led_flags, count; Bit16u kbd_code, max; BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX); + + shift_flags = read_byte(0x0040, 0x17); + led_flags = read_byte(0x0040, 0x97); + if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) { +ASM_START + cli +ASM_END + outb(0x60, 0xed); + while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21); + if ((inb(0x60) == 0xfa)) { + led_flags &= 0xf8; + led_flags |= ((shift_flags >> 4) & 0x07); + outb(0x60, led_flags & 0x07); + while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21); + inb(0x60); + write_byte(0x0040, 0x97, led_flags); + } +ASM_START + sti +ASM_END + } switch (GET_AH()) { case 0x00: /* read keyboard input */ @@ -4668,7 +4967,7 @@ break; case 0x09: /* GET KEYBOARD FUNCTIONALITY */ - // bit Bochs Description + // 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) @@ -4698,7 +4997,7 @@ kbd_code |= (inb(0x60) << 8); } } while (--count>0); - } + } } BX=kbd_code; break; @@ -4725,7 +5024,8 @@ case 0x12: /* get extended keyboard status */ shift_flags = read_byte(0x0040, 0x17); SET_AL(shift_flags); - shift_flags = read_byte(0x0040, 0x18); + shift_flags = read_byte(0x0040, 0x18) & 0x73; + shift_flags |= read_byte(0x0040, 0x96) & 0x0c; SET_AH(shift_flags); BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX); break; @@ -4740,7 +5040,7 @@ case 0x6F: if (GET_AL() == 0x08) - SET_AH(0x02); // unsupported, aka normal keyboard + SET_AH(0x02); // unsupported, aka normal keyboard default: BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH()); @@ -4881,7 +5181,7 @@ Bit16u DI, SI, BP, SP, BX, DX, CX, AX; { Bit8u scancode, asciicode, shift_flags; - Bit8u mf2_flags, mf2_state, led_flags; + Bit8u mf2_flags, mf2_state; // // DS has been set to F000 before call @@ -4899,7 +5199,6 @@ shift_flags = read_byte(0x0040, 0x17); mf2_flags = read_byte(0x0040, 0x18); mf2_state = read_byte(0x0040, 0x96); - led_flags = read_byte(0x0040, 0x97); asciicode = 0; switch (scancode) { @@ -4908,8 +5207,6 @@ write_byte(0x0040, 0x17, shift_flags); mf2_flags |= 0x40; write_byte(0x0040, 0x18, mf2_flags); - led_flags ^= 0x04; - write_byte(0x0040, 0x97, led_flags); break; case 0xba: /* Caps Lock release */ mf2_flags &= ~0x40; @@ -4917,11 +5214,8 @@ break; case 0x2a: /* L Shift press */ - /*shift_flags &= ~0x40;*/ shift_flags |= 0x02; write_byte(0x0040, 0x17, shift_flags); - led_flags &= ~0x04; - write_byte(0x0040, 0x97, led_flags); break; case 0xaa: /* L Shift release */ shift_flags &= ~0x02; @@ -4929,11 +5223,8 @@ break; case 0x36: /* R Shift press */ - /*shift_flags &= ~0x40;*/ shift_flags |= 0x01; write_byte(0x0040, 0x17, shift_flags); - led_flags &= ~0x04; - write_byte(0x0040, 0x97, led_flags); break; case 0xb6: /* R Shift release */ shift_flags &= ~0x01; @@ -4941,71 +5232,75 @@ break; case 0x1d: /* Ctrl press */ - shift_flags |= 0x04; - write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags |= 0x04; - } else { - mf2_flags |= 0x01; - } - write_byte(0x0040, 0x18, mf2_flags); + if ((mf2_state & 0x01) == 0) { + shift_flags |= 0x04; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x02) { + mf2_state |= 0x04; + write_byte(0x0040, 0x96, mf2_state); + } else { + mf2_flags |= 0x01; + write_byte(0x0040, 0x18, mf2_flags); + } + } break; case 0x9d: /* Ctrl release */ - shift_flags &= ~0x04; - write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags &= ~0x04; - } else { - mf2_flags &= ~0x01; - } - write_byte(0x0040, 0x18, mf2_flags); + if ((mf2_state & 0x01) == 0) { + shift_flags &= ~0x04; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x02) { + mf2_state &= ~0x04; + write_byte(0x0040, 0x96, mf2_state); + } else { + mf2_flags &= ~0x01; + write_byte(0x0040, 0x18, mf2_flags); + } + } break; case 0x38: /* Alt press */ shift_flags |= 0x08; write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags |= 0x08; + if (mf2_state & 0x02) { + mf2_state |= 0x08; + write_byte(0x0040, 0x96, mf2_state); } else { mf2_flags |= 0x02; - } - write_byte(0x0040, 0x18, mf2_flags); + write_byte(0x0040, 0x18, mf2_flags); + } break; case 0xb8: /* Alt release */ shift_flags &= ~0x08; write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags &= ~0x08; + if (mf2_state & 0x02) { + mf2_state &= ~0x08; + write_byte(0x0040, 0x96, mf2_state); } else { mf2_flags &= ~0x02; - } - write_byte(0x0040, 0x18, mf2_flags); + write_byte(0x0040, 0x18, mf2_flags); + } break; case 0x45: /* Num Lock press */ - if ((mf2_state & 0x01) == 0) { + if ((mf2_state & 0x03) == 0) { mf2_flags |= 0x20; write_byte(0x0040, 0x18, mf2_flags); shift_flags ^= 0x20; - led_flags ^= 0x02; write_byte(0x0040, 0x17, shift_flags); - write_byte(0x0040, 0x97, led_flags); - } + } break; case 0xc5: /* Num Lock release */ - if ((mf2_state & 0x01) == 0) { + if ((mf2_state & 0x03) == 0) { mf2_flags &= ~0x20; write_byte(0x0040, 0x18, mf2_flags); - } + } break; case 0x46: /* Scroll Lock press */ mf2_flags |= 0x10; write_byte(0x0040, 0x18, mf2_flags); shift_flags ^= 0x10; - led_flags ^= 0x01; write_byte(0x0040, 0x17, shift_flags); - write_byte(0x0040, 0x97, led_flags); break; case 0xc6: /* Scroll Lock release */ @@ -5018,50 +5313,55 @@ machine_reset(); /* Fall through */ default: - if (scancode & 0x80) return; /* toss key releases ... */ + if (scancode & 0x80) { + break; /* toss key releases ... */ + } if (scancode > MAX_SCAN_CODE) { - BX_INFO("KBD: int09h_handler(): unknown scancode (%x) read!\n", scancode); - return; - } + BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode); + return; + } if (shift_flags & 0x08) { /* ALT */ asciicode = scan_to_scanascii[scancode].alt; scancode = scan_to_scanascii[scancode].alt >> 8; - } - else if (shift_flags & 0x04) { /* CONTROL */ + } else if (shift_flags & 0x04) { /* CONTROL */ asciicode = scan_to_scanascii[scancode].control; scancode = scan_to_scanascii[scancode].control >> 8; - } - else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */ - /* check if lock state should be ignored + } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) { + /* extended keys handling */ + asciicode = 0xe0; + scancode = scan_to_scanascii[scancode].normal >> 8; + } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */ + /* check if lock state should be ignored * because a SHIFT key are pressed */ - + if (shift_flags & scan_to_scanascii[scancode].lock_flags) { asciicode = scan_to_scanascii[scancode].normal; scancode = scan_to_scanascii[scancode].normal >> 8; - } - else { + } else { asciicode = scan_to_scanascii[scancode].shift; scancode = scan_to_scanascii[scancode].shift >> 8; - } - } - else { + } + } else { /* check if lock is on */ if (shift_flags & scan_to_scanascii[scancode].lock_flags) { asciicode = scan_to_scanascii[scancode].shift; scancode = scan_to_scanascii[scancode].shift >> 8; - } - else { + } else { asciicode = scan_to_scanascii[scancode].normal; scancode = scan_to_scanascii[scancode].normal >> 8; - } - } + } + } if (scancode==0 && asciicode==0) { BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n"); - } + } enqueue_key(scancode, asciicode); break; - } - mf2_state &= ~0x01; + } + if ((scancode & 0x7f) != 0x1d) { + mf2_state &= ~0x01; + } + mf2_state &= ~0x02; + write_byte(0x0040, 0x96, mf2_state); } unsigned int @@ -5069,9 +5369,6 @@ Bit8u scan_code, ascii_code; { Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail; - - //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n", - // scan_code, ascii_code); #if BX_CPU < 2 buffer_start = 0x001E; @@ -5122,9 +5419,8 @@ mouse_flags_2 = read_byte(ebda_seg, 0x0027); if ( (mouse_flags_2 & 0x80) != 0x80 ) { - // BX_PANIC("int74_function:\n"); - return; - } + return; + } package_count = mouse_flags_2 & 0x07; index = mouse_flags_1 & 0x07; @@ -5152,10 +5448,10 @@ #if BX_USE_ATADRV void -int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) - Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; -{ - Bit32u lba; +int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit32u lba_low, lba_high; Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u cylinder, head, sector; Bit16u segment, offset; @@ -5176,12 +5472,12 @@ // Get the ata channel device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]); - // basic check : device has to be valid + // basic check : device has to be valid if (device >= BX_MAX_ATA_DEVICES) { BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL()); goto int13_fail; } - + switch (GET_AH()) { case 0x00: /* disk controller reset */ @@ -5199,7 +5495,7 @@ break; case 0x02: // read disk sectors - case 0x03: // write disk sectors + case 0x03: // write disk sectors case 0x04: // verify disk sectors count = GET_AL(); @@ -5211,10 +5507,10 @@ segment = ES; offset = BX; - if ( (count > 128) || (count == 0) ) { - BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH()); + if ((count > 128) || (count == 0) || (sector == 0)) { + BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH()); goto int13_fail; - } + } nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); @@ -5225,7 +5521,7 @@ 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 ( GET_AH() == 0x04 ) goto int13_success; @@ -5234,14 +5530,15 @@ // if needed, translate lchs to lba, and execute command if ( (nph != nlh) || (npspt != nlspt)) { - lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1; + lba_low = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1; + lba_high = 0; 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); + status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset); else - status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset); + status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset); // Set nb of sector transferred SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors)); @@ -5262,7 +5559,7 @@ break; case 0x08: /* read disk drive parameters */ - + // Get logical geometry from table nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); @@ -5277,13 +5574,13 @@ SET_DL(count); /* FIXME returns 0, 1, or n hard drives */ // 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 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT); if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) { @@ -5297,15 +5594,15 @@ case 0x15: /* read disk drive size */ - // Get physical geometry from table - npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders); - nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads); - npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt); + // Get logical geometry from table + nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); + nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); + nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt); // Compute sector count seen by int13 - lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt; - CX = lba >> 16; - DX = lba & 0xffff; + lba_low = (Bit32u)(nlc - 1) * (Bit32u)nlh * (Bit32u)nlspt; + CX = lba_low >> 16; + DX = lba_low & 0xffff; SET_AH(3); // hard disk accessible goto int13_success_noah; @@ -5326,17 +5623,18 @@ count=read_word(DS, SI+(Bit16u)&Int13Ext->count); segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment); offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset); - - // Can't use 64 bits lba - lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); - if (lba != 0L) { - BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH()); + + // Get 32 msb lba and check + lba_high=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); + if (lba_high > read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) ) { + BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH()); goto int13_fail; } - // Get 32 bits lba and check - lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); - if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) { + // Get 32 lsb lba and check + lba_low=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); + if (lba_high == read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) + && lba_low >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low) ) { BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH()); goto int13_fail; } @@ -5344,12 +5642,12 @@ // If verify or seek if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 )) goto int13_success; - + // Execute the command if ( GET_AH() == 0x42 ) - status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset); + status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset); else - status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset); + status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset); count=read_word(ebda_seg, &EbdaData->ata.trsfsectors); write_word(DS, SI+(Bit16u)&Int13Ext->count, count); @@ -5367,7 +5665,7 @@ case 0x49: // IBM/MS extended media change goto int13_success; // Always success for HD break; - + case 0x46: // IBM/MS eject media SET_AH(0xb2); // Volume Not Removable goto int13_fail_noah; // Always fail for HD @@ -5377,7 +5675,7 @@ size=read_word(DS,SI+(Bit16u)&Int13DPT->size); // Buffer is too small - if(size < 0x1a) + if(size < 0x1a) goto int13_fail; // EDD 1.x @@ -5387,17 +5685,26 @@ npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders); nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads); npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt); - lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors); + lba_low = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low); + lba_high = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high); blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a); - write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid - write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc); + if (lba_high || (lba_low/npspt)/nph > 0x3fff) + { + write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x00); // geometry is invalid + write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0x3fff); + } + else + { + write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid + write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc); + } write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph); write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt); - write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64 - write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L); - write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba_low); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, lba_high); + write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); } // EDD 2.x @@ -5407,8 +5714,8 @@ write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e); - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); // Fill in dpte channel = device / 2; @@ -5418,14 +5725,365 @@ mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation); - options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation + options = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation options |= (1<<4); // lba translation + options |= (mode==ATA_MODE_PIO32?1:0)<<7; + options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9; + options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9; + + write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1); + write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC); + write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb ); + write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq ); + write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 ); + write_word(ebda_seg, &EbdaData->ata.dpte.options, options); + write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0); + if (size >=0x42) + write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); + else + write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x10); + + checksum=0; + for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i); + checksum = ~checksum; + write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum); + } + + // EDD 3.x + if(size >= 0x42) { + Bit8u channel, iface, checksum, i; + Bit16u iobase1; + + channel = device / 2; + iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface); + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42); + write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd); + write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24); + write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0); + write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0); + + if (iface==ATA_IFACE_ISA) { + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0); + } + else { + // FIXME PCI + } + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0); + + if (iface==ATA_IFACE_ISA) { + write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1); + write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0); + write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L); + } + else { + // FIXME PCI + } + write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2); + write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0); + write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0); + write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L); + + checksum=0; + for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i); + checksum = ~checksum; + write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum); + } + + goto int13_success; + break; + + case 0x4e: // // IBM/MS set hardware configuration + // 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 */ + BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH()); + 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 + case 0x50: // IBM/MS send packet command + default: + BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH()); + goto int13_fail; + break; + } + +int13_fail: + SET_AH(0x01); // defaults to invalid function in AH or invalid parameter +int13_fail_noah: + SET_DISK_RET_STATUS(GET_AH()); +int13_fail_nostatus: + SET_CF(); // error occurred + return; + +int13_success: + SET_AH(0x00); // no error +int13_success_noah: + SET_DISK_RET_STATUS(0x00); + CLEAR_CF(); // no error + return; +} + +// --------------------------------------------------------------------------- +// Start of int13 for cdrom +// --------------------------------------------------------------------------- + + void +int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u device, status, locks; + Bit8u atacmd[12]; + Bit32u lba; + Bit16u count, segment, offset, i, size; + + BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); + + SET_DISK_RET_STATUS(0x00); + + /* basic check : device should be 0xE0+ */ + if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) { + BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL()); + goto int13_fail; + } + + // Get the ata channel + device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]); + + /* basic check : device has to be valid */ + if (device >= BX_MAX_ATA_DEVICES) { + BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL()); + 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 */ + case 0x43: // IBM/MS extended write + SET_AH(0x03); + goto int13_fail_noah; + break; + + case 0x01: /* read disk status */ + status = read_byte(0x0040, 0x0074); + SET_AH(status); + SET_DISK_RET_STATUS(0); + + /* 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; + + case 0x41: // IBM/MS installation check + BX=0xaa55; // install check + SET_AH(0x30); // EDD 2.1 + CX=0x0007; // ext disk access, removable and edd + goto int13_success_noah; + break; + + case 0x42: // IBM/MS extended read + case 0x44: // IBM/MS verify sectors + case 0x47: // IBM/MS extended seek + + count=read_word(DS, SI+(Bit16u)&Int13Ext->count); + segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment); + offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset); + + // Can't use 64 bits lba + lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); + if (lba != 0L) { + BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH()); + goto int13_fail; + } + + // Get 32 bits lba + lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); + + // If verify or seek + if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 )) + goto int13_success; + + memsetb(get_SS(),atacmd,0,12); + atacmd[0]=0x28; // READ command + atacmd[7]=(count & 0xff00) >> 8; // Sectors + atacmd[8]=(count & 0x00ff); // Sectors + atacmd[2]=(lba & 0xff000000) >> 24; // LBA + atacmd[3]=(lba & 0x00ff0000) >> 16; + atacmd[4]=(lba & 0x0000ff00) >> 8; + atacmd[5]=(lba & 0x000000ff); + status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset); + + count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11); + write_word(DS, SI+(Bit16u)&Int13Ext->count, count); + + if (status != 0) { + BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status); + SET_AH(0x0c); + goto int13_fail_noah; + } + + goto int13_success; + break; + + case 0x45: // IBM/MS lock/unlock drive + if (GET_AL() > 2) goto int13_fail; + + locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock); + + switch (GET_AL()) { + case 0 : // lock + if (locks == 0xff) { + SET_AH(0xb4); + SET_AL(1); + goto int13_fail_noah; + } + write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks); + SET_AL(1); + break; + case 1 : // unlock + if (locks == 0x00) { + SET_AH(0xb0); + SET_AL(0); + goto int13_fail_noah; + } + write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks); + SET_AL(locks==0?0:1); + break; + case 2 : // status + SET_AL(locks==0?0:1); + break; + } + goto int13_success; + break; + + case 0x46: // IBM/MS eject media + locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock); + + if (locks != 0) { + SET_AH(0xb1); // media locked + goto int13_fail_noah; + } + // FIXME should handle 0x31 no media in device + // FIXME should handle 0xb5 valid request failed + + // Call removable media eject + ASM_START + push bp + mov bp, sp + + mov ah, #0x52 + int #0x15 + mov _int13_cdrom.status + 2[bp], ah + jnc int13_cdrom_rme_end + mov _int13_cdrom.status, #1 +int13_cdrom_rme_end: + pop bp + ASM_END + + if (status != 0) { + SET_AH(0xb1); // media locked + goto int13_fail_noah; + } + + goto int13_success; + break; + + case 0x48: // IBM/MS get drive parameters + size = read_word(DS,SI+(Bit16u)&Int13Ext->size); + + // Buffer is too small + if(size < 0x1a) + goto int13_fail; + + // EDD 1.x + if(size >= 0x1a) { + Bit16u cylinders, heads, spt, blksize; + + blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a); + write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values + write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff); + write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff); + write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64 + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff); + write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); + } + + // EDD 2.x + if(size >= 0x1e) { + Bit8u channel, dev, irq, mode, checksum, i; + Bit16u iobase1, iobase2, options; + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e); + + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); + + // Fill in dpte + channel = device / 2; + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); + irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq); + mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); + + // FIXME atapi device + options = (1<<4); // lba translation + options |= (1<<5); // removable device + options |= (1<<6); // atapi device options |= (mode==ATA_MODE_PIO32?1:0<<7); - options |= (translation==ATA_TRANSLATION_LBA?1:0<<9); - options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9); write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1); - write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2); + write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC); write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 ); write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb ); write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq ); @@ -5435,9 +6093,9 @@ write_word(ebda_seg, &EbdaData->ata.dpte.options, options); write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0); write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); - + checksum=0; - for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i); + for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i); checksum = ~checksum; write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum); } @@ -5463,7 +6121,7 @@ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A'); write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0); } - else { + else { // FIXME PCI } write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A'); @@ -5476,7 +6134,7 @@ write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0); write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L); } - else { + else { // FIXME PCI } write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2); @@ -5491,6 +6149,12 @@ } goto int13_success; + break; + + case 0x49: // IBM/MS extended media change + // always send changed ?? + SET_AH(06); + goto int13_fail_nostatus; break; case 0x4e: // // IBM/MS set hardware configuration @@ -5507,361 +6171,6 @@ } 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 */ - BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH()); - 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 - case 0x50: // IBM/MS send packet command - default: - BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH()); - goto int13_fail; - break; - } - -int13_fail: - SET_AH(0x01); // defaults to invalid function in AH or invalid parameter -int13_fail_noah: - SET_DISK_RET_STATUS(GET_AH()); -int13_fail_nostatus: - SET_CF(); // error occurred - return; - -int13_success: - SET_AH(0x00); // no error -int13_success_noah: - SET_DISK_RET_STATUS(0x00); - CLEAR_CF(); // no error - return; -} - -// --------------------------------------------------------------------------- -// Start of int13 for cdrom -// --------------------------------------------------------------------------- - - void -int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) - Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; -{ - Bit16u ebda_seg=read_word(0x0040,0x000E); - Bit8u device, status, locks; - Bit8u atacmd[12]; - Bit32u lba; - Bit16u count, segment, offset, i, size; - - BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); - // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI); - - SET_DISK_RET_STATUS(0x00); - - /* basic check : device should be 0xE0+ */ - if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) { - BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL()); - goto int13_fail; - } - - // Get the ata channel - device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]); - - /* basic check : device has to be valid */ - if (device >= BX_MAX_ATA_DEVICES) { - BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL()); - 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 */ - case 0x43: // IBM/MS extended write - SET_AH(0x03); - goto int13_fail_noah; - break; - - case 0x01: /* read disk status */ - status = read_byte(0x0040, 0x0074); - SET_AH(status); - SET_DISK_RET_STATUS(0); - - /* 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; - - case 0x41: // IBM/MS installation check - BX=0xaa55; // install check - SET_AH(0x30); // EDD 2.1 - CX=0x0007; // ext disk access, removable and edd - goto int13_success_noah; - break; - - case 0x42: // IBM/MS extended read - case 0x44: // IBM/MS verify sectors - case 0x47: // IBM/MS extended seek - - count=read_word(DS, SI+(Bit16u)&Int13Ext->count); - segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment); - offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset); - - // Can't use 64 bits lba - lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); - if (lba != 0L) { - BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH()); - goto int13_fail; - } - - // Get 32 bits lba - lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); - - // If verify or seek - if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 )) - goto int13_success; - - memsetb(get_SS(),atacmd,0,12); - atacmd[0]=0x28; // READ command - atacmd[7]=(count & 0xff00) >> 8; // Sectors - atacmd[8]=(count & 0x00ff); // Sectors - atacmd[2]=(lba & 0xff000000) >> 24; // LBA - atacmd[3]=(lba & 0x00ff0000) >> 16; - atacmd[4]=(lba & 0x0000ff00) >> 8; - atacmd[5]=(lba & 0x000000ff); - status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset); - - count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11); - write_word(DS, SI+(Bit16u)&Int13Ext->count, count); - - if (status != 0) { - BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status); - SET_AH(0x0c); - goto int13_fail_noah; - } - - goto int13_success; - break; - - case 0x45: // IBM/MS lock/unlock drive - if (GET_AL() > 2) goto int13_fail; - - locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock); - - switch (GET_AL()) { - case 0 : // lock - if (locks == 0xff) { - SET_AH(0xb4); - SET_AL(1); - goto int13_fail_noah; - } - write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks); - SET_AL(1); - break; - case 1 : // unlock - if (locks == 0x00) { - SET_AH(0xb0); - SET_AL(0); - goto int13_fail_noah; - } - write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks); - SET_AL(locks==0?0:1); - break; - case 2 : // status - SET_AL(locks==0?0:1); - break; - } - goto int13_success; - break; - - case 0x46: // IBM/MS eject media - locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock); - - if (locks != 0) { - SET_AH(0xb1); // media locked - goto int13_fail_noah; - } - // FIXME should handle 0x31 no media in device - // FIXME should handle 0xb5 valid request failed - - // Call removable media eject - ASM_START - push bp - mov bp, sp - - mov ah, #0x52 - int 15 - mov _int13_cdrom.status + 2[bp], ah - jnc int13_cdrom_rme_end - mov _int13_cdrom.status, #1 -int13_cdrom_rme_end: - pop bp - ASM_END - - if (status != 0) { - SET_AH(0xb1); // media locked - goto int13_fail_noah; - } - - goto int13_success; - break; - - case 0x48: // IBM/MS get drive parameters - size = read_word(DS,SI+(Bit16u)&Int13Ext->size); - - // Buffer is too small - if(size < 0x1a) - goto int13_fail; - - // EDD 1.x - if(size >= 0x1a) { - Bit16u cylinders, heads, spt, blksize; - - blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); - - write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a); - write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values - write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff); - write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff); - write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff); - write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64 - write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff); - write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); - } - - // EDD 2.x - if(size >= 0x1e) { - Bit8u channel, dev, irq, mode, checksum, i; - Bit16u iobase1, iobase2, options; - - write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e); - - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); - - // Fill in dpte - channel = device / 2; - iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); - iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); - irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq); - mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); - - // FIXME atapi device - options = (1<<4); // lba translation - options |= (1<<5); // removable device - options |= (1<<6); // atapi device - options |= (mode==ATA_MODE_PIO32?1:0<<7); - - write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1); - write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2); - write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 ); - write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb ); - write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq ); - write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 ); - write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 ); - write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 ); - write_word(ebda_seg, &EbdaData->ata.dpte.options, options); - write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0); - write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); - - checksum=0; - for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i); - checksum = ~checksum; - write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum); - } - - // EDD 3.x - if(size >= 0x42) { - Bit8u channel, iface, checksum, i; - Bit16u iobase1; - - channel = device / 2; - iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface); - iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); - - write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42); - write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd); - write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24); - write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0); - write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0); - - if (iface==ATA_IFACE_ISA) { - write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I'); - write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S'); - write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A'); - write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0); - } - else { - // FIXME PCI - } - write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A'); - write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T'); - write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A'); - write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0); - - if (iface==ATA_IFACE_ISA) { - write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1); - write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0); - write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L); - } - else { - // FIXME PCI - } - write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2); - write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0); - write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0); - write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L); - - checksum=0; - for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i); - checksum = ~checksum; - write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum); - } - - goto int13_success; - break; - - case 0x49: // IBM/MS extended media change - // always send changed ?? - SET_AH(06); - goto int13_fail_nostatus; - break; - - case 0x4e: // // IBM/MS set hardware configuration - // 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 */ @@ -5909,7 +6218,7 @@ BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); // 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 @@ -5984,11 +6293,10 @@ Bit8u atacmd[12]; BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); - //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI); - + /* at this point, we are emulating a floppy/harddisk */ - - // Recompute the device number + + // Recompute the device number device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2; device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec); @@ -6001,7 +6309,6 @@ goto int13_fail; } - switch (GET_AH()) { // all those functions return SUCCESS @@ -6010,7 +6317,7 @@ 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 0x11: /* recalibrate */ case 0x14: /* controller internal diagnostic */ case 0x16: /* detect disk change */ goto int13_success; @@ -6035,9 +6342,9 @@ case 0x02: // read disk sectors case 0x04: // verify disk sectors - vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); - vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders); - vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads); + vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); + vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders); + vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads); ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba); @@ -6066,17 +6373,17 @@ // calculate the virtual lba inside the image vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1)); - + // In advance so we don't loose the count SET_AL(nbsectors); // start lba on cd - slba = (Bit32u)vlba/4; + slba = (Bit32u)vlba/4; before= (Bit16u)vlba%4; // end lba on cd elba = (Bit32u)(vlba+nbsectors-1)/4; - + memsetb(get_SS(),atacmd,0,12); atacmd[0]=0x28; // READ command atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors @@ -6096,10 +6403,10 @@ break; case 0x08: /* read disk drive parameters */ - vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); - vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1; - vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1; - + vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); + vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1; + vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1; + SET_AL( 0x00 ); SET_BL( 0x00 ); SET_CH( vcylinders & 0xff ); @@ -6107,7 +6414,7 @@ SET_DH( vheads ); SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2 // FIXME ElTorito Harddisk. should send the HD count - + switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) { case 0x01: SET_BL( 0x02 ); break; case 0x02: SET_BL( 0x04 ); break; @@ -6143,7 +6450,7 @@ case 0x45: // IBM/MS lock/unlock drive case 0x46: // IBM/MS eject media case 0x47: // IBM/MS extended seek - case 0x48: // IBM/MS get drive parameters + case 0x48: // IBM/MS get drive parameters case 0x49: // IBM/MS extended media change case 0x4e: // ? - set hardware configuration case 0x50: // ? - send packet command @@ -6231,8 +6538,8 @@ } void -int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) - Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; { Bit8u drive, num_sectors, sector, head, status, mod; Bit8u drive_map; @@ -6338,7 +6645,7 @@ } if ( (num_sectors > 128) || (num_sectors == 0) ) - BX_PANIC("int13_harddisk(): num_sectors out of range!\n"); + BX_PANIC("int13_harddisk: num_sectors out of range!\n"); if (head > 15) BX_PANIC("hard drive BIOS:(read/verify) head > 15\n"); @@ -6484,7 +6791,7 @@ } if ( (num_sectors > 128) || (num_sectors == 0) ) - BX_PANIC("int13_harddisk(): num_sectors out of range!\n"); + BX_PANIC("int13_harddisk: num_sectors out of range!\n"); if (head > 15) BX_PANIC("hard drive BIOS:(read) head > 15\n"); @@ -6594,7 +6901,7 @@ case 0x08: /* read disk drive parameters */ BX_DEBUG_INT13_HD("int13_f08\n"); - + drive = GET_ELDL (); get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors); @@ -6734,10 +7041,10 @@ break; case 0x18: // set media type for format - case 0x41: // IBM/MS - case 0x42: // IBM/MS - case 0x43: // IBM/MS - case 0x44: // IBM/MS + case 0x41: // IBM/MS + case 0x42: // IBM/MS + case 0x43: // IBM/MS + case 0x44: // IBM/MS case 0x45: // IBM/MS lock/unlock drive case 0x46: // IBM/MS eject media case 0x47: // IBM/MS extended seek @@ -6782,7 +7089,7 @@ hd_type = inb_cmos(0x12) & 0x0f; if (hd_type != 0x0f) BX_INFO(panic_msg_reg12h,1); - hd_type = inb_cmos(0x1a); // HD0: extended type + hd_type = inb_cmos(0x1a); // HD1: extended type if (hd_type != 47) BX_INFO(panic_msg_reg19h,0,0x1a); iobase = 0x24; @@ -6801,10 +7108,71 @@ #endif //else BX_USE_ATADRV +#if BX_SUPPORT_FLOPPY ////////////////////// // FLOPPY functions // ////////////////////// + +void floppy_reset_controller() +{ + Bit8u val8; + + // Reset controller + val8 = inb(0x03f2); + outb(0x03f2, val8 & ~0x04); + outb(0x03f2, val8 | 0x04); + + // Wait for controller to come out of reset + do { + val8 = inb(0x3f4); + } while ( (val8 & 0xc0) != 0x80 ); +} + +void floppy_prepare_controller(drive) + Bit16u drive; +{ + Bit8u val8, dor, prev_reset; + + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0040, 0x003e); + val8 &= 0x7f; + write_byte(0x0040, 0x003e, val8); + + // turn on motor of selected drive, DMA & int enabled, normal operation + prev_reset = inb(0x03f2) & 0x04; + if (drive) + dor = 0x20; + else + dor = 0x10; + dor |= 0x0c; + dor |= drive; + outb(0x03f2, dor); + + // reset the disk motor timeout value of INT 08 + write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); + + // wait for drive readiness + do { + val8 = inb(0x3f4); + } while ( (val8 & 0xc0) != 0x80 ); + + if (prev_reset == 0) { + // turn on interrupts +ASM_START + sti +ASM_END + // wait on 40:3e bit 7 to become 1 + do { + val8 = read_byte(0x0040, 0x003e); + } while ( (val8 & 0x80) == 0 ); + val8 &= 0x7f; +ASM_START + cli +ASM_END + write_byte(0x0040, 0x003e, val8); + } +} bx_bool floppy_media_known(drive) @@ -6912,7 +7280,7 @@ retval = 1; } // - // Extended floppy size uses special cmos setting + // Extended floppy size uses special cmos setting else if ( drive_type == 6 ) { // 160k 5.25" drive config_data = 0x00; // 0000 0000 @@ -6953,63 +7321,41 @@ floppy_drive_recal(drive) Bit16u drive; { - Bit8u val8, dor; + Bit8u val8; Bit16u curr_cyl_offset; - // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("floppy recal:f07: ctrl not ready\n"); + floppy_prepare_controller(drive); // send Recalibrate command (2 bytes) to controller outb(0x03f5, 0x07); // 07: Recalibrate outb(0x03f5, drive); // 0=drive0, 1=drive1 - // turn on interrupts + // turn on interrupts ASM_START sti ASM_END // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); - } - - val8 = 0; // separate asm from while() loop - // turn off interrupts + do { + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0, and calibrated bit - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; if (drive) { val8 |= 0x02; // Drive 1 calibrated curr_cyl_offset = 0x0095; - } - else { + } else { val8 |= 0x01; // Drive 0 calibrated curr_cyl_offset = 0x0094; - } + } write_byte(0x0040, 0x003e, val8); write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0 @@ -7036,7 +7382,6 @@ return(1); } -#if BX_SUPPORT_FLOPPY void int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; @@ -7049,7 +7394,6 @@ Bit16u es, last_addr; BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); - // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI); ah = GET_AH(); @@ -7062,7 +7406,7 @@ set_diskette_ret_status(1); SET_CF(); return; - } + } drive_type = inb_cmos(0x10); if (drive == 0) @@ -7074,7 +7418,7 @@ set_diskette_ret_status(0x80); SET_CF(); return; - } + } SET_AH(0); set_diskette_ret_status(0); CLEAR_CF(); // successful @@ -7087,7 +7431,7 @@ SET_AH(val8); if (val8) { SET_CF(); - } + } return; case 0x02: // Read Diskette Sectors @@ -7099,15 +7443,15 @@ head = GET_DH(); drive = GET_ELDL(); - if ( (drive > 1) || (head > 1) || - (num_sectors == 0) || (num_sectors > 72) ) { -BX_INFO("floppy: drive>1 || head>1 ...\n"); + if ((drive > 1) || (head > 1) || (sector == 0) || + (num_sectors == 0) || (num_sectors > 72)) { + BX_INFO("int13_diskette: read/write/verify: parameter out of range\n"); SET_AH(1); set_diskette_ret_status(1); SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } // see if drive exists if (floppy_drive_exists(drive) == 0) { @@ -7116,7 +7460,7 @@ 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) { @@ -7126,8 +7470,8 @@ SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } - } + } + } if (ah == 0x02) { // Read Diskette Sectors @@ -7146,7 +7490,7 @@ if ( base_address < base_es ) { // in case of carry, adjust page by 1 page++; - } + } base_count = (num_sectors * 512) - 1; // check for 64K boundary overrun @@ -7157,7 +7501,7 @@ SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } BX_DEBUG_INT13_FL("masking DMA-1 c2\n"); outb(0x000a, 0x06); @@ -7190,28 +7534,7 @@ //-------------------------------------- // set up floppy controller for transfer //-------------------------------------- - - // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("int13_diskette:f02: ctrl not ready\n"); + floppy_prepare_controller(drive); // send read-normal-data command (9 bytes) to controller outb(0x03f5, 0xe6); // e6: read normal data @@ -7224,27 +7547,35 @@ outb(0x03f5, 0); // Gap length outb(0x03f5, 0xff); // Gap length - // turn on interrupts + // turn on interrupts ASM_START sti ASM_END // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); - } - - val8 = 0; // separate asm from while() loop - // turn off interrupts + do { + val8 = read_byte(0x0040, 0x0040); + if (val8 == 0) { + floppy_reset_controller(); + SET_AH(0x80); // drive not ready (timeout) + set_diskette_ret_status(0x80); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); + write_byte(0x0040, 0x003e, val8); // check port 3f4 for accessibility to status bytes val8 = inb(0x3f4); @@ -7275,7 +7606,7 @@ SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } // ??? should track be new val from return_status[3] ? set_diskette_current_cyl(drive, track); @@ -7283,8 +7614,7 @@ SET_AH(0x00); // success CLEAR_CF(); // success return; - } - else if (ah == 0x03) { + } else if (ah == 0x03) { // Write Diskette Sectors //----------------------------------- @@ -7301,7 +7631,7 @@ if ( base_address < base_es ) { // in case of carry, adjust page by 1 page++; - } + } base_count = (num_sectors * 512) - 1; // check for 64K boundary overrun @@ -7312,7 +7642,7 @@ SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } BX_DEBUG_INT13_FL("masking DMA-1 c2\n"); outb(0x000a, 0x06); @@ -7338,30 +7668,9 @@ //-------------------------------------- // set up floppy controller for transfer //-------------------------------------- - - // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("int13_diskette:f03: ctrl not ready\n"); - - // send read-normal-data command (9 bytes) to controller + floppy_prepare_controller(drive); + + // send write-normal-data command (9 bytes) to controller outb(0x03f5, 0xc5); // c5: write normal data outb(0x03f5, (head << 2) | drive); // HD DR1 DR2 outb(0x03f5, track); @@ -7372,27 +7681,35 @@ outb(0x03f5, 0); // Gap length outb(0x03f5, 0xff); // Gap length - // turn on interrupts + // turn on interrupts ASM_START sti ASM_END // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); - } - - val8 = 0; // separate asm from while() loop - // turn off interrupts + do { + val8 = read_byte(0x0040, 0x0040); + if (val8 == 0) { + floppy_reset_controller(); + SET_AH(0x80); // drive not ready (timeout) + set_diskette_ret_status(0x80); + SET_AL(0); // no sectors written + SET_CF(); // error occurred + return; + } + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); + write_byte(0x0040, 0x003e, val8); // check port 3f4 for accessibility to status bytes val8 = inb(0x3f4); @@ -7436,8 +7753,7 @@ SET_AH(0x00); // success CLEAR_CF(); // success return; - } - else { // if (ah == 0x04) + } else { // if (ah == 0x04) // Verify Diskette Sectors // ??? should track be new val from return_status[3] ? @@ -7446,8 +7762,8 @@ CLEAR_CF(); // success SET_AH(0x00); // success return; - } - + } + break; case 0x05: // format diskette track BX_DEBUG_INT13_FL("floppy f05\n"); @@ -7462,7 +7778,7 @@ SET_AH(1); set_diskette_ret_status(1); SET_CF(); // error occurred - } + } // see if drive exists if (floppy_drive_exists(drive) == 0) { @@ -7470,7 +7786,7 @@ 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) { @@ -7480,8 +7796,8 @@ SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } - } + } + } // set up DMA controller for transfer page = (ES >> 12); // upper 4 bits @@ -7491,7 +7807,7 @@ if ( base_address < base_es ) { // in case of carry, adjust page by 1 page++; - } + } base_count = (num_sectors * 4) - 1; // check for 64K boundary overrun @@ -7502,7 +7818,7 @@ SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } outb(0x000a, 0x06); outb(0x000c, 0x00); // clear flip-flop @@ -7519,27 +7835,9 @@ outb(0x000a, 0x02); // set up floppy controller for transfer - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("int13_diskette:f05: ctrl not ready\n"); - - // send read-normal-data command (6 bytes) to controller + floppy_prepare_controller(drive); + + // send format-track command (6 bytes) to controller outb(0x03f5, 0x4d); // 4d: format track outb(0x03f5, (head << 2) | drive); // HD DR1 DR2 outb(0x03f5, 2); // 512 byte sector size @@ -7550,20 +7848,29 @@ ASM_START sti ASM_END + // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); - } - val8 = 0; // separate asm from while() loop - // turn off interrupts + do { + val8 = read_byte(0x0040, 0x0040); + if (val8 == 0) { + floppy_reset_controller(); + SET_AH(0x80); // drive not ready (timeout) + set_diskette_ret_status(0x80); + SET_CF(); // error occurred + return; + } + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); + write_byte(0x0040, 0x003e, val8); // check port 3f4 for accessibility to status bytes val8 = inb(0x3f4); if ( (val8 & 0xc0) != 0xc0 ) @@ -7915,8 +8222,9 @@ Bit16u bootseg; Bit16u bootip; Bit16u status; - - struct ipl_entry e; + Bit16u bootfirst; + + ipl_entry_t e; // if BX_ELTORITO_BOOT is not defined, old behavior // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL @@ -7930,7 +8238,7 @@ // CMOS reg 0x38 & 0xf0 : 3rd boot device // boot device codes: // 0x00 : not defined - // 0x01 : first floppy + // 0x01 : first floppy // 0x02 : first harddrive // 0x03 : first cdrom // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot) @@ -7942,16 +8250,25 @@ bootdev |= ((inb_cmos(0x38) & 0xf0) << 4); bootdev >>= 4 * seq_nr; bootdev &= 0xf; - if (bootdev == 0) BX_PANIC("No bootable device.\n"); - + + /* Read user selected device */ + bootfirst = read_word(ebda_seg, IPL_BOOTFIRST_OFFSET); + if (bootfirst != 0xFFFF) { + bootdev = bootfirst; + /* User selected device not set */ + write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF); + /* Reset boot sequence */ + write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xFFFF); + } else if (bootdev == 0) BX_PANIC("No bootable device.\n"); + /* Translate from CMOS runes to an IPL table offset by subtracting 1 */ bootdev -= 1; -#else +#else if (seq_nr ==2) BX_PANIC("No more boot devices."); - if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1)) + if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1)) /* Boot from floppy if the bit is set or it's the second boot */ bootdev = 0x00; - else + else bootdev = 0x01; #endif @@ -7963,13 +8280,13 @@ /* Do the loading, and set up vector as a far pointer to the boot * address, and bootdrv as the boot drive */ - print_boot_device(e.type); + print_boot_device(&e); switch(e.type) { - case 0x01: /* FDD */ - case 0x02: /* HDD */ - - bootdrv = (e.type == 0x02) ? 0x80 : 0x00; + case IPL_TYPE_FLOPPY: /* FDD */ + case IPL_TYPE_HARDDISK: /* HDD */ + + bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00; bootseg = 0x07c0; status = 0; @@ -7984,7 +8301,7 @@ mov dl, _int18_function.bootdrv + 2[bp] mov ax, _int18_function.bootseg + 2[bp] mov es, ax ;; segment - mov bx, #0x0000 ;; offset + xor bx, bx ;; offset mov ah, #0x02 ;; function 2, read diskette sector mov al, #0x01 ;; read 1 sector mov ch, #0x00 ;; track 0 @@ -8002,7 +8319,7 @@ pop ax pop bp ASM_END - + if (status != 0) { print_boot_failure(e.type, 1); return; @@ -8010,7 +8327,7 @@ /* Always check the signature on a HDD boot sector; on FDD, only do * the check if the CMOS doesn't tell us to skip it */ - if (e.type != 0x00 || !((inb_cmos(0x38) & 0x01))) { + if ((e.type != IPL_TYPE_FLOPPY) || !((inb_cmos(0x38) & 0x01))) { if (read_word(bootseg,0x1fe) != 0xaa55) { print_boot_failure(e.type, 0); return; @@ -8028,7 +8345,7 @@ break; #if BX_ELTORITO_BOOT - case 0x03: /* CD-ROM */ + case IPL_TYPE_CDROM: /* CD-ROM */ status = cdrom_boot(); // If failure @@ -8047,7 +8364,7 @@ break; #endif - case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */ + case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */ bootseg = e.vector >> 16; bootip = e.vector & 0xffff; break; @@ -8055,16 +8372,20 @@ default: return; } - + /* Debugging info */ + BX_INFO("Booting from %x:%x\n", bootseg, bootip); + /* Jump to the boot vector */ ASM_START mov bp, sp +// push cs +// push #int18_handler ;; Build an iret stack frame that will take us to the boot vector. ;; iret pops ip, then cs, then flags, so push them in the opposite order. pushf - mov ax, _int18_function.bootseg + 0[bp] + mov ax, _int18_function.bootseg + 0[bp] push ax - mov ax, _int18_function.bootip + 0[bp] + mov ax, _int18_function.bootip + 0[bp] push ax ;; Set the magic number in ax and the boot drive in dl. mov ax, #0xaa55 @@ -8267,7 +8588,11 @@ } else if (regs.u.r8.bl == 0x83) { BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx); } else if (regs.u.r8.bl == 0x86) { - BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx); + if (regs.u.r8.al == 0x02) { + 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); + } } regs.u.r8.ah = regs.u.r8.bl; SetCF(iret_addr.flags); @@ -8313,11 +8638,11 @@ // Done waiting. Bit16u segment, offset; - offset = read_word( 0x40, 0x98 ); - segment = read_word( 0x40, 0x9A ); + segment = read_word( 0x40, 0x98 ); + offset = read_word( 0x40, 0x9A ); write_byte( 0x40, 0xA0, 0 ); // Turn of status byte. outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt. - write_byte( segment, offset, 0x80 ); // Write to specified flag byte. + write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte. } else { // Continue waiting. time -= 0x3D1; @@ -8525,13 +8850,18 @@ #endif int13_disk: + ;; int13_harddisk modifies high word of EAX + shr eax, #16 + push ax call _int13_harddisk + pop ax + shl eax, #16 int13_out: pop ds pop es popa - iret + iret ;---------- ;- INT18h - @@ -8544,19 +8874,19 @@ xor ax, ax mov ss, ax - ;; Get the boot sequence number out of the IPL memory ;; The first time we do this it will have been set to -1 so ;; we will start from device 0. mov ds, ax - mov bx, word ptr [EBDA_SEG_PTR] + mov bx, word ptr [0x40E] ;; EBDA segment mov ds, bx ;; Set segment mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number inc bx ;; ++ mov IPL_SEQUENCE_OFFSET, bx ;; Write it back - mov ds, ax ;; and reset the segment to zero. + mov ds, ax ;; and reset the segment to zero. ;; Call the C code for the next boot device push bx + call _int18_function ;; Boot failed: invoke the boot recovery function... @@ -8566,6 +8896,7 @@ ;- INT19h - ;---------- int19_relocated: ;; Boot function, relocated + ;; ;; *** Warning: INT 19h resets the whole machine *** ;; @@ -8577,10 +8908,12 @@ ;; boot sequence will start, which is more or less the required behaviour. ;; ;; Reset SP and SS + mov ax, #0xfffe mov sp, ax xor ax, ax mov ss, ax + call _machine_reset ;---------- @@ -8594,7 +8927,7 @@ ;- POST: Floppy Drive - ;---------------------- floppy_drive_post: - mov ax, #0x0000 + xor ax, ax mov ds, ax mov al, #0x00 @@ -8676,7 +9009,7 @@ mov dx, #0x03f6 out dx, al - mov ax, #0x0000 + xor ax, ax mov ds, ax mov 0x0474, al /* hard disk status of last operation */ mov 0x0477, al /* hard disk port offset (XT only ???) */ @@ -8691,8 +9024,8 @@ SET_INT_VECTOR(0x76, #0xF000, #int76_handler) ;; INT 41h: hard disk 0 configuration pointer ;; INT 46h: hard disk 1 configuration pointer - SET_INT_VECTOR(0x41, word ptr [EBDA_SEG_PTR], #0x003D) - SET_INT_VECTOR(0x46, word ptr [EBDA_SEG_PTR], #0x004D) + SET_INT_VECTOR(0x41, word ptr [0x40E], #0x003D) /* EBDA:003D */ + SET_INT_VECTOR(0x46, word ptr [0x40E], #0x004D) /* EBDA:004D */ ;; move disk geometry data from CMOS to EBDA disk parameter table(s) mov al, #0x12 @@ -8723,7 +9056,7 @@ xor ax, ax mov ds, ax - mov ax, word ptr [EBDA_SEG_PTR] + mov ax, word ptr [0x40E] ;; EBDA segment mov ds, ax ;;; Filling EBDA table for hard disk 0. @@ -8869,7 +9202,9 @@ ;; 0x2b landing zone high D ;; 0x2c sectors/track E ;;; Fill EBDA table for hard disk 1. - mov ax, #EBDA_SEG + xor ax, ax + mov ds, ax + mov ax, word ptr [0x40E] ;; EBDA segment mov ds, ax mov al, #0x28 out #0x70, al @@ -8992,7 +9327,7 @@ #endif xor ax, ax ; mov EBDA seg into 40E mov ds, ax - mov word ptr [EBDA_SEG_PTR], #EBDA_SEG + mov word ptr [0x40E], #EBDA_SEG ret;; ;-------------------- @@ -9000,13 +9335,42 @@ ;-------------------- ; relocated here because the primary POST area isnt big enough. eoi_jmp_post: - call eoi_both_pics - + mov al, #0x20 + out #0xA0, al ;; slave PIC EOI + mov al, #0x20 + out #0x20, al ;; master PIC EOI + +jmp_post_0x467: xor ax, ax mov ds, ax jmp far ptr [0x467] +iret_post_0x467: + xor ax, ax + mov ds, ax + + mov sp, [0x467] + mov ss, [0x469] + iret + +retf_post_0x467: + xor ax, ax + mov ds, ax + + mov sp, [0x467] + mov ss, [0x469] + retf + +s3_post: +#if BX_ROMBIOS32 + call rombios32_init +#endif + call _s3_resume + mov bl, #0x00 + and ax, ax + jz normal_post + call _s3_resume_panic ;-------------------- eoi_both_pics: @@ -9159,16 +9523,22 @@ .align 16 bios32_entry_point: - pushf - cmp eax, #0x49435024 + pushfd + cmp eax, #0x49435024 ;; "$PCI" jne unknown_service mov eax, #0x80000000 mov dx, #0x0cf8 out dx, eax mov dx, #0x0cfc in eax, dx - cmp eax, #0x12378086 +#ifdef PCI_FIXED_HOST_BRIDGE + cmp eax, #PCI_FIXED_HOST_BRIDGE jne unknown_service +#else + ;; say ok if a device is present + cmp eax, #0xffffffff + je unknown_service +#endif mov ebx, #0x000f0000 mov ecx, #0 mov edx, #pcibios_protected @@ -9177,12 +9547,15 @@ unknown_service: mov al, #0x80 bios32_end: - popf +#ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu +#endif + popfd retf .align 16 pcibios_protected: - pushf + pushfd cli push esi push edi @@ -9190,15 +9563,15 @@ jne pci_pro_f02 mov bx, #0x0210 mov cx, #0 - mov edx, #0x20494350 + mov edx, #0x20494350 ;; "PCI " mov al, #0x01 jmp pci_pro_ok pci_pro_f02: ;; find pci device cmp al, #0x02 - jne pci_pro_f08 + jne pci_pro_f03 shl ecx, #16 mov cx, dx - mov bx, #0x0000 + xor bx, bx mov di, #0x00 pci_pro_devloop: call pci_pro_select_reg @@ -9213,6 +9586,27 @@ inc bx cmp bx, #0x0100 jne pci_pro_devloop + mov ah, #0x86 + jmp pci_pro_fail +pci_pro_f03: ;; find class code + cmp al, #0x03 + jne pci_pro_f08 + xor bx, bx + mov di, #0x08 +pci_pro_devloop2: + call pci_pro_select_reg + mov dx, #0x0cfc + in eax, dx + shr eax, #8 + cmp eax, ecx + jne pci_pro_nextdev2 + cmp si, #0 + je pci_pro_ok + dec si +pci_pro_nextdev2: + inc bx + cmp bx, #0x0100 + jne pci_pro_devloop2 mov ah, #0x86 jmp pci_pro_fail pci_pro_f08: ;; read configuration byte @@ -9288,16 +9682,20 @@ pci_pro_fail: pop edi pop esi - sti - popf +#ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu +#endif + popfd stc retf pci_pro_ok: xor ah, ah pop edi pop esi - sti - popf +#ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu +#endif + popfd clc retf @@ -9324,8 +9722,14 @@ out dx, eax mov dx, #0x0cfc in eax, dx - cmp eax, #0x12378086 +#ifdef PCI_FIXED_HOST_BRIDGE + cmp eax, #PCI_FIXED_HOST_BRIDGE je pci_present +#else + ;; say ok if a device is present + cmp eax, #0xffffffff + jne pci_present +#endif pop dx pop eax mov ah, #0xff @@ -9339,7 +9743,7 @@ mov ax, #0x0001 mov bx, #0x0210 mov cx, #0 - mov edx, #0x20494350 + mov edx, #0x20494350 ;; "PCI " mov edi, #0xf0000 mov di, #pcibios_protected clc @@ -9348,10 +9752,10 @@ push esi push edi cmp al, #0x02 - jne pci_real_f08 + jne pci_real_f03 shl ecx, #16 mov cx, dx - mov bx, #0x0000 + xor bx, bx mov di, #0x00 pci_real_devloop: call pci_real_select_reg @@ -9368,7 +9772,30 @@ jne pci_real_devloop mov dx, cx shr ecx, #16 - mov ah, #0x86 + mov ax, #0x8602 + jmp pci_real_fail +pci_real_f03: ;; find class code + cmp al, #0x03 + jne pci_real_f08 + xor bx, bx + mov di, #0x08 +pci_real_devloop2: + call pci_real_select_reg + mov dx, #0x0cfc + in eax, dx + shr eax, #8 + cmp eax, ecx + jne pci_real_nextdev2 + cmp si, #0 + je pci_real_ok + dec si +pci_real_nextdev2: + inc bx + cmp bx, #0x0100 + jne pci_real_devloop2 + mov dx, cx + shr ecx, #16 + mov ax, #0x8603 jmp pci_real_fail pci_real_f08: ;; read configuration byte cmp al, #0x08 @@ -9430,7 +9857,7 @@ jmp pci_real_ok pci_real_f0d: ;; write configuration dword cmp al, #0x0d - jne pci_real_unknown + jne pci_real_f0e call pci_real_select_reg push dx mov dx, #0x0cfc @@ -9438,6 +9865,46 @@ out dx, eax pop dx jmp pci_real_ok +pci_real_f0e: ;; get irq routing options + cmp al, #0x0e + jne pci_real_unknown + SEG ES + cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start + jb pci_real_too_small + SEG ES + mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start + pushf + push ds + push es + push cx + push si + push di + cld + mov si, #pci_routing_table_structure_start + push cs + pop ds + SEG ES + mov cx, [di+2] + SEG ES + mov es, [di+4] + mov di, cx + mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start + rep + movsb + pop di + pop si + pop cx + pop es + pop ds + popf + mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used + jmp pci_real_ok +pci_real_too_small: + SEG ES + mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start + mov ah, #0x89 + jmp pci_real_fail + pci_real_unknown: mov ah, #0x81 pci_real_fail: @@ -9464,7 +9931,7 @@ out dx, eax pop dx ret - + .align 16 pci_routing_table_structure: db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature @@ -9472,21 +9939,22 @@ dw 32 + (6 * 16) ;; table size db 0 ;; PCI interrupt router bus db 0x08 ;; PCI interrupt router DevFunc - dw 0x0000 ;; PCI exclusive IRQs + dw 0x0000 ;; PCI exclusive IRQs dw 0x8086 ;; compatible PCI interrupt router vendor ID - dw 0x7000 ;; compatible PCI interrupt router device ID + dw 0x122e ;; compatible PCI interrupt router device ID dw 0,0 ;; Miniport data db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved - db 0x07 ;; checksum + db 0x37 ;; checksum +pci_routing_table_structure_start: ;; first slot entry PCI-to-ISA (embedded) db 0 ;; pci bus number db 0x08 ;; pci device number (bit 7-3) db 0x61 ;; link value INTA#: pointer into PCI2ISA config space - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x62 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x63 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x60 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 0 ;; physical slot (0 = embedded) @@ -9495,11 +9963,11 @@ db 0 ;; pci bus number db 0x10 ;; pci device number (bit 7-3) db 0x62 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x63 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x60 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x61 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 1 ;; physical slot (0 = embedded) @@ -9508,11 +9976,11 @@ db 0 ;; pci bus number db 0x18 ;; pci device number (bit 7-3) db 0x63 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x60 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x61 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x62 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 2 ;; physical slot (0 = embedded) @@ -9521,11 +9989,11 @@ db 0 ;; pci bus number db 0x20 ;; pci device number (bit 7-3) db 0x60 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x61 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x62 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x63 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 3 ;; physical slot (0 = embedded) @@ -9534,11 +10002,11 @@ db 0 ;; pci bus number db 0x28 ;; pci device number (bit 7-3) db 0x61 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x62 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x63 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x60 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 4 ;; physical slot (0 = embedded) @@ -9547,16 +10015,351 @@ db 0 ;; pci bus number db 0x30 ;; pci device number (bit 7-3) db 0x62 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x63 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x60 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x61 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 5 ;; physical slot (0 = embedded) db 0 ;; reserved +pci_routing_table_structure_end: + +#if !BX_ROMBIOS32 +pci_irq_list: + db 11, 10, 9, 5; + +pcibios_init_sel_reg: + push eax + mov eax, #0x800000 + mov ax, bx + shl eax, #8 + and dl, #0xfc + or al, dl + mov dx, #0x0cf8 + out dx, eax + pop eax + ret + +pcibios_init_iomem_bases: + push bp + mov bp, sp + mov eax, #0xe0000000 ;; base for memory init + push eax + mov ax, #0xc000 ;; base for i/o init + push ax + mov ax, #0x0010 ;; start at base address #0 + push ax + mov bx, #0x0008 +pci_init_io_loop1: + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in ax, dx + cmp ax, #0xffff + jz next_pci_dev + mov dl, #0x04 ;; disable i/o and memory space access + call pcibios_init_sel_reg + mov dx, #0x0cfc + in al, dx + and al, #0xfc + out dx, al +pci_init_io_loop2: + mov dl, [bp-8] + call pcibios_init_sel_reg + mov dx, #0x0cfc + in eax, dx + test al, #0x01 + jnz init_io_base + mov ecx, eax + mov eax, #0xffffffff + out dx, eax + in eax, dx + cmp eax, ecx + je next_pci_base + xor eax, #0xffffffff + mov ecx, eax + mov eax, [bp-4] + out dx, eax + add eax, ecx ;; calculate next free mem base + add eax, #0x01000000 + and eax, #0xff000000 + mov [bp-4], eax + jmp next_pci_base +init_io_base: + mov cx, ax + mov ax, #0xffff + out dx, ax + in ax, dx + cmp ax, cx + je next_pci_base + xor ax, #0xfffe + mov cx, ax + mov ax, [bp-6] + out dx, ax + add ax, cx ;; calculate next free i/o base + add ax, #0x0100 + and ax, #0xff00 + mov [bp-6], ax +next_pci_base: + mov al, [bp-8] + add al, #0x04 + cmp al, #0x28 + je enable_iomem_space + mov byte ptr[bp-8], al + jmp pci_init_io_loop2 +enable_iomem_space: + mov dl, #0x04 ;; enable i/o and memory space access if available + call pcibios_init_sel_reg + mov dx, #0x0cfc + in al, dx + or al, #0x07 + out dx, al +next_pci_dev: + mov byte ptr[bp-8], #0x10 + inc bx + cmp bx, #0x0100 + jne pci_init_io_loop1 + mov sp, bp + pop bp + ret + +pcibios_init_set_elcr: + push ax + push cx + mov dx, #0x04d0 + test al, #0x08 + jz is_master_pic + inc dx + and al, #0x07 +is_master_pic: + mov cl, al + mov bl, #0x01 + shl bl, cl + in al, dx + or al, bl + out dx, al + pop cx + pop ax + ret + +pcibios_init_irqs: + push ds + push bp + mov ax, #0xf000 + mov ds, ax + mov dx, #0x04d0 ;; reset ELCR1 + ELCR2 + mov al, #0x00 + out dx, al + inc dx + out dx, al + mov si, #pci_routing_table_structure + mov bh, [si+8] + mov bl, [si+9] + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in eax, dx + cmp eax, [si+12] ;; check irq router + jne pci_init_end + mov dl, [si+34] + call pcibios_init_sel_reg + push bx ;; save irq router bus + devfunc + mov dx, #0x0cfc + mov ax, #0x8080 + out dx, ax ;; reset PIRQ route control + add dx, #2 + out dx, ax + mov ax, [si+6] + sub ax, #0x20 + shr ax, #4 + mov cx, ax + add si, #0x20 ;; set pointer to 1st entry + mov bp, sp + mov ax, #pci_irq_list + push ax + xor ax, ax + push ax +pci_init_irq_loop1: + mov bh, [si] + mov bl, [si+1] +pci_init_irq_loop2: + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in ax, dx + cmp ax, #0xffff + jnz pci_test_int_pin + test bl, #0x07 + jz next_pir_entry + jmp next_pci_func +pci_test_int_pin: + mov dl, #0x3c + call pcibios_init_sel_reg + mov dx, #0x0cfd + in al, dx + and al, #0x07 + jz next_pci_func + dec al ;; determine pirq reg + mov dl, #0x03 + mul al, dl + add al, #0x02 + xor ah, ah + mov bx, ax + mov al, [si+bx] + mov dl, al + mov bx, [bp] + call pcibios_init_sel_reg + mov dx, #0x0cfc + and al, #0x03 + add dl, al + in al, dx + cmp al, #0x80 + jb pirq_found + mov bx, [bp-2] ;; pci irq list pointer + mov al, [bx] + out dx, al + inc bx + mov [bp-2], bx + call pcibios_init_set_elcr +pirq_found: + mov bh, [si] + mov bl, [si+1] + add bl, [bp-3] ;; pci function number + mov dl, #0x3c + call pcibios_init_sel_reg + mov dx, #0x0cfc + out dx, al +next_pci_func: + inc byte ptr[bp-3] + inc bl + test bl, #0x07 + jnz pci_init_irq_loop2 +next_pir_entry: + add si, #0x10 + mov byte ptr[bp-3], #0x00 + loop pci_init_irq_loop1 + mov sp, bp + pop bx +pci_init_end: + pop bp + pop ds + ret +#endif // !BX_ROMBIOS32 #endif // BX_PCIBIOS + +#if BX_ROMBIOS32 +rombios32_init: + ;; save a20 and enable it + in al, 0x92 + push ax + or al, #0x02 + out 0x92, al + + ;; save SS:SP to the BDA + xor ax, ax + mov ds, ax + mov 0x0469, ss + mov 0x0467, sp + + SEG CS + lidt [pmode_IDT_info] + SEG CS + lgdt [rombios32_gdt_48] + ;; set PE bit in CR0 + mov eax, cr0 + or al, #0x01 + mov cr0, eax + ;; start protected mode code: ljmpl 0x10:rombios32_init1 + db 0x66, 0xea + dw rombios32_05 + dw 0x000f ;; high 16 bit address + dw 0x0010 + +use32 386 +rombios32_05: + ;; init data segments + mov eax, #0x18 + mov ds, ax + mov es, ax + mov ss, ax + xor eax, eax + mov fs, ax + mov gs, ax + cld + + ;; init the stack pointer to point below EBDA + mov ax, [0x040e] + shl eax, #4 + mov esp, #-0x10 + add esp, eax + + ;; pass pointer to s3_resume_flag and s3_resume_vector to rombios32 + push #0x04b0 + push #0x04b2 + + ;; call rombios32 code + mov eax, #0x000e0000 + call eax + + ;; return to 16 bit protected mode first + db 0xea + dd rombios32_10 + dw 0x20 + +use16 386 +rombios32_10: + ;; restore data segment limits to 0xffff + mov ax, #0x28 + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + ;; reset PE bit in CR0 + mov eax, cr0 + and al, #0xFE + mov cr0, eax + + ;; far jump to flush CPU queue after transition to real mode + JMP_AP(0xf000, rombios32_real_mode) + +rombios32_real_mode: + ;; restore IDT to normal real-mode defaults + SEG CS + lidt [rmode_IDT_info] + + xor ax, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ;; restore SS:SP from the BDA + mov ss, 0x0469 + xor esp, esp + mov sp, 0x0467 + ;; restore a20 + pop ax + out 0x92, al + ret + +rombios32_gdt_48: + dw 0x30 + dw rombios32_gdt + dw 0x000f + +rombios32_gdt: + dw 0, 0, 0, 0 + dw 0, 0, 0, 0 + dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10) + dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18) + dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff + dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff +#endif // BX_ROMBIOS32 + ; parallel port detection: base address in DX, index in BX, timeout in CL detect_parport: @@ -9628,13 +10431,12 @@ ret -;; We need a copy of this string, but we are not actually a PnP BIOS, +;; We need a copy of this string, but we are not actually a PnP BIOS, ;; so make sure it is *not* aligned, so OSes will not see it if they scan. .align 16 db 0 pnp_string: .ascii "$PnP" - rom_scan: ;; Scan for existence of valid expansion ROMS. @@ -9652,8 +10454,9 @@ #if BX_TCGBIOS call _tcpa_start_option_rom_scan /* specs: 3.2.3.3 + 10.4.3 */ #endif - mov cx, #0xc000 + rom_scan_loop: + push ax ;; Save AX mov ds, cx mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k cmp [0], #0xAA55 ;; look for signature @@ -9670,6 +10473,8 @@ add al, #0x04 block_count_rounded: + xor bx, bx ;; Restore DS back to 0000: + mov ds, bx #if BX_TCGBIOS push ax push ds @@ -9680,7 +10485,7 @@ push ecx ;; segment where option rom is located at call _tcpa_option_rom /* specs: 3.2.3.3 */ add sp, #4 ;; pop segment - pop ecx ;; original ecx + pop ecx ;; original ecx pop ds pop ax #endif @@ -9704,11 +10509,11 @@ xor ax, ax mov al, [bx] - ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS. + ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS. ;; That should stop it grabbing INT 19h; we will use its BEV instead. mov bx, #0xf000 mov es, bx - lea di, pnp_string + lea di, pnp_string xor bx, bx ;; Restore DS back to 0000: mov ds, bx @@ -9721,8 +10526,8 @@ add sp, #2 ;; Pop offset value pop cx ;; Pop seg value (restore CX) - ;; Look at the ROM's PnP Expansion header. Properly, we're supposed - ;; to init all the ROMs and then go back and build an IPL table of + ;; Look at the ROM's PnP Expansion header. Properly, we're supposed + ;; to init all the ROMs and then go back and build an IPL table of ;; all the bootable devices, but we can get away with one pass. mov ds, cx ;; ROM base mov bx, 0x001a ;; 0x1A is the offset into ROM header that contains... @@ -9730,7 +10535,7 @@ cmp ax, #0x5024 ;; we look for signature "$PnP" jne no_bev mov ax, 2[bx] - cmp ax, #0x506e + cmp ax, #0x506e jne no_bev mov ax, 0x16[bx] ;; 0x16 is the offset of Boot Connection Vector @@ -9753,25 +10558,31 @@ cli ;; In case expansion ROM BIOS turns IF on add sp, #2 ;; Pop offset value pop cx ;; Pop seg value (restore CX) - jmp no_bev + jmp no_bev no_bcv: mov ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of... cmp ax, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none. je no_bev - ;; Found a device that thinks it can boot the system. Record its BEV. + ;; Found a device that thinks it can boot the system. Record its BEV and product name string. + mov di, 0x10[bx] ;; Pointer to the product name string or zero if none xor bx, bx mov ds, bx - mov bx, word ptr [EBDA_SEG_PTR] - mov ds, bx ;; Go to the segment where the IPL table lives + mov bx, word ptr [0x40E] ;; EBDA segment + mov ds, bx ;; Go to the segment where the IPL table lives mov bx, IPL_COUNT_OFFSET ;; Read the number of entries so far cmp bx, #IPL_TABLE_ENTRIES je no_bev ;; Get out if the table is full shl bx, #0x4 ;; Turn count into offset (entries are 16 bytes) - mov IPL_TABLE_OFFSET+0[bx], #0x80 ;; This entry is a BEV device - mov IPL_TABLE_OFFSET+6[bx], cx ;; Build a far pointer from the segment... - mov IPL_TABLE_OFFSET+4[bx], ax ;; and the offset + mov IPL_TABLE_OFFSET+0[bx], #IPL_TYPE_BEV ;; This entry is a BEV device + mov IPL_TABLE_OFFSET+6[bx], cx ;; Build a far pointer from the segment... + mov IPL_TABLE_OFFSET+4[bx], ax ;; and the offset + cmp di, #0x0000 + je no_prod_str + mov 0xA[bx], cx ;; Build a far pointer from the segment... + mov 8[bx], di ;; and the offset +no_prod_str: shr bx, #0x4 ;; Turn the offset back into a count inc bx ;; We have one more entry now mov IPL_COUNT_OFFSET, bx ;; Remember that. @@ -9783,7 +10594,8 @@ shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments ;; because the segment selector is shifted left 4 bits. add cx, ax - cmp cx, #0xe000 + pop ax ;; Restore AX + cmp cx, ax jbe rom_scan_loop xor ax, ax ;; Restore DS back to 0000: @@ -9848,10 +10660,36 @@ #endif -;; for 'C' strings and other data, insert them here with -;; a the following hack: -;; DATA_SEG_DEFS_HERE - +post_init_pic: + mov al, #0x11 ; send initialisation commands + out 0x20, al + out 0xa0, al + mov al, #0x08 + out 0x21, al + mov al, #0x70 + out 0xa1, al + mov al, #0x04 + out 0x21, al + mov al, #0x02 + out 0xa1, al + mov al, #0x01 + out 0x21, al + out 0xa1, al + mov al, #0xb8 + out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6 +#if BX_USE_PS2_MOUSE + mov al, #0x8f +#else + mov al, #0x9f +#endif + out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14 + ret + +;; the following area can be used to write dynamically generated tables + .align 16 +bios_table_area_start: + dd 0xaafb4442 + dd bios_table_area_end - bios_table_area_start - 8; ;-------- ;- POST - @@ -9887,16 +10725,65 @@ ;; Examine CMOS shutdown status. mov al, bl - mov dx, #EBDA_SEG - mov ds, dx - mov [EBDA_CMOS_SHUTDOWN_STATUS_OFFSET], AL + + ;; 0x00, 0x09, 0x0D+ = normal startup + cmp AL, #0x00 + jz normal_post + cmp AL, #0x0d + jae normal_post + cmp AL, #0x09 + je normal_post + + ;; 0x05 = eoi + jmp via [0x40:0x67] jump + cmp al, #0x05 + je eoi_jmp_post + + ;; 0x0A = jmp via [0x40:0x67] jump + cmp al, #0x0a + je jmp_post_0x467 + + ;; 0x0B = iret via [0x40:0x67] + cmp al, #0x0b + je iret_post_0x467 + + ;; 0x0C = retf via [0x40:0x67] + cmp al, #0x0c + je retf_post_0x467 + + ;; Examine CMOS shutdown status. + ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08 = Unimplemented shutdown status. + push bx + call _shutdown_status_panic + +#if 0 + HALT(__LINE__) + ; + ;#if 0 + ; 0xb0, 0x20, /* mov al, #0x20 */ + ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */ + ;#endif + ; + pop es + pop ds + popa + iret +#endif + +normal_post: + ; case 0: normal startup cli mov ax, #0xfffe mov sp, ax - mov ax, #0x0000 + xor ax, ax mov ds, ax mov ss, ax + + ;; Save shutdown status + mov 0x04b0, bl + + cmp bl, #0xfe + jz s3_post ;; zero out BIOS data area (40:00..40:ff) mov es, ax @@ -9909,18 +10796,16 @@ call _log_bios_start ;; set all interrupts to default handler - mov bx, #0x0000 ;; offset index + xor bx, bx ;; offset index mov cx, #0x0100 ;; counter (256 interrupts) mov ax, #dummy_iret_handler mov dx, #0xF000 post_default_ints: mov [bx], ax - inc bx - inc bx + add bx, #2 mov [bx], dx - inc bx - inc bx + add bx, #2 loop post_default_ints ;; set vector 0x79 to zero @@ -10076,28 +10961,51 @@ SET_INT_VECTOR(0x10, #0xF000, #int10_handler) ;; PIC - mov al, #0x11 ; send initialisation commands - out 0x20, al - out 0xa0, al - mov al, #0x08 - out 0x21, al - mov al, #0x70 - out 0xa1, al - mov al, #0x04 - out 0x21, al - mov al, #0x02 - out 0xa1, al - mov al, #0x01 - out 0x21, al - out 0xa1, al - mov al, #0xb8 - out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6 -#if BX_USE_PS2_MOUSE - mov al, #0x8f -#else - mov al, #0x9f -#endif - out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14 + call post_init_pic + + mov cx, #0xc000 ;; init vga bios + mov ax, #0xc780 + call rom_scan + + call _print_bios_banner + +#if BX_ROMBIOS32 + call rombios32_init +#else +#if BX_PCIBIOS + call pcibios_init_iomem_bases + call pcibios_init_irqs +#endif //BX_PCIBIOS +#endif + + ;; + ;; Floppy setup + ;; + call floppy_drive_post + + ;; + ;; Hard Drive setup + ;; + call hard_drive_post + +#if BX_USE_ATADRV + + ;; + ;; ATA/ATAPI driver setup + ;; + call _ata_init + call _ata_detect + ;; + +#endif // BX_USE_ATADRV + +#if BX_ELTORITO_BOOT + ;; + ;; eltorito floppy/harddisk emulation from cd + ;; + call _cdemu_init + ;; +#endif // BX_ELTORITO_BOOT #ifdef HVMASSIST call _enable_rom_write_access @@ -10109,52 +11017,19 @@ call _init_boot_vectors + mov cx, #0xc800 ;; init option roms + mov ax, #0xe000 call rom_scan - call _print_bios_banner - - ;; - ;; Floppy setup - ;; - call floppy_drive_post - -#if BX_USE_ATADRV - - ;; - ;; Hard Drive setup - ;; - call hard_drive_post - - ;; - ;; ATA/ATAPI driver setup - ;; - call _ata_init - call _ata_detect - ;; -#else // BX_USE_ATADRV - - ;; - ;; Hard Drive setup - ;; - call hard_drive_post - -#endif // BX_USE_ATADRV - -#if BX_ELTORITO_BOOT - ;; - ;; eltorito floppy/harddisk emulation from cd - ;; - call _cdemu_init - ;; +#if BX_ELTORITO_BOOT + call _interactive_bootkey #endif // BX_ELTORITO_BOOT - - call _s3_resume - call _interactive_bootkey #if BX_TCGBIOS call tcpa_post_part2 #endif + sti ;; enable interrupts ;; Start the boot sequence. See the comments in int19_relocated ;; for why we use INT 18h instead of INT 19h here. int #0x18 @@ -10167,7 +11042,7 @@ iret int75_handler: - out 0xf0, al // clear irq13 + out 0xf0, al // clear irq13 call eoi_both_pics // clear interrupt int 2 // legacy nmi call iret @@ -10266,7 +11141,7 @@ int14_handler: push ds pusha - mov ax, #0x0000 + xor ax, ax mov ds, ax call _int14_function popa @@ -10371,26 +11246,7 @@ jz int09_finish in al, #0x60 ;;read key from keyboard controller - //test al, #0x80 ;;look for key release - //jnz int09_process_key ;; dont pass releases to intercept? - - ;; check for extended key - cmp al, #0xe0 - jne int09_call_int15_4f - - push ds - xor ax, ax - mov ds, ax - mov al, BYTE [0x496] ;; mf2_state |= 0x01 - or al, #0x01 - mov BYTE [0x496], al - pop ds - - in al, #0x60 ;;read another key from keyboard controller - sti - -int09_call_int15_4f: push ds pusha #ifdef BX_CALL_INT15_4F @@ -10400,8 +11256,27 @@ jnc int09_done #endif - -//int09_process_key: + ;; check for extended key + cmp al, #0xe0 + jne int09_check_pause + xor ax, ax + mov ds, ax + mov al, BYTE [0x496] ;; mf2_state |= 0x02 + or al, #0x02 + mov BYTE [0x496], al + jmp int09_done + +int09_check_pause: ;; check for pause key + cmp al, #0xe1 + jne int09_process_key + xor ax, ax + mov ds, ax + mov al, BYTE [0x496] ;; mf2_state |= 0x01 + or al, #0x01 + mov BYTE [0x496], al + jmp int09_done + +int09_process_key: mov bx, #0xf000 mov ds, bx call _int09_function @@ -10417,8 +11292,6 @@ out #0x64, al pop ax iret - - ;---------------------------------------- @@ -10459,7 +11332,7 @@ je int0e_loop2 int0e_normal: push ds - mov ax, #0x0000 ;; segment 0000 + xor ax, ax ;; segment 0000 mov ds, ax call eoi_master_pic mov al, 0x043e @@ -10496,7 +11369,7 @@ int17_handler: push ds pusha - mov ax, #0x0000 + xor ax, ax mov ds, ax call _int17_function popa @@ -10686,11 +11559,11 @@ ;; int70_handler: push ds - pusha + pushad xor ax, ax mov ds, ax call _int70_function - popa + popad pop ds iret @@ -10748,7 +11621,7 @@ .org 0xff00 -.ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team." +.ascii BIOS_COPYRIGHT_STRING ;------------------------------------------------ ;- IRET Instruction for Dummy Interrupt Handler - @@ -10770,7 +11643,7 @@ #ifdef HVMTEST jmp 0xd000:0x0003; #else - jmp 0xf000:post + jmp 0xf000:post #endif .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY @@ -10783,10 +11656,10 @@ .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters) ASM_END /* - * This font comes from the fntcol16.zip package (c) by Joseph Gil + * This font comes from the fntcol16.zip package (c) by Joseph Gil * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip * This font is public domain - */ + */ static Bit8u vgafont8[128*8]= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -10962,328 +11835,10 @@ db 0,0,0,0,0,0,0 ; 31 bytes ASM_END -#else // !HVMASSIST - -ASM_START -.org 0xcc00 +#endif // HVMASSIST +ASM_START +.org 0xcff0 +bios_table_area_end: // bcc-generated data will be placed here - -// For documentation of this config structure, look on developer.intel.com and -// search for multiprocessor specification. Note that when you change anything -// you must update the checksum (a pain!). It would be better to construct this -// with C structures, or at least fill in the checksum automatically. -// -// Maybe this structs could be moved elsewhere than d000 - -#if (BX_SMP_PROCESSORS==1) - // no structure necessary. -#elif (BX_SMP_PROCESSORS==2) -// define the Intel MP Configuration Structure for 2 processors at -// APIC ID 0,1. I/O APIC at ID=2. -.align 16 -mp_config_table: - db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature - dw (mp_config_end-mp_config_table) ;; table length - db 4 ;; spec rev - db 0x65 ;; checksum - .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" - db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " - db 0x20, 0x20, 0x20, 0x20 - db 0x20, 0x20, 0x20, 0x20 - dw 0,0 ;; oem table ptr - dw 0 ;; oem table size - dw 20 ;; entry count - dw 0x0000, 0xfee0 ;; memory mapped address of local APIC - dw 0 ;; extended table length - db 0 ;; extended table checksum - db 0 ;; reserved -mp_config_proc0: - db 0 ;; entry type=processor - db 0 ;; local APIC id - db 0x11 ;; local APIC version number - db 3 ;; cpu flags: enabled, bootstrap processor - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc1: - db 0 ;; entry type=processor - db 1 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_isa_bus: - db 1 ;; entry type=bus - db 0 ;; bus ID - db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " -mp_config_ioapic: - db 2 ;; entry type=I/O APIC - db 2 ;; apic id=2. linux will set. - db 0x11 ;; I/O APIC version number - db 1 ;; flags=1=enabled - dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC -mp_config_irqs: - db 3 ;; entry type=I/O interrupt - db 0 ;; interrupt type=vectored interrupt - db 0,0 ;; flags po=0, el=0 (linux uses as default) - db 0 ;; source bus ID is ISA - db 0 ;; source bus IRQ - db 2 ;; destination I/O APIC ID - db 0 ;; destination I/O APIC interrrupt in - ;; repeat pattern for interrupts 0-15 - db 3,0,0,0,0,1,2,1 - db 3,0,0,0,0,2,2,2 - db 3,0,0,0,0,3,2,3 - db 3,0,0,0,0,4,2,4 - db 3,0,0,0,0,5,2,5 - db 3,0,0,0,0,6,2,6 - db 3,0,0,0,0,7,2,7 - db 3,0,0,0,0,8,2,8 - db 3,0,0,0,0,9,2,9 - db 3,0,0,0,0,10,2,10 - db 3,0,0,0,0,11,2,11 - db 3,0,0,0,0,12,2,12 - db 3,0,0,0,0,13,2,13 - db 3,0,0,0,0,14,2,14 - db 3,0,0,0,0,15,2,15 -#elif (BX_SMP_PROCESSORS==4) -// define the Intel MP Configuration Structure for 4 processors at -// APIC ID 0,1,2,3. I/O APIC at ID=4. -.align 16 -mp_config_table: - db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature - dw (mp_config_end-mp_config_table) ;; table length - db 4 ;; spec rev - db 0xdd ;; checksum - .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" - db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " - db 0x20, 0x20, 0x20, 0x20 - db 0x20, 0x20, 0x20, 0x20 - dw 0,0 ;; oem table ptr - dw 0 ;; oem table size - dw 22 ;; entry count - dw 0x0000, 0xfee0 ;; memory mapped address of local APIC - dw 0 ;; extended table length - db 0 ;; extended table checksum - db 0 ;; reserved -mp_config_proc0: - db 0 ;; entry type=processor - db 0 ;; local APIC id - db 0x11 ;; local APIC version number - db 3 ;; cpu flags: enabled, bootstrap processor - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc1: - db 0 ;; entry type=processor - db 1 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc2: - db 0 ;; entry type=processor - db 2 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc3: - db 0 ;; entry type=processor - db 3 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_isa_bus: - db 1 ;; entry type=bus - db 0 ;; bus ID - db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " -mp_config_ioapic: - db 2 ;; entry type=I/O APIC - db 4 ;; apic id=4. linux will set. - db 0x11 ;; I/O APIC version number - db 1 ;; flags=1=enabled - dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC -mp_config_irqs: - db 3 ;; entry type=I/O interrupt - db 0 ;; interrupt type=vectored interrupt - db 0,0 ;; flags po=0, el=0 (linux uses as default) - db 0 ;; source bus ID is ISA - db 0 ;; source bus IRQ - db 4 ;; destination I/O APIC ID - db 0 ;; destination I/O APIC interrrupt in - ;; repeat pattern for interrupts 0-15 - db 3,0,0,0,0,1,4,1 - db 3,0,0,0,0,2,4,2 - db 3,0,0,0,0,3,4,3 - db 3,0,0,0,0,4,4,4 - db 3,0,0,0,0,5,4,5 - db 3,0,0,0,0,6,4,6 - db 3,0,0,0,0,7,4,7 - db 3,0,0,0,0,8,4,8 - db 3,0,0,0,0,9,4,9 - db 3,0,0,0,0,10,4,10 - db 3,0,0,0,0,11,4,11 - db 3,0,0,0,0,12,4,12 - db 3,0,0,0,0,13,4,13 - db 3,0,0,0,0,14,4,14 - db 3,0,0,0,0,15,4,15 -#elif (BX_SMP_PROCESSORS==8) -// define the Intel MP Configuration Structure for 8 processors at -// APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8. -.align 16 -mp_config_table: - db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature - dw (mp_config_end-mp_config_table) ;; table length - db 4 ;; spec rev - db 0xc3 ;; checksum - .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" - db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " - db 0x20, 0x20, 0x20, 0x20 - db 0x20, 0x20, 0x20, 0x20 - dw 0,0 ;; oem table ptr - dw 0 ;; oem table size - dw 26 ;; entry count - dw 0x0000, 0xfee0 ;; memory mapped address of local APIC - dw 0 ;; extended table length - db 0 ;; extended table checksum - db 0 ;; reserved -mp_config_proc0: - db 0 ;; entry type=processor - db 0 ;; local APIC id - db 0x11 ;; local APIC version number - db 3 ;; cpu flags: enabled, bootstrap processor - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc1: - db 0 ;; entry type=processor - db 1 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc2: - db 0 ;; entry type=processor - db 2 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc3: - db 0 ;; entry type=processor - db 3 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc4: - db 0 ;; entry type=processor - db 4 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc5: - db 0 ;; entry type=processor - db 5 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc6: - db 0 ;; entry type=processor - db 6 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc7: - db 0 ;; entry type=processor - db 7 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_isa_bus: - db 1 ;; entry type=bus - db 0 ;; bus ID - db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " -mp_config_ioapic: - db 2 ;; entry type=I/O APIC - db 8 ;; apic id=8 - db 0x11 ;; I/O APIC version number - db 1 ;; flags=1=enabled - dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC -mp_config_irqs: - db 3 ;; entry type=I/O interrupt - db 0 ;; interrupt type=vectored interrupt - db 0,0 ;; flags po=0, el=0 (linux uses as default) - db 0 ;; source bus ID is ISA - db 0 ;; source bus IRQ - db 8 ;; destination I/O APIC ID - db 0 ;; destination I/O APIC interrrupt in - ;; repeat pattern for interrupts 0-15 - db 3,0,0,0,0,1,8,1 - db 3,0,0,0,0,2,8,2 - db 3,0,0,0,0,3,8,3 - db 3,0,0,0,0,4,8,4 - db 3,0,0,0,0,5,8,5 - db 3,0,0,0,0,6,8,6 - db 3,0,0,0,0,7,8,7 - db 3,0,0,0,0,8,8,8 - db 3,0,0,0,0,9,8,9 - db 3,0,0,0,0,10,8,10 - db 3,0,0,0,0,11,8,11 - db 3,0,0,0,0,12,8,12 - db 3,0,0,0,0,13,8,13 - db 3,0,0,0,0,14,8,14 - db 3,0,0,0,0,15,8,15 -#else -# error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors. -#endif // if (BX_SMP_PROCESSORS==...) - -mp_config_end: // this label used to find length of mp structure - db 0 - -#if (BX_SMP_PROCESSORS>1) -.align 16 -mp_floating_pointer_structure: -db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature -dw mp_config_table, 0xf ;; pointer to MP configuration table -db 1 ;; length of this struct in 16-bit byte chunks -db 4 ;; MP spec revision -db 0xc1 ;; checksum -db 0 ;; MP feature byte 1. value 0 means look at the config table -db 0,0,0,0 ;; MP feature bytes 2-5. -#endif - -ASM_END - -#endif // HVMASSIST +ASM_END + diff -r a76b4e00e186 tools/firmware/rombios/rombios.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/firmware/rombios/rombios.h Wed Dec 17 23:38:15 2008 +0900 @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: rombios.h,v 1.8 2008/12/04 18:48:33 sshwarts Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2006 Volker Ruppert +// +// This library is free software; you can redistribute it and/or +// 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 + +/* define it to include QEMU specific code */ +//#define BX_QEMU +#define LEGACY + +#ifndef LEGACY +# define BX_ROMBIOS32 1 +#else +# define BX_ROMBIOS32 0 +#endif +#define DEBUG_ROMBIOS 1 + +#define PANIC_PORT 0x400 +#define PANIC_PORT2 0x401 +#define INFO_PORT 0x402 +#define DEBUG_PORT 0x403 + +#define BIOS_PRINTF_HALT 1 +#define BIOS_PRINTF_SCREEN 2 +#define BIOS_PRINTF_INFO 4 +#define BIOS_PRINTF_DEBUG 8 +#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO) +#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT) + +#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p) + +// 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 +# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) +#else +# define BX_DEBUG(format, p...) +#endif +#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) +#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p) + +#define ACPI_DATA_SIZE 0x00010000L +#define PM_IO_BASE 0xb000 +#define SMB_IO_BASE 0xb100 + + // Define the application NAME +#if define HVMASSIST +# define BX_APPNAME "HVMAssist" +#elif defined(BX_QEMU) +# define BX_APPNAME "QEMU" +#elif defined(PLEX86) +# define BX_APPNAME "Plex86" +#else +# define BX_APPNAME "Bochs" +#endif _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |