Index: /trunk/src/VBox/Devices/PC/BIOS-new/ata.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/ata.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/ata.c	(revision 38699)
@@ -0,0 +1,1083 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include <stdarg.h>
+#include "inlines.h"
+#include "biosint.h"
+#include "ebda.h"
+#include "ata.h"
+
+#if DEBUG_ATA
+#  define BX_DEBUG_ATA(...) BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_ATA(...)
+#endif
+
+
+// ---------------------------------------------------------------------------
+// Start of ATA/ATAPI Driver
+// ---------------------------------------------------------------------------
+
+void insw_discard(unsigned nwords, unsigned port);
+#pragma aux insw_discard =  \
+    ".286"                  \
+    "again:"                \
+    "in ax,dx"              \
+    "loop again"            \
+    parm [cx] [dx] modify exact [cx ax] nomemory;
+
+void insd_discard(unsigned ndwords, unsigned port);
+#pragma aux insd_discard =  \
+    ".386"                  \
+    "push eax"              \
+    "again:"                \
+    "in eax,dx"             \
+    "loop again"            \
+    "pop eax"               \
+    parm [cx] [dx] modify exact [cx] nomemory;
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : initialization
+// ---------------------------------------------------------------------------
+void BIOSCALL ata_init(void)
+{
+    uint16_t        ebda_seg=read_word(0x0040,0x000E);
+    uint8_t         channel, device;
+    ata_t __far     *AtaData;
+    
+    AtaData = ebda_seg :> &EbdaData->ata;
+    
+    // Channels info init.
+    for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
+        AtaData->channels[channel].iface   = ATA_IFACE_NONE;
+        AtaData->channels[channel].iobase1 = 0x0;
+        AtaData->channels[channel].iobase2 = 0x0;
+        AtaData->channels[channel].irq     = 0;
+    }
+    
+    // Devices info init.
+    for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
+        AtaData->devices[device].type        = ATA_TYPE_NONE;
+        AtaData->devices[device].device      = ATA_DEVICE_NONE;
+        AtaData->devices[device].removable   = 0;
+        AtaData->devices[device].lock        = 0;
+        AtaData->devices[device].mode        = ATA_MODE_NONE;
+        AtaData->devices[device].blksize     = 0x200;
+        AtaData->devices[device].translation = ATA_TRANSLATION_NONE;
+        AtaData->devices[device].lchs.heads     = 0;
+        AtaData->devices[device].lchs.cylinders = 0;
+        AtaData->devices[device].lchs.spt       = 0;
+        AtaData->devices[device].pchs.heads     = 0;
+        AtaData->devices[device].pchs.cylinders = 0;
+        AtaData->devices[device].pchs.spt       = 0;
+        AtaData->devices[device].sectors     = 0;
+    }
+    
+    // hdidmap  and cdidmap init.
+    for (device=0; device<BX_MAX_STORAGE_DEVICES; device++) {
+        AtaData->hdidmap[device] = BX_MAX_STORAGE_DEVICES;
+        AtaData->cdidmap[device] = BX_MAX_STORAGE_DEVICES;
+    }
+    
+    AtaData->hdcount = 0;
+    AtaData->cdcount = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : software reset
+// ---------------------------------------------------------------------------
+// ATA-3
+// 8.2.1 Software reset - Device 0
+
+void   ata_reset(uint16_t device)
+{
+    uint16_t        ebda_seg = read_word(0x0040,0x000E);
+    uint16_t        iobase1, iobase2;
+    uint8_t         channel, slave, sn, sc;
+    uint16_t        max;
+    uint16_t        pdelay;
+    ata_t __far     *AtaData;
+    
+    AtaData = ebda_seg :> &EbdaData->ata;
+    channel = device / 2;
+    slave = device % 2;
+    
+    iobase1 = AtaData->channels[channel].iobase1;
+    iobase2 = AtaData->channels[channel].iobase2;
+
+    // Reset
+
+    // 8.2.1 (a) -- set SRST in DC
+    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) {
+        uint8_t status = inb(iobase1+ATA_CB_STAT);
+        if ((status & ATA_CB_STAT_BSY) != 0)
+            break;
+    }
+
+    // 8.2.1 (f) -- clear SRST
+    outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+    if (AtaData->devices[device].type != ATA_TYPE_NONE) {
+        // 8.2.1 (g) -- check for sc==sn==0x01
+        // select device
+        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) ) {
+            // 8.2.1 (h) -- wait for not BSY
+            max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
+            while(--max>0) {
+                uint8_t status = inb(iobase1+ATA_CB_STAT);
+                if ((status & ATA_CB_STAT_BSY) == 0)
+                    break;
+                pdelay=0xffff;
+                while (--pdelay>0) {
+                    /* nothing */
+                }
+            }
+        }
+    }
+
+    // 8.2.1 (i) -- wait for DRDY
+    max = 0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
+    while(--max>0) {
+        uint8_t status = inb(iobase1+ATA_CB_STAT);
+        if ((status & ATA_CB_STAT_RDY) != 0) 
+            break;
+    }
+    
+    // Enable interrupts
+    outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a data-in command
+// ---------------------------------------------------------------------------
+      // returns
+      // 0 : no error
+      // 1 : BUSY bit set
+      // 2 : read error
+      // 3 : expected DRQ=1
+      // 4 : no sectors left to read/verify
+      // 5 : more sectors to read/verify
+      // 6 : no sectors left to write
+      // 7 : more sectors to write
+uint16_t ata_cmd_data_in(uint16_t device, uint16_t command, uint16_t count, uint16_t cylinder, 
+                         uint16_t head, uint16_t sector, uint32_t lba, char __far *buffer)
+{
+    uint16_t        ebda_seg = read_word(0x0040,0x000E);
+    uint16_t        iobase1, iobase2, blksize, mult_blk_cnt;
+    uint8_t         channel, slave;
+    uint8_t         status, current, mode;
+    ata_t __far     *AtaData;
+    
+    AtaData = ebda_seg :> &EbdaData->ata;
+    
+    channel = device / 2;
+    slave   = device % 2;
+    
+    iobase1 = AtaData->channels[channel].iobase1;
+    iobase2 = AtaData->channels[channel].iobase2;
+    mode    = AtaData->devices[device].mode;
+    blksize = AtaData->devices[device].blksize;
+    if (blksize == 0) {   /* If transfer size is exactly 64K */
+        if (mode == ATA_MODE_PIO32)
+            blksize = 0x4000;
+        else
+            blksize = 0x8000;
+    } else {
+        if (mode == ATA_MODE_PIO32)
+            blksize >>= 2;
+        else
+            blksize >>= 1;
+    }
+    
+    status = inb(iobase1 + ATA_CB_STAT);
+    if (status & ATA_CB_STAT_BSY)
+    {
+        BX_DEBUG_ATA("%s: disk busy\n", __func__);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 1;
+    }
+    
+    // sector will be 0 only on lba access. Convert to lba-chs
+    if (sector == 0) {
+        if (lba + count >= 268435456)
+        {
+            sector = (lba & 0xff000000L) >> 24;
+            cylinder = 0; /* The parameter lba is just a 32 bit value. */
+            outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
+            outb(iobase1 + ATA_CB_SN, sector);
+            outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+            outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+            /* Leave the bottom 24 bits as is, they are treated correctly by the
+            * LBA28 code path. */
+            lba &= 0xffffff;
+        }
+        sector = (uint16_t) (lba & 0x000000ffL);
+        lba >>= 8;
+        cylinder = (uint16_t) (lba & 0x0000ffffL);
+        lba >>= 16;
+        head = ((uint16_t) (lba & 0x0000000fL)) | 0x40;
+    }
+    
+    // Reset count of transferred data
+    AtaData->trsfsectors = 0;
+    AtaData->trsfbytes   = 0;
+    current = 0;
+    
+    outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+    outb(iobase1 + ATA_CB_FR, 0x00);
+    outb(iobase1 + ATA_CB_SC, count);
+    outb(iobase1 + ATA_CB_SN, sector);
+    outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+    outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+    outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (uint8_t) head );
+    outb(iobase1 + ATA_CB_CMD, command);
+    
+    if (command == ATA_CMD_READ_MULTIPLE || command == ATA_CMD_READ_MULTIPLE_EXT) {
+        mult_blk_cnt = count;
+        count = 1;
+    } else {
+        mult_blk_cnt = 1;
+    }
+    
+    while (1) {
+        status = inb(iobase1 + ATA_CB_STAT);
+        if ( !(status & ATA_CB_STAT_BSY) )
+            break;
+    }
+    
+    if (status & ATA_CB_STAT_ERR) {
+        BX_DEBUG_ATA("%s: read error\n", __func__);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 2;
+    } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+        BX_DEBUG_ATA("%s: DRQ not set (status %02x)\n", __func__, (unsigned) status);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 3;
+    }
+    
+    // FIXME : move seg/off translation here
+    
+    int_enable(); // enable higher priority interrupts
+    
+    while (1) {
+    
+        // adjust if there will be an overrun. 2K max sector size
+        if (FP_OFF(buffer) >= 0xF800)
+            buffer = MK_FP(FP_SEG(buffer) + 0x80, FP_OFF(buffer) - 0x800);
+        
+        if (mode == ATA_MODE_PIO32) {
+            buffer = rep_insd(buffer, blksize, iobase1);
+        } else {
+            buffer = rep_insw(buffer, blksize, iobase1);
+        }
+        current += mult_blk_cnt;
+        AtaData->trsfsectors = current;
+        count--;
+        while (1) {
+            status = inb(iobase1 + ATA_CB_STAT);
+            if ( !(status & ATA_CB_STAT_BSY) )
+                break;
+        }
+        if (count == 0) {
+            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("%s: no sectors left (status %02x)\n", __func__, (unsigned) status);
+                // Enable interrupts
+                outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+                return 4;
+            }
+            break;
+        }
+        else {
+            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("%s: more sectors left (status %02x)\n", __func__, (unsigned) status);
+                // Enable interrupts
+                outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+                return 5;
+            }
+            continue;
+        }
+    }
+    // Enable interrupts
+    outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+    return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : device detection
+// ---------------------------------------------------------------------------
+
+void BIOSCALL ata_detect(void)
+{
+    uint16_t        ebda_seg = read_word(0x0040,0x000E);
+    uint8_t         hdcount, cdcount, device, type;
+    uint8_t         buffer[0x0200];
+    ata_t __far     *AtaData;
+    
+    AtaData = ebda_seg :> &EbdaData->ata;
+
+#if BX_MAX_ATA_INTERFACES > 0
+    AtaData->channels[0].iface   = ATA_IFACE_ISA;
+    AtaData->channels[0].iobase1 = 0x1f0;
+    AtaData->channels[0].iobase2 = 0x3f0;
+    AtaData->channels[0].irq     = 14;
+#endif
+#if BX_MAX_ATA_INTERFACES > 1
+    AtaData->channels[1].iface   = ATA_IFACE_ISA;
+    AtaData->channels[1].iobase1 = 0x170;
+    AtaData->channels[1].iobase2 = 0x370;
+    AtaData->channels[1].irq     = 15;
+#endif
+#if BX_MAX_ATA_INTERFACES > 2
+    AtaData->channels[2].iface   = ATA_IFACE_ISA;
+    AtaData->channels[2].iobase1 = 0x1e8;
+    AtaData->channels[2].iobase2 = 0x3e0;
+    AtaData->channels[2].irq     = 12;
+#endif
+#if BX_MAX_ATA_INTERFACES > 3
+    AtaData->channels[3].iface   = ATA_IFACE_ISA;
+    AtaData->channels[3].iobase1 = 0x168;
+    AtaData->channels[3].iobase2 = 0x360;
+    AtaData->channels[3].irq     = 11;
+#endif
+#if BX_MAX_ATA_INTERFACES > 4
+#error Please fill the ATA interface informations
+#endif
+
+    // Device detection
+    hdcount = cdcount = 0;
+
+    for (device = 0; device < BX_MAX_ATA_DEVICES; device++) {
+        uint16_t    iobase1, iobase2;
+        uint8_t     channel, slave;
+        uint8_t     sc, sn, cl, ch, st;
+        
+        channel = device / 2;
+        slave = device % 2;
+        
+        iobase1 = AtaData->channels[channel].iobase1;
+        iobase2 = AtaData->channels[channel].iobase2;
+        
+        // Disable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+        
+        // Look for device
+        outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
+        outb(iobase1+ATA_CB_SC, 0x55);
+        outb(iobase1+ATA_CB_SN, 0xaa);
+        outb(iobase1+ATA_CB_SC, 0xaa);
+        outb(iobase1+ATA_CB_SN, 0x55);
+        outb(iobase1+ATA_CB_SC, 0x55);
+        outb(iobase1+ATA_CB_SN, 0xaa);
+        
+        // If we found something
+        sc = inb(iobase1+ATA_CB_SC);
+        sn = inb(iobase1+ATA_CB_SN);
+
+        if ( (sc == 0x55) && (sn == 0xaa) ) {
+            AtaData->devices[device].type = ATA_TYPE_UNKNOWN;
+
+            // reset the channel
+            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)) {
+                cl = inb(iobase1+ATA_CB_CL);
+                ch = inb(iobase1+ATA_CB_CH);
+                st = inb(iobase1+ATA_CB_STAT);
+
+                if ((cl==0x14) && (ch==0xeb)) {
+                    AtaData->devices[device].type = ATA_TYPE_ATAPI;
+                } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
+                    AtaData->devices[device].type = ATA_TYPE_ATA;
+                } else if ((cl==0xff) && (ch==0xff)) {
+                    AtaData->devices[device].type = ATA_TYPE_NONE;
+                }
+            }
+        }
+
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+
+        type = AtaData->devices[device].type;
+
+        // Now we send a IDENTIFY command to ATA device
+        if (type == ATA_TYPE_ATA) {
+            uint32_t    sectors;
+            uint16_t    cylinders, heads, spt, blksize;
+            uint16_t    lcylinders, lheads, lspt;
+            uint8_t     chsgeo_base;
+            uint8_t     removable, mode;
+
+            //Temporary values to do the transfer
+            AtaData->devices[device].device = ATA_DEVICE_HD;
+            AtaData->devices[device].mode   = ATA_MODE_PIO16;
+
+            if (ata_cmd_data_in(device, ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, buffer) !=0 )
+                BX_PANIC("ata-detect: Failed to detect ATA device\n");
+
+            removable = (*(buffer+0) & 0x80) ? 1 : 0;
+            mode      = *(buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+            blksize   = 512;  /* There is no sector size field any more. */
+
+            cylinders = *(uint16_t *)(buffer+(1*2)); // word 1
+            heads     = *(uint16_t *)(buffer+(3*2)); // word 3
+            spt       = *(uint16_t *)(buffer+(6*2)); // word 6
+
+            sectors   = *(uint32_t *)(buffer+(60*2)); // word 60 and word 61
+            /** @todo update sectors to be a 64 bit number (also lba...). */
+            if (sectors == 268435455)
+                sectors = *(uint32_t *)(buffer+(100*2)); // words 100 to 103 (someday)
+            switch (device)
+            {
+            case 0:
+                chsgeo_base = 0x1e;
+                break;
+            case 1:
+                chsgeo_base = 0x26;
+                break;
+            case 2:
+                chsgeo_base = 0x67;
+                break;
+            case 3:
+                chsgeo_base = 0x70;
+                break;
+            case 4:
+                chsgeo_base = 0x40;
+                break;
+            case 5:
+                chsgeo_base = 0x48;
+                break;
+            case 6:
+                chsgeo_base = 0x50;
+                break;
+            case 7:
+                chsgeo_base = 0x58;
+                break;
+            default:
+                chsgeo_base = 0;
+            }
+            if (chsgeo_base != 0)
+            {
+                lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
+                lheads = inb_cmos(chsgeo_base+2);
+                lspt = inb_cmos(chsgeo_base+7);
+            }
+            else
+            {
+                lcylinders = 0;
+                lheads = 0;
+                lspt = 0;
+            }
+            BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave,
+                    cylinders,heads, spt, lcylinders, lheads, lspt);
+
+            AtaData->devices[device].device         = ATA_DEVICE_HD;
+            AtaData->devices[device].removable      = removable;
+            AtaData->devices[device].mode           = mode;
+            AtaData->devices[device].blksize        = blksize;
+            AtaData->devices[device].pchs.heads     = heads;
+            AtaData->devices[device].pchs.cylinders = cylinders;
+            AtaData->devices[device].pchs.spt       = spt;
+            AtaData->devices[device].sectors        = sectors;
+            AtaData->devices[device].lchs.heads     = lheads;
+            AtaData->devices[device].lchs.cylinders = lcylinders;
+            AtaData->devices[device].lchs.spt       = lspt;
+            if (device < 2)
+            {
+                uint8_t         sum, i;
+                fdpt_t __far    *fdpt;
+
+                if (device == 0)
+                    fdpt = ebda_seg :> &EbdaData->fdpt0;
+                else
+                    fdpt = ebda_seg :> &EbdaData->fdpt1;
+
+                /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
+                 * to be done at POST time with lots of ugly assembler code, which
+                 * isn't worth the effort of converting from AMI to Award CMOS
+                 * format. Just do it here. */
+                fdpt->lcyl  = lcylinders;
+                fdpt->lhead = lheads;
+                fdpt->sig   = 0xa0;
+                fdpt->spt   = spt;
+                fdpt->cyl   = cylinders;
+                fdpt->head  = heads;
+                fdpt->lspt  = spt;
+                sum = 0;
+                for (i = 0; i < 0xf; i++)
+                    sum += *((uint8_t __far *)fdpt + i);
+                sum = -sum;
+                fdpt->csum = sum;
+            }
+
+            // fill hdidmap
+            AtaData->hdidmap[hdcount] = device;
+            hdcount++;
+        }
+
+        // Now we send an IDENTIFY command to ATAPI device
+        if (type == ATA_TYPE_ATAPI) {
+            uint8_t     type, removable, mode;
+            uint16_t    blksize;
+
+            // Temporary values to do the transfer
+            AtaData->devices[device].device = ATA_DEVICE_CDROM;
+            AtaData->devices[device].mode   = ATA_MODE_PIO16;
+
+            if (ata_cmd_data_in(device, ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, buffer) != 0)
+                BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
+
+            type      = *(buffer+1) & 0x1f;
+            removable = (*(buffer+0) & 0x80) ? 1 : 0;
+            mode      = *(buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+            blksize   = 2048;
+
+            AtaData->devices[device].device    = type;
+            AtaData->devices[device].removable = removable;
+            AtaData->devices[device].mode      = mode;
+            AtaData->devices[device].blksize   = blksize;
+
+            // fill cdidmap
+            AtaData->cdidmap[cdcount] = device;
+            cdcount++;
+        }
+
+        {
+            uint32_t    sizeinmb;
+            uint16_t    ataversion;
+            uint8_t     version, model[41];
+            int         i;
+
+            switch (type) {
+            case ATA_TYPE_ATA:
+                sizeinmb = AtaData->devices[device].sectors;
+                sizeinmb >>= 11;
+            case ATA_TYPE_ATAPI:
+                // Read ATA/ATAPI version
+                ataversion = ((uint16_t)(*(buffer+161))<<8) | *(buffer+160);
+                for (version = 15; version > 0; version--) {
+                    if ((ataversion & (1 << version)) !=0 )
+                        break;
+                }
+
+                // Read model name
+                for (i = 0; i < 20; i++ ) {
+                    *(model+(i*2))   = *(buffer+(i*2)+54+1);
+                    *(model+(i*2)+1) = *(buffer+(i*2)+54);
+                }
+
+                // Reformat
+                *(model+40) = 0x00;
+                for ( i = 39; i > 0; i-- ){
+                    if (*(model+i) == 0x20)
+                        *(model+i) = 0x00;
+                    else 
+                        break;
+                }
+                break;
+            }
+
+#ifdef VBOXz
+            // we don't want any noisy output for now
+#else /* !VBOX */
+            switch (type) {
+            int c;
+            case ATA_TYPE_ATA:
+                printf("ata%d %s: ", channel, slave ? " slave" : "master");
+                i=0;
+                while(c=*(model+i++))
+                    printf("%c", c);
+                printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
+                break;
+            case ATA_TYPE_ATAPI:
+                printf("ata%d %s: ", channel, slave ? " slave" : "master");
+                i=0;
+                while(c=*(model+i++))
+                    printf("%c", c);
+                if (AtaData->devices[device].device == ATA_DEVICE_CDROM)
+                    printf(" ATAPI-%d CD-ROM/DVD-ROM\n", version);
+                else
+                    printf(" ATAPI-%d Device\n", version);
+                break;
+            case ATA_TYPE_UNKNOWN:
+                printf("ata%d %s: Unknown device\n", channel , slave ? " slave" : "master");
+                break;
+            }
+#endif /* !VBOX */
+        }
+    }
+
+    // Store the devices counts
+    AtaData->hdcount = hdcount;
+    AtaData->cdcount = cdcount;
+    write_byte(0x40,0x75, hdcount);
+
+#ifdef VBOX
+      // we don't want any noisy output for now
+#else /* !VBOX */
+  printf("\n");
+#endif /* !VBOX */
+
+    // FIXME : should use bios=cmos|auto|disable bits
+    // FIXME : should know about translation bits
+    // FIXME : move hard_drive_post here
+
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a data-out command
+// ---------------------------------------------------------------------------
+      // returns
+      // 0 : no error
+      // 1 : BUSY bit set
+      // 2 : read error
+      // 3 : expected DRQ=1
+      // 4 : no sectors left to read/verify
+      // 5 : more sectors to read/verify
+      // 6 : no sectors left to write
+      // 7 : more sectors to write
+uint16_t ata_cmd_data_out(uint16_t device, uint16_t command, uint16_t count, uint16_t cylinder, 
+                          uint16_t head, uint16_t sector, uint32_t lba, char __far *buffer)
+{
+    uint16_t    ebda_seg = read_word(0x0040,0x000E);
+    uint16_t    iobase1, iobase2, blksize;
+    uint8_t     channel, slave;
+    uint8_t     status, current, mode;
+    ata_t __far *AtaData;
+    
+    AtaData = ebda_seg :> &EbdaData->ata;
+    
+    channel = device / 2;
+    slave   = device % 2;
+    
+    iobase1 = AtaData->channels[channel].iobase1;
+    iobase2 = AtaData->channels[channel].iobase2;
+    mode    = AtaData->devices[device].mode;
+    blksize = 0x200; // was = AtaData->devices[device].blksize;
+    if (mode == ATA_MODE_PIO32)
+        blksize >>= 2;
+    else
+        blksize >>= 1;
+    
+    status = inb(iobase1 + ATA_CB_STAT);
+    if (status & ATA_CB_STAT_BSY)
+    {
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 1;
+    }
+    
+    // sector will be 0 only on lba access. Convert to lba-chs
+    if (sector == 0) {
+        if (lba + count >= 268435456)
+        {
+            sector = (lba & 0xff000000L) >> 24;
+            cylinder = 0; /* The parameter lba is just a 32 bit value. */
+            outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
+            outb(iobase1 + ATA_CB_SN, sector);
+            outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+            outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+            /* Leave the bottom 24 bits as is, they are treated correctly by the
+            * LBA28 code path. */
+            lba &= 0xffffff;
+        }
+        sector = (uint16_t) (lba & 0x000000ffL);
+        lba >>= 8;
+        cylinder = (uint16_t) (lba & 0x0000ffffL);
+        lba >>= 16;
+        head = ((uint16_t) (lba & 0x0000000fL)) | 0x40;
+    }
+    
+    // Reset count of transferred data
+    AtaData->trsfsectors = 0;
+    AtaData->trsfbytes   = 0;
+    current = 0;
+    
+    outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+    outb(iobase1 + ATA_CB_FR, 0x00);
+    outb(iobase1 + ATA_CB_SC, count);
+    outb(iobase1 + ATA_CB_SN, sector);
+    outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+    outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+    outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (uint8_t) head );
+    outb(iobase1 + ATA_CB_CMD, command);
+    
+    while (1) {
+        status = inb(iobase1 + ATA_CB_STAT);
+        if ( !(status & ATA_CB_STAT_BSY) )
+            break;
+    }
+    
+    if (status & ATA_CB_STAT_ERR) {
+        BX_DEBUG_ATA("%s: read error\n", __func__);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 2;
+    } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+        BX_DEBUG_ATA("%s: DRQ not set (status %02x)\n", __func__, (unsigned) status);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 3;
+    }
+    
+    // FIXME : move seg/off translation here
+    
+    int_enable(); // enable higher priority interrupts
+    
+    while (1) {
+    
+        // adjust if there will be an overrun. 2K max sector size
+        if (FP_OFF(buffer) >= 0xF800)
+            buffer = MK_FP(FP_SEG(buffer) + 0x80, FP_OFF(buffer) - 0x800);
+        
+        if (mode == ATA_MODE_PIO32) {
+            buffer = rep_outsd(buffer, blksize, iobase1);
+        } else {
+            buffer = rep_outsw(buffer, blksize, iobase1);
+        }
+        
+        current++;
+        AtaData->trsfsectors = current;
+        count--;
+        while (1) {
+            status = inb(iobase1 + ATA_CB_STAT);
+            if ( !(status & ATA_CB_STAT_BSY) )
+                break;
+        }
+        if (count == 0) {
+            if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+              != ATA_CB_STAT_RDY ) {
+                BX_DEBUG_ATA("%s: no sectors left (status %02x)\n", __func__, (unsigned) status);
+                // Enable interrupts
+                outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+                return 6;
+            }
+            break;
+        }
+        else {
+            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("%s: more sectors left (status %02x)\n", __func__, (unsigned) status);
+                // Enable interrupts
+                outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+                return 7;
+            }
+            continue;
+        }
+    }
+    // Enable interrupts
+    outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+    return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a packet command
+// ---------------------------------------------------------------------------
+      // returns
+      // 0 : no error
+      // 1 : error in parameters
+      // 2 : BUSY bit set
+      // 3 : error
+      // 4 : not ready
+uint16_t ata_cmd_packet(uint16_t device, uint8_t cmdlen, char __far *cmdbuf, 
+                        uint16_t header, uint32_t length, uint8_t inout, char __far *buffer)
+{
+    uint16_t    ebda_seg = read_word(0x0040,0x000E);
+    uint16_t    iobase1, iobase2;
+    uint16_t    lcount, lbefore, lafter, count;
+    uint8_t     channel, slave;
+    uint8_t     status, mode, lmode;
+    uint32_t    transfer;
+    ata_t __far *AtaData;
+
+    AtaData = ebda_seg :> &EbdaData->ata;
+
+    channel = device / 2;
+    slave = device % 2;
+
+    // Data out is not supported yet
+    if (inout == ATA_DATA_OUT) {
+        BX_INFO("%s: DATA_OUT not supported yet\n", __func__);
+        return 1;
+    }
+    
+    // The header length must be even
+    if (header & 1) {
+        BX_DEBUG_ATA("%s: header must be even (%04x)\n", __func__, header);
+        return 1;
+    }
+    
+    iobase1  = AtaData->channels[channel].iobase1;
+    iobase2  = AtaData->channels[channel].iobase2;
+    mode     = AtaData->devices[device].mode;
+    transfer = 0L;
+    
+    if (cmdlen < 12)
+        cmdlen = 12;
+    if (cmdlen > 12)
+        cmdlen = 16;
+    cmdlen >>= 1;
+    
+    // Reset count of transferred data
+    AtaData->trsfsectors = 0;
+    AtaData->trsfbytes   = 0;
+    
+    status = inb(iobase1 + ATA_CB_STAT);
+    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_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;
+    }
+    
+    if (status & ATA_CB_STAT_ERR) {
+        BX_DEBUG_ATA("%s: error, status is %02x\n", __func__, status);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 3;
+    } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+        BX_DEBUG_ATA("%s: DRQ not set (status %02x)\n", __func__, (unsigned) status);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 4;
+    }
+    
+    int_enable(); // enable higher priority interrupts
+    
+    // Normalize address
+    BX_DEBUG_ATA("acp1 buffer ptr: %04x:%04x wlen %04x\n", FP_SEG(cmdbuf), FP_OFF(cmdbuf), cmdlen);
+    cmdbuf = MK_FP(FP_SEG(cmdbuf) + FP_OFF(cmdbuf) / 16 , FP_OFF(cmdbuf) % 16);
+    //  cmdseg += (cmdoff / 16);
+    //  cmdoff %= 16;
+    
+    // Send command to device
+    rep_outsw(cmdbuf, cmdlen, iobase1);
+    
+    if (inout == ATA_DATA_NO) {
+        status = inb(iobase1 + ATA_CB_STAT);
+    }
+    else {
+        while (1) {
+        
+            while (1) {
+                status = inb(iobase1 + ATA_CB_STAT);
+                if ( !(status & ATA_CB_STAT_BSY) ) 
+                    break;
+            }
+            
+            // Check if command completed
+            if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 )
+                break;
+            
+            if (status & ATA_CB_STAT_ERR) {
+                BX_DEBUG_ATA("%s: error (status %02x)\n", __func__, status);
+                // Enable interrupts
+                outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+                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("%s: not ready (status %02x)\n", __func__, status);
+                // Enable interrupts
+                outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+                return 4;
+            }
+            
+            // Normalize address
+            BX_DEBUG_ATA("acp2 buffer ptr: %04x:%04x\n", FP_SEG(buffer), FP_OFF(buffer));
+            buffer = MK_FP(FP_SEG(buffer) + FP_OFF(buffer) / 16 , FP_OFF(buffer) % 16);
+            //      bufseg += (bufoff / 16);
+            //      bufoff %= 16;
+            
+            // Get the byte count
+            lcount =  ((uint16_t)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
+            
+            // adjust to read what we want
+            if (header>lcount) {
+                lbefore = lcount;
+                header -= lcount;
+                lcount  = 0;
+            }
+            else {
+                lbefore = header;
+                header  = 0;
+                lcount -= lbefore;
+            }
+            
+            if (lcount>length) {
+                lafter = lcount - length;
+                lcount = length;
+                length = 0;
+            }
+            else {
+                lafter  = 0;
+                length -= lcount;
+            }
+            
+            // Save byte count
+            count = lcount;
+            
+            BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
+            BX_DEBUG_ATA("to 0x%04x:0x%04x\n",FP_SEG(buffer),FP_OFF(buffer));
+            
+            // If counts not dividable by 4, use 16bits mode
+            lmode = mode;
+            if (lbefore & 0x03)
+                lmode = ATA_MODE_PIO16;
+            if (lcount  & 0x03)
+                lmode = ATA_MODE_PIO16;
+            if (lafter  & 0x03)
+                lmode = ATA_MODE_PIO16;
+            
+            // adds an extra byte if count are odd. before is always even
+            if (lcount & 0x01) {
+                lcount += 1;
+                if ((lafter > 0) && (lafter & 0x01)) {
+                    lafter -= 1;
+                }
+            }
+            
+            if (lmode == ATA_MODE_PIO32) {
+                lcount  >>= 2;
+                lbefore >>= 2;
+                lafter  >>= 2;
+            }
+            else {
+                lcount  >>= 1;
+                lbefore >>= 1;
+                lafter  >>= 1;
+            }
+            
+            if (lmode == ATA_MODE_PIO32) {
+                if (lbefore)
+                    insd_discard(lbefore, iobase1);
+                rep_insd(buffer, lcount, iobase1);
+                if (lafter)
+                    insd_discard(lafter, iobase1);
+            } else {
+                if (lbefore)
+                    insw_discard(lbefore, iobase1);
+                rep_insw(buffer, lcount, iobase1);
+                if (lafter)
+                    insw_discard(lafter, iobase1);
+            }
+            
+            
+            // Compute new buffer address
+            buffer += count;
+            
+            // Save transferred bytes count
+            transfer += count;
+            AtaData->trsfbytes = transfer;
+        }
+    }
+    
+    // Final check, device must be ready
+    if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+      != ATA_CB_STAT_RDY ) {
+        BX_DEBUG_ATA("%s: not ready (status %02x)\n", __func__, (unsigned) status);
+        // Enable interrupts
+        outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+        return 4;
+    }
+    
+    // Enable interrupts
+    outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+    return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// End of ATA/ATAPI Driver
+// ---------------------------------------------------------------------------
+
+uint16_t atapi_is_cdrom(uint8_t device)
+{
+    uint16_t        ebda_seg = read_word(0x0040,0x000E);
+    ata_t __far     *AtaData;
+    
+    AtaData = ebda_seg :> &EbdaData->ata;
+    
+    if (device >= BX_MAX_ATA_DEVICES)
+        return 0;
+    
+    if (AtaData->devices[device].type != ATA_TYPE_ATAPI)
+        return 0;
+    
+    if (AtaData->devices[device].device != ATA_DEVICE_CDROM)
+        return 0;
+    
+    return 1;
+}
+
+// ---------------------------------------------------------------------------
+// End of ATA/ATAPI generic functions
+// ---------------------------------------------------------------------------
Index: /trunk/src/VBox/Devices/PC/BIOS-new/ata.h
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/ata.h	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/ata.h	(revision 38699)
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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 ATA_DATA_NO      0x00
+#define ATA_DATA_IN      0x01
+#define ATA_DATA_OUT     0x02
+
+#define ATA_TRANSLATION_NONE  0
+#define ATA_TRANSLATION_LBA   1
+#define ATA_TRANSLATION_LARGE 2
+#define ATA_TRANSLATION_RECHS 3
+
+#define ATA_IFACE_NONE    0x00
+#define ATA_IFACE_ISA     0x00
+#define ATA_IFACE_PCI     0x01
+
+#define ATA_MODE_NONE    0x00
+#define ATA_MODE_PIO16   0x00
+#define ATA_MODE_PIO32   0x01
+#define ATA_MODE_ISADMA  0x02
+#define ATA_MODE_PCIDMA  0x03
+#define ATA_MODE_USEIRQ  0x10
+
+//@todo: this should be elsewhere, since it's not in fact ATA specific!
+#define ATA_TYPE_NONE     0x00
+#define ATA_TYPE_UNKNOWN  0x01
+#define ATA_TYPE_ATA      0x02
+#define ATA_TYPE_ATAPI    0x03
+#define ATA_TYPE_SCSI     0x04 // SCSI disk
+
+#define ATA_DEVICE_NONE  0x00
+#define ATA_DEVICE_HD    0xFF
+#define ATA_DEVICE_CDROM 0x05
+
+
+// Global defines -- ATA register and register bits.
+// command block & control block regs
+#define ATA_CB_DATA  0   // data reg         in/out pio_base_addr1+0
+#define ATA_CB_ERR   1   // error            in     pio_base_addr1+1
+#define ATA_CB_FR    1   // feature reg         out pio_base_addr1+1
+#define ATA_CB_SC    2   // sector count     in/out pio_base_addr1+2
+#define ATA_CB_SN    3   // sector number    in/out pio_base_addr1+3
+#define ATA_CB_CL    4   // cylinder low     in/out pio_base_addr1+4
+#define ATA_CB_CH    5   // cylinder high    in/out pio_base_addr1+5
+#define ATA_CB_DH    6   // device head      in/out pio_base_addr1+6
+#define ATA_CB_STAT  7   // primary status   in     pio_base_addr1+7
+#define ATA_CB_CMD   7   // command             out pio_base_addr1+7
+#define ATA_CB_ASTAT 6   // alternate status in     pio_base_addr2+6
+#define ATA_CB_DC    6   // device control      out pio_base_addr2+6
+#define ATA_CB_DA    7   // device address   in     pio_base_addr2+7
+
+#define ATA_CB_ER_ICRC 0x80    // ATA Ultra DMA bad CRC
+#define ATA_CB_ER_BBK  0x80    // ATA bad block
+#define ATA_CB_ER_UNC  0x40    // ATA uncorrected error
+#define ATA_CB_ER_MC   0x20    // ATA media change
+#define ATA_CB_ER_IDNF 0x10    // ATA id not found
+#define ATA_CB_ER_MCR  0x08    // ATA media change request
+#define ATA_CB_ER_ABRT 0x04    // ATA command aborted
+#define ATA_CB_ER_NTK0 0x02    // ATA track 0 not found
+#define ATA_CB_ER_NDAM 0x01    // ATA address mark not found
+
+#define ATA_CB_ER_P_SNSKEY 0xf0   // ATAPI sense key (mask)
+#define ATA_CB_ER_P_MCR    0x08   // ATAPI Media Change Request
+#define ATA_CB_ER_P_ABRT   0x04   // ATAPI command abort
+#define ATA_CB_ER_P_EOM    0x02   // ATAPI End of Media
+#define ATA_CB_ER_P_ILI    0x01   // ATAPI Illegal Length Indication
+
+// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
+#define ATA_CB_SC_P_TAG    0xf8   // ATAPI tag (mask)
+#define ATA_CB_SC_P_REL    0x04   // ATAPI release
+#define ATA_CB_SC_P_IO     0x02   // ATAPI I/O
+#define ATA_CB_SC_P_CD     0x01   // ATAPI C/D
+
+// 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
+
+// status reg (CB_STAT and CB_ASTAT) bits
+#define ATA_CB_STAT_BSY  0x80  // busy
+#define ATA_CB_STAT_RDY  0x40  // ready
+#define ATA_CB_STAT_DF   0x20  // device fault
+#define ATA_CB_STAT_WFT  0x20  // write fault (old name)
+#define ATA_CB_STAT_SKC  0x10  // seek complete
+#define ATA_CB_STAT_SERV 0x10  // service
+#define ATA_CB_STAT_DRQ  0x08  // data request
+#define ATA_CB_STAT_CORR 0x04  // corrected
+#define ATA_CB_STAT_IDX  0x02  // index
+#define ATA_CB_STAT_ERR  0x01  // error (ATA)
+#define ATA_CB_STAT_CHK  0x01  // check (ATAPI)
+
+// device control reg (CB_DC) bits
+#define ATA_CB_DC_HD15   0x08  // bit should always be set to one
+#define ATA_CB_DC_SRST   0x04  // soft reset
+#define ATA_CB_DC_NIEN   0x02  // disable interrupts
+
+// Most mandatory and optional ATA commands (from ATA-3),
+#define ATA_CMD_CFA_ERASE_SECTORS            0xC0
+#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE     0x03
+#define ATA_CMD_CFA_TRANSLATE_SECTOR         0x87
+#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE  0xCD
+#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE   0x38
+#define ATA_CMD_CHECK_POWER_MODE1            0xE5
+#define ATA_CMD_CHECK_POWER_MODE2            0x98
+#define ATA_CMD_DEVICE_RESET                 0x08
+#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC    0x90
+#define ATA_CMD_FLUSH_CACHE                  0xE7
+#define ATA_CMD_FORMAT_TRACK                 0x50
+#define ATA_CMD_IDENTIFY_DEVICE              0xEC
+#define ATA_CMD_IDENTIFY_DEVICE_PACKET       0xA1
+#define ATA_CMD_IDENTIFY_PACKET_DEVICE       0xA1
+#define ATA_CMD_IDLE1                        0xE3
+#define ATA_CMD_IDLE2                        0x97
+#define ATA_CMD_IDLE_IMMEDIATE1              0xE1
+#define ATA_CMD_IDLE_IMMEDIATE2              0x95
+#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS  0x91
+#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define ATA_CMD_NOP                          0x00
+#define ATA_CMD_PACKET                       0xA0
+#define ATA_CMD_READ_BUFFER                  0xE4
+#define ATA_CMD_READ_DMA                     0xC8
+#define ATA_CMD_READ_DMA_QUEUED              0xC7
+#define ATA_CMD_READ_MULTIPLE                0xC4
+#define ATA_CMD_READ_SECTORS                 0x20
+#define ATA_CMD_READ_SECTORS_EXT             0x24
+#define ATA_CMD_READ_MULTIPLE_EXT            0x29
+#define ATA_CMD_WRITE_MULTIPLE_EXT           0x39
+#define ATA_CMD_READ_VERIFY_SECTORS          0x40
+#define ATA_CMD_RECALIBRATE                  0x10
+#define ATA_CMD_SEEK                         0x70
+#define ATA_CMD_SET_FEATURES                 0xEF
+#define ATA_CMD_SET_MULTIPLE_MODE            0xC6
+#define ATA_CMD_SLEEP1                       0xE6
+#define ATA_CMD_SLEEP2                       0x99
+#define ATA_CMD_STANDBY1                     0xE2
+#define ATA_CMD_STANDBY2                     0x96
+#define ATA_CMD_STANDBY_IMMEDIATE1           0xE0
+#define ATA_CMD_STANDBY_IMMEDIATE2           0x94
+#define ATA_CMD_WRITE_BUFFER                 0xE8
+#define ATA_CMD_WRITE_DMA                    0xCA
+#define ATA_CMD_WRITE_DMA_QUEUED             0xCC
+#define ATA_CMD_WRITE_MULTIPLE               0xC5
+#define ATA_CMD_WRITE_SECTORS                0x30
+#define ATA_CMD_WRITE_SECTORS_EXT            0x34
+#define ATA_CMD_WRITE_VERIFY                 0x3C
+
+// for access to the int13ext structure
+typedef struct {
+    uint8_t     size;
+    uint8_t     reserved;
+    uint16_t    count;
+    uint16_t    offset;
+    uint16_t    segment;
+    uint32_t    lba1;
+    uint32_t    lba2;
+} int13ext_t;
+
+#define Int13Ext ((int13ext_t *) 0)
+
+// Disk Physical Table definition
+typedef struct {
+    uint16_t    size;
+    uint16_t    infos;
+    uint32_t    cylinders;
+    uint32_t    heads;
+    uint32_t    spt;
+    uint32_t    sector_count1;
+    uint32_t    sector_count2;
+    uint16_t    blksize;
+    uint16_t    dpte_offset;
+    uint16_t    dpte_segment;
+    uint16_t    key;
+    uint8_t     dpi_length;
+    uint8_t     reserved1;
+    uint16_t    reserved2;
+    uint8_t     host_bus[4];
+    uint8_t     iface_type[8];
+    uint8_t     iface_path[8];
+    uint8_t     device_path[8];
+    uint8_t     reserved3;
+    uint8_t     checksum;
+} dpt_t;
+
+#define Int13DPT ((dpt_t *) 0)
+
+
+extern void     ata_reset(uint16_t device);
+extern uint16_t atapi_is_cdrom(uint8_t device);
+extern uint16_t ata_cmd_data_in(uint16_t device, uint16_t command, 
+                                uint16_t count, uint16_t cylinder,
+                                uint16_t head, uint16_t sector,
+                                uint32_t lba, char __far *buffer);
+extern uint16_t ata_cmd_data_out(uint16_t device, uint16_t command,
+                                 uint16_t count, uint16_t cylinder,
+                                 uint16_t head, uint16_t sector,
+                                 uint32_t lba, char __far *buffer);
+extern uint16_t ata_cmd_packet(uint16_t device, uint8_t cmdlen,
+                               char __far *cmdbuf, uint16_t header, 
+                               uint32_t length, uint8_t inout, 
+                               char __far *buffer);
Index: /trunk/src/VBox/Devices/PC/BIOS-new/bios.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/bios.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/bios.c	(revision 38699)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "inlines.h"
+#include "biosint.h"
+#include "ebda.h"
+
+static  const char  bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
+
+uint8_t read_byte(uint16_t seg, uint16_t offset)
+{
+    return( *(seg:>(uint8_t *)offset) );
+}
+
+void write_byte(uint16_t seg, uint16_t offset, uint8_t data)
+{
+    *(seg:>(uint8_t *)offset) = data;
+}
+
+uint16_t read_word(uint16_t seg, uint16_t offset)
+{
+    return( *(seg:>(uint16_t *)offset) );
+}
+
+void write_word(uint16_t seg, uint16_t offset, uint16_t data)
+{
+    *(seg:>(uint16_t *)offset) = data;
+}
+
+uint32_t read_dword(uint16_t seg, uint16_t offset)
+{
+    return( *(seg:>(uint32_t *)offset) );
+}
+
+void write_dword(uint16_t seg, uint16_t offset, uint32_t data)
+{
+    *(seg:>(uint32_t *)offset) = data;
+}
+
+uint8_t inb_cmos(uint8_t cmos_reg)
+{
+    outb(0x70, cmos_reg);
+    return inb(0x71);
+}
+
+void outb_cmos(uint8_t cmos_reg, uint8_t val)
+{
+    outb(0x70, cmos_reg);
+    outb(0x71, val);
+}
+
+void BIOSCALL dummy_isr_function(pusha_regs_t regs, uint16_t es,
+                                 uint16_t ds, iret_addr_t iret_addr)
+{
+    // Interrupt handler for unexpected hardware interrupts. We have to clear
+    // the PIC because if we don't, the next EOI will clear the wrong interrupt
+    // and all hell will break loose! This routine also masks the unexpected
+    // interrupt so it will generally be called only once for each unexpected
+    // interrupt level.
+    uint8_t     isrA, isrB, imr, last_int = 0xFF;
+    
+    outb(PIC_MASTER, PIC_CMD_RD_ISR);           // Read master ISR
+    isrA = inb(PIC_MASTER);
+    if (isrA) {
+        outb(PIC_SLAVE, PIC_CMD_RD_ISR);        // Read slave ISR
+        isrB = inb(PIC_SLAVE);
+        if (isrB) {
+            imr = inb(PIC_SLAVE_MASK);
+            outb(PIC_SLAVE_MASK, imr | isrB );  // Mask this interrupt
+            outb(PIC_SLAVE, PIC_CMD_EOI);       // Send EOI on slave PIC
+        } else {
+            imr = inb(PIC_MASTER_MASK);
+            isrA &= 0xFB;                       // Never mask the cascade interrupt
+            outb(PIC_MASTER_MASK, imr | isrA);  // Mask this interrupt
+        }
+        outb(PIC_MASTER, PIC_CMD_EOI);          // Send EOI on master PIC
+        last_int = isrA;
+    }
+    write_byte(0x40, 0x6B, last_int);           // Write INTR_FLAG
+}
+
+
+void BIOSCALL nmi_handler_msg(void)
+{
+    BX_PANIC("NMI Handler called\n");
+}
+
+void BIOSCALL int18_panic_msg(void)
+{
+    BX_PANIC("INT18: BOOT FAILURE\n");
+}
+
+void BIOSCALL log_bios_start(void)
+{
+#if BX_DEBUG_SERIAL
+    outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
+#endif
+    BX_INFO("%s\n", bios_cvs_version_string);
+}
+
+//@todo: restore
+//#undef VBOX
+
+#define BX_PCIBIOS  1
+#define BX_APPNAME          "VirtualBox"
+#define BIOS_BUILD_DATE     __DATE__
+//--------------------------------------------------------------------------
+// print_bios_banner
+//   displays a the bios version
+//--------------------------------------------------------------------------
+void BIOSCALL print_bios_banner(void)
+{
+#ifdef VBOX
+    // Skip the logo if a warm boot is requested.
+    uint16_t    warm_boot = read_word(0x0040,0x0072);
+    write_word(0x0040,0x0072, 0);
+    if (warm_boot == 0x1234)
+        return;
+    /* show graphical logo */
+    show_logo();
+#else /* !VBOX */
+    char        *bios_conf;
+
+    /* Avoid using preprocessing directives within macro arguments. */
+    bios_conf = 
+#ifdef __WATCOMC__
+    "watcom "
+#endif
+#if BX_APM
+    "apmbios "
+#endif
+#if BX_PCIBIOS
+    "pcibios "
+#endif
+#if BX_ELTORITO_BOOT
+    "eltorito "
+#endif
+#if BX_ROMBIOS32
+    "rombios32 "
+#endif
+    "\n\n";
+
+    printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
+           BIOS_BUILD_DATE, bios_cvs_version_string);
+    printf(bios_conf, 0);
+#endif /* VBOX */
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/biosint.h
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/biosint.h	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/biosint.h	(revision 38699)
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+/* For functions called from assembly code. */
+#define BIOSCALL	__cdecl
+
+#define BX_ELTORITO_BOOT    1
+#define BX_PCIBIOS          1
+#define BX_USE_PS2_MOUSE    1
+
+#define DEBUG_ATA       0
+#define DEBUG_ELTORITO  0
+#define DEBUG_INT13_HD  0
+#define DEBUG_INT13_FL  0
+#define DEBUG_INT13_CD  0
+#define DEBUG_INT15     0
+#define DEBUG_INT15_MS  0
+#define DEBUG_INT16     0
+#define DEBUG_INT1A     0
+#define DEBUG_INT74     0
+
+#define FP_OFF(p)   ((unsigned)(p))
+#define FP_SEG(p)   ((unsigned)((unsigned long)(void __far*)(p) >> 16))
+#define MK_FP(s,o)  (((unsigned short)(s)):>((void __near *)(o)))
+
+typedef struct {
+    union {
+        struct {
+            uint16_t    di, si, bp, sp;
+            uint16_t    bx, dx, cx, ax;
+        } r16;
+        struct {
+            uint16_t    filler[4];
+            uint8_t     bl, bh, dl, dh, cl, ch, al, ah;
+        } r8;
+    } u;
+} pusha_regs_t;
+
+typedef struct {
+    union {
+        struct {
+            uint32_t    edi, esi, ebp, esp;
+            uint32_t    ebx, edx, ecx, eax;
+        } r32;
+        struct {
+            uint16_t    di, filler1, si, filler2, bp, filler3, sp, filler4;
+            uint16_t    bx, filler5, dx, filler6, cx, filler7, ax, filler8;
+        } r16;
+        struct {
+            uint32_t    filler[4];
+            uint8_t     bl, bh;
+            uint16_t    filler1;
+            uint8_t     dl, dh;
+            uint16_t    filler2;
+            uint8_t     cl, ch;
+            uint16_t    filler3;
+            uint8_t     al, ah;
+            uint16_t    filler4;
+        } r8;
+    } u;
+} pushad_regs_t;
+
+typedef struct {
+    union {
+        struct {
+            uint16_t    flags;
+        } r16;
+        struct {
+            uint16_t    flagsl;
+            uint16_t    flagsh;
+        } r8;
+    } u;
+} flags_t;
+
+typedef struct {
+    uint16_t    ip;
+    uint16_t    cs;
+    flags_t     flags;
+} iret_addr_t;
+
+typedef struct {
+    uint16_t        ds;
+    uint16_t        es;
+    pusha_regs_t    gr;
+    iret_addr_t     ra;
+} disk_regs_t;
+
+typedef struct {
+    pusha_regs_t    gr;
+    flags_t         fl;
+} kbd_regs_t;
+
+typedef struct {
+    pusha_regs_t    gr;
+    uint16_t        es;
+    uint16_t        ds;
+    flags_t         fl;
+} sys_regs_t;
+
+typedef struct {
+    pushad_regs_t   gr;
+    uint16_t        es;
+    uint16_t        ds;
+    flags_t         fl;
+} sys32_regs_t;
+
+typedef struct {
+    pusha_regs_t    gr;
+    iret_addr_t     ra;
+} i1apci_regs_t;
+
+
+#define SetCF(x)   x.u.r8.flagsl |= 0x01
+#define SetZF(x)   x.u.r8.flagsl |= 0x40
+#define ClearCF(x) x.u.r8.flagsl &= 0xfe
+#define ClearZF(x) x.u.r8.flagsl &= 0xbf
+#define GetCF(x)   (x.u.r8.flagsl & 0x01)
+
+#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
+#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
+#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
+#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
+#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
+#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
+#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
+#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
+
+#define GET_AL() ( AX & 0x00ff )
+#define GET_BL() ( BX & 0x00ff )
+#define GET_CL() ( CX & 0x00ff )
+#define GET_DL() ( DX & 0x00ff )
+#define GET_AH() ( AX >> 8 )
+#define GET_BH() ( BX >> 8 )
+#define GET_CH() ( CX >> 8 )
+#define GET_DH() ( DX >> 8 )
+
+#define GET_ELDL() ( ELDX & 0x00ff )
+#define GET_ELDH() ( ELDX >> 8 )
+
+#define SET_CF()     FLAGS |= 0x0001
+#define CLEAR_CF()   FLAGS &= 0xfffe
+#define GET_CF()     (FLAGS & 0x0001)
+
+#define SET_ZF()     FLAGS |= 0x0040
+#define CLEAR_ZF()   FLAGS &= 0xffbf
+#define GET_ZF()     (FLAGS & 0x0040)
+
+typedef unsigned short  bx_bool;
+
+#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
+#define BX_DEBUG_SERIAL  0 /* output to COM1 */
+
+#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)
+
+extern  const char  bios_prefix_string[];
+extern  void        bios_printf(uint16_t action, const char *s, ...);
+extern  void        put_str(uint16_t action, const char __far *s);
+extern  void        put_str_near(uint16_t action, const char __near *s);
+extern  uint8_t     inb_cmos(uint8_t cmos_reg);
+extern  void        outb_cmos(uint8_t cmos_reg, uint8_t val);
+extern  uint16_t    cdrom_boot(void);
+extern  void        show_logo(void);
+extern  void        delay_boot(uint16_t secs);
+
+int scsi_read_sectors(uint8_t device_id, uint16_t count, uint32_t lba, void __far *buffer);
+int scsi_write_sectors(uint8_t device_id, uint16_t count, uint32_t lba, void __far *buffer);
+
+#define printf(...)  bios_printf(BIOS_PRINTF_SCREEN, __VA_ARGS__)
+
+// 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
+#define DEBUG_ROMBIOS   1
+#if DEBUG_ROMBIOS
+#  define BX_DEBUG(...) bios_printf(BIOS_PRINTF_INFO, __VA_ARGS__)
+#else
+#  define BX_DEBUG(...)
+#endif
+#ifdef VBOX
+#define BX_INFO(...)    do { put_str(BIOS_PRINTF_INFO, bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, __VA_ARGS__); } while (0)
+#else /* !VBOX */
+#define BX_INFO(...)    bios_printf(BIOS_PRINTF_INFO, __VA_ARGS__)
+#endif /* !VBOX */
+#define BX_PANIC(...)   bios_printf(BIOS_PRINTF_DEBHALT, __VA_ARGS__)
+
+/* Random hardware-related definitions. */
+
+#define PIC_MASTER          0x20
+#define PIC_MASTER_MASK     0x21
+#define PIC_SLAVE           0xA0
+#define PIC_SLAVE_MASK      0xA1
+#define PIC_CMD_EOI         0x20
+#define PIC_CMD_RD_ISR      0x0B
+#define PIC_CMD_INIT        0x11
Index: /trunk/src/VBox/Devices/PC/BIOS-new/boot.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/boot.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/boot.c	(revision 38699)
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include <string.h>
+#include "inlines.h"
+#include "biosint.h"
+#include "ebda.h"
+
+
+/* PnP header used with LAN boot ROMs. */
+typedef struct {
+    uint32_t    sig;
+    uint8_t     revision;
+    uint8_t     length;
+    uint16_t    next_s;
+    uint8_t     pad1;
+    uint8_t     checksum;
+    uint32_t    dev_id;
+    uint16_t    mfg_string;
+    uint16_t    prod_string;
+    uint8_t     base_class;
+    uint8_t     subclass;
+    uint8_t     interface;
+    uint8_t     dev_ind;
+    uint16_t    boot_code;
+    uint16_t    dv;
+    uint16_t    bev;
+    uint16_t    pad2;
+    uint16_t    sriv;
+} pnp_exp_t;
+
+
+int read_boot_sec(uint8_t bootdrv, uint16_t segment);
+#pragma aux read_boot_sec = \
+    "mov ax,0201h"          \
+    "mov dh,0"              \
+    "mov cx,1"              \
+    "xor bx,bx"             \
+    "int 13h"               \
+    "mov ax,0"              \
+    "sbb ax,0"              \
+    parm [dl] [es] modify [ax bx cx dx];
+
+//--------------------------------------------------------------------------
+// print_boot_device
+//   displays the boot device
+//--------------------------------------------------------------------------
+
+static const char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
+
+//@todo: pass inputs as bit flags rather than bytes?
+void print_boot_device(uint8_t cdboot, uint8_t lanboot, uint8_t drive)
+{
+    int     i;
+    
+    // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
+    // lanboot contains 0 if floppy/harddisk, 1 otherwise
+    // drive contains real/emulated boot drive
+    
+    if(cdboot)i=2;                    // CD-Rom
+    else if(lanboot)i=3;              // LAN
+    else if((drive&0x0080)==0x00)i=0; // Floppy
+    else if((drive&0x0080)==0x80)i=1; // Hard drive
+    else return;
+    
+    BX_INFO("Booting from %s...\n",drivetypes[i]);
+}
+
+//--------------------------------------------------------------------------
+// print_boot_failure
+//   displays the reason why boot failed
+//--------------------------------------------------------------------------
+//@todo: pass inputs as bit flags rather than bytes?
+void print_boot_failure(uint8_t cdboot, uint8_t lanboot, uint8_t drive, 
+                        uint8_t reason, uint8_t lastdrive)
+{
+    uint16_t    drivenum = drive&0x7f;
+    
+    // cdboot: 1 if boot from cd, 0 otherwise
+    // lanboot: 1 if boot from lan, 0 otherwise
+    // drive : drive number
+    // reason: 0 signature check failed, 1 read error
+    // lastdrive: 1 boot drive is the last one in boot sequence
+    
+    if (cdboot)
+        BX_INFO("Boot from %s failed\n",drivetypes[2]);
+    else if (lanboot)
+        BX_INFO("Boot from %s failed\n",drivetypes[3]);
+    else if (drive & 0x80)
+        BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
+    else
+        BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
+    
+    if (lastdrive==1) {
+        if (reason==0)
+            BX_PANIC("No bootable medium found! System halted.\n");
+        else
+            BX_PANIC("Could not read from the boot medium! System halted.\n");
+    }
+}
+
+//--------------------------------------------------------------------------
+// print_cdromboot_failure
+//   displays the reason why boot failed
+//--------------------------------------------------------------------------
+void print_cdromboot_failure(uint16_t code)
+{
+    BX_INFO("CDROM boot failure code : %04x\n",code);
+    return;
+}
+
+// returns bootsegment in ax, drive in bl
+uint32_t BIOSCALL int19_function(uint8_t bseqnr)
+{
+    //@todo: common code for getting the EBDA segment
+    uint16_t    ebda_seg=read_word(0x0040,0x000E);
+    uint16_t    bootseq;
+    uint8_t     bootdrv;
+    uint8_t     bootcd;
+    uint8_t     bootlan;
+    uint8_t     bootchk;
+    uint16_t    bootseg;
+    uint16_t    status;
+    uint8_t     lastdrive=0;
+    
+    // if BX_ELTORITO_BOOT is not defined, old behavior
+    //   check bit 5 in CMOS reg 0x2d.  load either 0x00 or 0x80 into DL
+    //   in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
+    //     0: system boot sequence, first drive C: then A:
+    //     1: system boot sequence, first drive A: then C:
+    // else BX_ELTORITO_BOOT is defined
+    //   CMOS regs 0x3D and 0x38 contain the boot sequence:
+    //     CMOS reg 0x3D & 0x0f : 1st boot device
+    //     CMOS reg 0x3D & 0xf0 : 2nd boot device
+    //     CMOS reg 0x38 & 0xf0 : 3rd boot device
+    //     CMOS reg 0x3C & 0x0f : 4th boot device
+    //   boot device codes:
+    //     0x00 : not defined
+    //     0x01 : first floppy
+    //     0x02 : first harddrive
+    //     0x03 : first cdrom
+    //     0x04 : local area network
+    //     else : boot failure
+    
+    // Get the boot sequence
+#if BX_ELTORITO_BOOT
+    bootseq=inb_cmos(0x3d);
+    bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
+    bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
+    if (read_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice))
+        bootseq = read_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice);
+    /* Boot delay hack. */
+    if (bseqnr == 1)
+        delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
+    
+    if (bseqnr==2) bootseq >>= 4;
+    if (bseqnr==3) bootseq >>= 8;
+    if (bseqnr==4) bootseq >>= 12;
+    if (bootseq<0x10) lastdrive = 1;
+    bootdrv=0x00; bootcd=0;
+    bootlan=0;
+    BX_INFO("Boot : bseqnr=%d, bootseq=%x\r\n",bseqnr, bootseq);    
+    
+    switch(bootseq & 0x0f) {
+    case 0x01:
+        bootdrv=0x00;
+        bootcd=0;
+        break;
+    case 0x02:
+    {
+        // Get the Boot drive.
+        uint8_t boot_drive = read_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDrive);
+        
+        bootdrv = boot_drive + 0x80;
+        bootcd=0;
+        break;
+    }
+    case 0x03:
+        bootdrv=0x00;
+        bootcd=1;
+        break;
+    case 0x04: bootlan=1; break;
+    default:   return 0x00000000;
+    }
+#else
+    bootseq=inb_cmos(0x2d);
+    
+    if (bseqnr==2) {
+        bootseq ^= 0x20;
+        lastdrive = 1;
+    }
+    bootdrv=0x00; bootcd=0;
+    if((bootseq&0x20)==0) bootdrv=0x80;
+#endif // BX_ELTORITO_BOOT
+    
+#if BX_ELTORITO_BOOT
+    // We have to boot from cd
+    if (bootcd != 0) {
+        status = cdrom_boot();
+    
+        // If failure
+        if ( (status & 0x00ff) !=0 ) {
+            print_cdromboot_failure(status);
+            print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
+            return 0x00000000;
+        }
+        
+        bootseg = read_word(ebda_seg,(uint16_t)&EbdaData->cdemu.load_segment);
+        bootdrv = (uint8_t)(status>>8);
+    }
+    
+#endif // BX_ELTORITO_BOOT
+    
+    // Check for boot from LAN first
+    if (bootlan == 1) {
+        uint8_t __far   *fplan;
+
+        fplan = MK_FP(VBOX_LANBOOT_SEG, 0);
+        if (*(uint16_t __far *)fplan == 0xaa55) {
+            pnp_exp_t __far *pnps;
+            uint32_t        manuf;
+            void    (__far  *netboot_entry)(void);
+
+            // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
+            pnps = (void __far *)(fplan + *(uint16_t __far *)(fplan + 0x1a));
+            if (pnps->sig == 0x506e5024/* '$PnP' */) {
+                // Found PnP signature
+                manuf = *(uint32_t __far *)(fplan + pnps->mfg_string);
+                if (manuf == 0x65687445/* 'Ethe' */) {
+                    // Found Etherboot ROM
+                    print_boot_device(bootcd, bootlan, bootdrv);
+                    netboot_entry = (void __far *)(fplan + 6);
+                    netboot_entry();
+                } else if (manuf == 0x65746E49/* 'Inte' */) {
+                    // Found Intel PXE ROM
+                    print_boot_device(bootcd, bootlan, bootdrv);
+                    int_enable();   /* Disabled as we were invoked via INT instruction. */
+                    netboot_entry = (void __far *)(fplan + pnps->bev);
+                    netboot_entry();
+                }
+            }
+        }
+        
+        // boot from LAN will not return if successful.
+        print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
+        return 0x00000000;
+    }
+
+    // We have to boot from harddisk or floppy
+    if (bootcd == 0 && bootlan == 0) {
+        bootseg=0x07c0;
+                
+        status = read_boot_sec(bootdrv,bootseg);
+        if (status != 0) {
+            print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
+            return 0x00000000;
+        }
+    }
+    
+    // Don't check boot sectors on floppies and don't read CMOS - byte
+    // 0x38 in CMOS always has the low bit clear.
+    // There is *no* requirement whatsoever for a valid boot sector to
+    // have a 55AAh signature. UNIX boot floppies typically have no such
+    // signature. In general, it is impossible to tell a valid bootsector
+    // from an invalid one.
+    // NB: It is somewhat common for failed OS installs to have the
+    // 0x55AA signature and a valid partition table but zeros in the
+    // rest of the boot sector. We do a quick check by comparing the first
+    // two words of boot sector; if identical, the boot sector is
+    // extremely unlikely to be valid.
+    if (bootdrv != 0) bootchk = 0;
+    else bootchk = 1; /* disable 0x55AA signature check on drive A: */
+    
+#if BX_ELTORITO_BOOT
+    // if boot from cd, no signature check
+    if (bootcd != 0)
+        bootchk = 1;
+#endif // BX_ELTORITO_BOOT
+    
+    if (bootchk == 0) {
+        if (read_word(bootseg,0x1fe) != 0xaa55 ||
+            read_word(bootseg,0) == read_word(bootseg,2)) {
+            print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
+            return 0x00000000;
+        }
+    }
+    
+#if BX_ELTORITO_BOOT
+    // Print out the boot string
+    print_boot_device(bootcd, bootlan, bootdrv);
+#else // BX_ELTORITO_BOOT
+    print_boot_device(0, bootlan, bootdrv);
+#endif // BX_ELTORITO_BOOT
+    
+    // return the boot segment
+    return (((uint32_t)bootdrv) << 16) + bootseg;
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/disk.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/disk.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/disk.c	(revision 38699)
@@ -0,0 +1,641 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "biosint.h"
+#include "inlines.h"
+#include "ebda.h"
+#include "ata.h"
+
+
+#if DEBUG_INT13_HD
+#  define BX_DEBUG_INT13_HD(...) BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT13_HD(...)
+#endif
+
+//@todo: put in a header
+#define AX      r.gr.u.r16.ax
+#define BX      r.gr.u.r16.bx
+#define CX      r.gr.u.r16.cx
+#define DX      r.gr.u.r16.dx
+#define SI      r.gr.u.r16.si
+#define DI      r.gr.u.r16.di
+#define BP      r.gr.u.r16.bp
+#define ELDX    r.gr.u.r16.sp
+#define DS      r.ds
+#define ES      r.es
+#define FLAGS   r.ra.flags.u.r16.flags
+
+void BIOSCALL int13_harddisk(disk_regs_t r)
+{
+    uint32_t    lba;
+    uint16_t    ebda_seg=read_word(0x0040,0x000E);
+    uint16_t    cylinder, head, sector;
+    uint16_t    npc, nph, npspt, nlc, nlh, nlspt;
+    uint16_t    count;
+    uint8_t     device, status;
+    uint8_t     scsi_device;
+
+    BX_DEBUG_INT13_HD("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
+    
+    write_byte(0x0040, 0x008e, 0);  // clear completion flag
+    
+    // basic check : device has to be defined
+    if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
+        BX_DEBUG("%s: function %02x, ELDL out of range %02x\n", __func__, GET_AH(), GET_ELDL());
+        goto int13_fail;
+    }
+    
+    // Get the ata channel
+    device=read_byte(ebda_seg,(uint16_t)&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
+    
+    // basic check : device has to be valid
+    if (device >= BX_MAX_STORAGE_DEVICES) {
+        BX_DEBUG("%s: function %02x, unmapped device for ELDL=%02x\n", __func__, GET_AH(), GET_ELDL());
+        goto int13_fail;
+    }
+
+    switch (GET_AH()) {
+
+    case 0x00: /* disk controller reset */
+#ifdef VBOX_WITH_SCSI
+        /* SCSI controller does not need a reset. */
+        if (!VBOX_IS_SCSI_DEVICE(device))
+#endif
+        ata_reset (device);
+        goto int13_success;
+        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 0x02: // read disk sectors
+    case 0x03: // write disk sectors
+    case 0x04: // verify disk sectors
+
+        count       = GET_AL();
+        cylinder    = GET_CH();
+        cylinder   |= ( ((uint16_t) GET_CL()) << 2) & 0x300;
+        sector      = (GET_CL() & 0x3f);
+        head        = GET_DH();
+        
+        /* Segment and offset are in ES:BX. */        
+        if ( (count > 128) || (count == 0) ) {
+            BX_INFO("%s: function %02x, count out of range!\n", __func__, GET_AH());
+            goto int13_fail;
+        }
+
+#ifdef VBOX_WITH_SCSI
+        if (!VBOX_IS_SCSI_DEVICE(device))
+#endif
+        {
+            nlc   = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].lchs.cylinders);
+            nlh   = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].lchs.heads);
+            nlspt = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].lchs.spt);
+        }
+#ifdef VBOX_WITH_SCSI
+        else {
+            scsi_device = VBOX_GET_SCSI_DEVICE(device);
+    
+            nlc   = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
+            nlh   = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
+            nlspt = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
+        }
+#endif
+
+        // sanity check on cyl heads, sec
+        if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
+            BX_INFO("%s: function %02x, disk %02x, parameters out of range %04x/%04x/%04x!\n", __func__, GET_AH(), GET_DL(), cylinder, head, sector);
+            goto int13_fail;
+        }
+        
+        // FIXME verify
+        if ( GET_AH() == 0x04 )
+            goto int13_success;
+
+#ifdef VBOX_WITH_SCSI
+        if (!VBOX_IS_SCSI_DEVICE(device))
+#endif
+        {
+            nph   = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].pchs.heads);
+            npspt = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].pchs.spt);
+        }
+#ifdef VBOX_WITH_SCSI
+        else {
+            scsi_device = VBOX_GET_SCSI_DEVICE(device);
+            nph   = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
+            npspt = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
+        }
+#endif
+
+        // if needed, translate lchs to lba, and execute command
+#ifdef VBOX_WITH_SCSI
+        if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
+            lba = ((((uint32_t)cylinder * (uint32_t)nlh) + (uint32_t)head) * (uint32_t)nlspt) + (uint32_t)sector - 1;
+            sector = 0; // this forces the command to be lba
+        }
+#else
+        if (( (nph != nlh) || (npspt != nlspt)) ) {
+            lba = ((((uint32_t)cylinder * (uint32_t)nlh) + (uint32_t)head) * (uint32_t)nlspt) + (uint32_t)sector - 1;
+            sector = 0; // this forces the command to be lba
+        }
+#endif
+
+        if ( GET_AH() == 0x02 )
+        {
+#ifdef VBOX_WITH_SCSI
+            if (VBOX_IS_SCSI_DEVICE(device))
+                status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, MK_FP(ES, BX));
+            else
+#endif
+            {
+                write_word(ebda_seg,(uint16_t)&EbdaData->ata.devices[device].blksize,count * 0x200);
+                status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, cylinder, head, sector, lba, MK_FP(ES, BX));
+                write_word(ebda_seg,(uint16_t)&EbdaData->ata.devices[device].blksize,0x200);
+            }
+        } else {
+#ifdef VBOX_WITH_SCSI
+            if (VBOX_IS_SCSI_DEVICE(device))
+                status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, MK_FP(ES, BX));
+            else
+#endif
+                status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, MK_FP(ES, BX));
+        }
+
+        // Set nb of sector transferred
+        SET_AL(read_word(ebda_seg, (uint16_t)&EbdaData->ata.trsfsectors));
+        
+        if (status != 0) {
+            BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
+            SET_AH(0x0c);
+            goto int13_fail_noah;
+        }
+        
+        goto int13_success;
+        break;
+
+    case 0x05: /* format disk track */
+          BX_INFO("format disk track called\n");
+          goto int13_success;
+          return;
+          break;
+
+    case 0x08: /* read disk drive parameters */
+
+        // Get logical geometry from table
+#ifdef VBOX_WITH_SCSI
+        if (!VBOX_IS_SCSI_DEVICE(device))
+#endif
+        {
+            nlc   = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].lchs.cylinders);
+            nlh   = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].lchs.heads);
+            nlspt = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].lchs.spt);
+        }
+#ifdef VBOX_WITH_SCSI
+        else {
+            scsi_device = VBOX_GET_SCSI_DEVICE(device);
+            nlc   = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
+            nlh   = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
+            nlspt = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
+        }
+#endif
+
+        count = read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdcount);
+        /* Maximum cylinder number is just one less than the number of cylinders. */
+        nlc = nlc - 1; /* 0 based , last sector not used */
+        SET_AL(0);
+        SET_CH(nlc & 0xff);
+        SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
+        SET_DH(nlh - 1);
+        SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
+        
+        // FIXME should set ES & DI
+        // @todo: Actually, the above comment is nonsense.
+        
+        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, (uint16_t)&EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
+        if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
+            goto int13_success;
+        } else {
+            SET_AH(0xAA);
+            goto int13_fail_noah;
+        }
+        break;
+
+    case 0x15: /* read disk drive size */
+
+      // Get physical geometry from table
+#ifdef VBOX_WITH_SCSI
+        if (!VBOX_IS_SCSI_DEVICE(device))
+#endif
+        {
+            npc   = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].pchs.cylinders);
+            nph   = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].pchs.heads);
+            npspt = read_word(ebda_seg, (uint16_t)&EbdaData->ata.devices[device].pchs.spt);
+        }
+#ifdef VBOX_WITH_SCSI
+        else {
+            scsi_device = VBOX_GET_SCSI_DEVICE(device);
+            npc   = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
+            nph   = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
+            npspt = read_word(ebda_seg, (uint16_t)&EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
+        }
+#endif
+
+        // Compute sector count seen by int13
+        lba = (uint32_t)npc * (uint32_t)nph * (uint32_t)npspt;
+        CX = lba >> 16;
+        DX = lba & 0xffff;
+        
+        SET_AH(3);  // hard disk accessible
+        goto int13_success_noah;
+        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("%s: function %02xh unimplemented, returns success\n", __func__, 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
+    default:
+        BX_INFO("%s: function %02xh unsupported, returns fail\n", __func__, 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;
+}
+
+void BIOSCALL int13_harddisk_ext(disk_regs_t r)
+{
+    uint32_t            lba;
+    uint16_t            ebda_seg = read_word(0x0040,0x000E);
+    uint16_t            segment, offset;
+    uint16_t            npc, nph, npspt;
+    uint16_t            size, count;
+    uint8_t             device, status;
+    uint8_t             scsi_device;
+    ebda_data_t __far   *ebda_data;
+    int13ext_t __far    *i13_ext;
+    dpt_t __far         *dpt;
+
+    ebda_data = ebda_seg :> 0;
+
+    BX_DEBUG_INT13_HD("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
+    
+    write_byte(0x0040, 0x008e, 0);  // clear completion flag
+    
+    // basic check : device has to be defined
+    if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
+        BX_DEBUG("%s: function %02x, ELDL out of range %02x\n", __func__, GET_AH(), GET_ELDL());
+        goto int13x_fail;
+    }
+    
+    // Get the ata channel
+    device = ebda_data->ata.hdidmap[GET_ELDL()-0x80];
+    
+    // basic check : device has to be valid
+    if (device >= BX_MAX_STORAGE_DEVICES) {
+        BX_DEBUG("%s: function %02x, unmapped device for ELDL=%02x\n", __func__, GET_AH(), GET_ELDL());
+        goto int13x_fail;
+    }
+
+    switch (GET_AH()) {
+    case 0x41: // IBM/MS installation check
+        BX=0xaa55;     // install check
+        SET_AH(0x30);  // EDD 3.0
+        CX=0x0007;     // ext disk access and edd, removable supported
+        goto int13x_success_noah;
+        break;
+
+    case 0x42: // IBM/MS extended read
+    case 0x43: // IBM/MS extended write
+    case 0x44: // IBM/MS verify
+    case 0x47: // IBM/MS extended seek
+
+        /* Get a pointer to the extended structure. */
+        i13_ext = DS :> (int13ext_t *)SI;
+
+        count   = i13_ext->count;
+        segment = i13_ext->segment;
+        offset  = i13_ext->offset;
+        
+        // Can't use 64 bits lba
+        lba = i13_ext->lba2;
+        if (lba != 0L) {
+            BX_PANIC("%s: function %02x. Can't use 64bits lba\n", __func__, GET_AH());
+            goto int13x_fail;
+        }
+        
+        // Get 32 bits lba and check
+        lba = i13_ext->lba1;
+
+#ifdef VBOX_WITH_SCSI
+        if (VBOX_IS_SCSI_DEVICE(device))
+        {
+            if (lba >= ebda_data->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors ) {
+                BX_INFO("%s: function %02x. LBA out of range\n", __func__, GET_AH());
+                goto int13x_fail;
+            }
+        }
+        else
+#endif
+        if (lba >= ebda_data->ata.devices[device].sectors) {
+              BX_INFO("%s: function %02x. LBA out of range\n", __func__, GET_AH());
+              goto int13x_fail;
+        }
+
+        // If verify or seek
+        if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
+            goto int13x_success;
+        
+        // Execute the command
+        if ( GET_AH() == 0x42 ) {
+#ifdef VBOX_WITH_SCSI
+            if (VBOX_IS_SCSI_DEVICE(device))
+                status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, MK_FP(segment, offset));
+            else {
+#endif
+                if (lba + count >= 268435456)
+                    status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, MK_FP(segment, offset));
+                else {
+                    ebda_data->ata.devices[device].blksize = count * 0x200;
+                    status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, 0, 0, 0, lba, MK_FP(segment, offset));
+                    ebda_data->ata.devices[device].blksize = 0x200;
+                }
+            }
+        } else {
+#ifdef VBOX_WITH_SCSI
+            if (VBOX_IS_SCSI_DEVICE(device))
+                status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, MK_FP(segment, offset));
+            else {
+#endif
+                if (lba + count >= 268435456)
+                    status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, MK_FP(segment, offset));
+                else
+                    status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, MK_FP(segment, offset));
+            }
+        }
+
+        count = ebda_data->ata.trsfsectors;
+        i13_ext->count = count;
+        
+        if (status != 0) {
+            BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
+            SET_AH(0x0c);
+            goto int13x_fail_noah;
+        }
+        
+        goto int13x_success;
+        break;
+
+    case 0x45: // IBM/MS lock/unlock drive
+    case 0x49: // IBM/MS extended media change
+        goto int13x_success;   // Always success for HD
+        break;
+
+    case 0x46: // IBM/MS eject media
+        SET_AH(0xb2);          // Volume Not Removable
+        goto int13x_fail_noah; // Always fail for HD
+        break;
+
+    case 0x48: // IBM/MS get drive parameters
+        dpt = DS :> (dpt_t *)SI;
+        size = dpt->size;
+
+        // Buffer is too small
+        if(size < 0x1a)
+            goto int13x_fail;
+        
+        // EDD 1.x
+        if(size >= 0x1a) {
+            uint16_t   blksize;
+
+#ifdef VBOX_WITH_SCSI
+            if (!VBOX_IS_SCSI_DEVICE(device))
+#endif
+            {
+                npc     = ebda_data->ata.devices[device].pchs.cylinders;
+                nph     = ebda_data->ata.devices[device].pchs.heads;
+                npspt   = ebda_data->ata.devices[device].pchs.spt;
+                lba     = ebda_data->ata.devices[device].sectors;
+                blksize = ebda_data->ata.devices[device].blksize;
+            }
+#ifdef VBOX_WITH_SCSI
+            else {
+                scsi_device = VBOX_GET_SCSI_DEVICE(device);
+                npc     = ebda_data->scsi.devices[scsi_device].device_info.pchs.cylinders;
+                nph     = ebda_data->scsi.devices[scsi_device].device_info.pchs.heads;
+                npspt   = ebda_data->scsi.devices[scsi_device].device_info.pchs.spt;
+                lba     = ebda_data->scsi.devices[scsi_device].device_info.sectors;
+                blksize = ebda_data->scsi.devices[scsi_device].device_info.blksize;
+            }
+#endif
+            dpt->size      = 0x1a;
+            dpt->infos     = 0x02;  // geometry is valid
+            dpt->cylinders = npc;
+            dpt->heads     = nph;
+            dpt->spt       = npspt;
+            dpt->blksize   = blksize;
+            dpt->sector_count1 = lba;   // FIXME should be Bit64
+            dpt->sector_count2 = 0;
+        }
+
+        // EDD 2.x
+        if(size >= 0x1e) {
+            uint8_t     channel, irq, mode, checksum, i, translation;
+            uint16_t    iobase1, iobase2, options;
+            
+            dpt->size = 0x1e;
+            dpt->dpte_segment = ebda_seg;
+            dpt->dpte_offset  = (uint16_t)&EbdaData->ata.dpte;
+            
+            // Fill in dpte
+            channel = device / 2;
+            iobase1 = ebda_data->ata.channels[channel].iobase1;
+            iobase2 = ebda_data->ata.channels[channel].iobase2;
+            irq     = ebda_data->ata.channels[channel].irq;
+            mode    = ebda_data->ata.devices[device].mode;
+            translation = ebda_data->ata.devices[device].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);
+            
+            ebda_data->ata.dpte.iobase1  = iobase1;
+            ebda_data->ata.dpte.iobase2  = iobase2;
+            ebda_data->ata.dpte.prefix   = (0xe | (device % 2)) << 4;
+            ebda_data->ata.dpte.unused   = 0xcb;
+            ebda_data->ata.dpte.irq      = irq;
+            ebda_data->ata.dpte.blkcount = 1;
+            ebda_data->ata.dpte.dma      = 0;
+            ebda_data->ata.dpte.pio      = 0;
+            ebda_data->ata.dpte.options  = options;
+            ebda_data->ata.dpte.reserved = 0;
+            ebda_data->ata.dpte.revision = 0x11;
+            
+            checksum = 0;
+            for (i=0; i<15; i++)
+                checksum += read_byte(ebda_seg, (uint16_t)&EbdaData->ata.dpte + i);
+            checksum = -checksum;
+            ebda_data->ata.dpte.checksum = checksum;
+        }
+
+        // EDD 3.x
+        if(size >= 0x42) {
+            uint8_t     channel, iface, checksum, i;
+            uint16_t    iobase1;
+
+            channel = device / 2;
+            iface   = ebda_data->ata.channels[channel].iface;
+            iobase1 = ebda_data->ata.channels[channel].iobase1;
+            
+            dpt->size       = 0x42;
+            dpt->key        = 0xbedd;
+            dpt->dpi_length = 0x24;
+            dpt->reserved1  = 0;
+            dpt->reserved2  = 0;
+            
+            if (iface == ATA_IFACE_ISA) {
+                dpt->host_bus[0] = 'I';
+                dpt->host_bus[1] = 'S';
+                dpt->host_bus[2] = 'A';
+                dpt->host_bus[3] = 0;
+            }
+            else {
+                // FIXME PCI
+            }
+            dpt->iface_type[0] = 'A';
+            dpt->iface_type[1] = 'T';
+            dpt->iface_type[2] = 'A';
+            dpt->iface_type[3] = 0;
+            
+            if (iface == ATA_IFACE_ISA) {
+                ((uint16_t __far *)dpt->iface_path)[0] = iobase1;
+                ((uint16_t __far *)dpt->iface_path)[1] = 0;
+                ((uint32_t __far *)dpt->iface_path)[1] = 0;
+            }
+            else {
+                // FIXME PCI
+            }
+            ((uint16_t __far *)dpt->device_path)[0] = device & 1; // device % 2; @todo: correct?
+            ((uint16_t __far *)dpt->device_path)[1] = 0;
+            ((uint32_t __far *)dpt->device_path)[1] = 0;
+            
+            checksum = 0;
+            for (i = 30; i < 64; i++)
+                checksum += read_byte(DS, SI + i);
+            checksum = -checksum;
+            dpt->checksum = checksum;
+        }
+
+        goto int13x_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 int13x_success;
+            break;
+        default :
+            goto int13x_fail;
+        }
+        break;
+
+    case 0x50: // IBM/MS send packet command
+    default:
+        BX_INFO("%s: function %02xh unsupported, returns fail\n", __func__, GET_AH());
+        goto int13x_fail;
+        break;
+    }
+
+int13x_fail:
+    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+int13x_fail_noah:
+    SET_DISK_RET_STATUS(GET_AH());
+    SET_CF();     // error occurred
+    return;
+
+int13x_success:
+    SET_AH(0x00); // no error
+int13x_success_noah:
+    SET_DISK_RET_STATUS(0x00);
+    CLEAR_CF();   // no error
+    return;
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/ebda.h
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/ebda.h	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/ebda.h	(revision 38699)
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+
+/* Must be defined here (EBDA structures depend on these). */
+#define BX_MAX_ATA_INTERFACES   4
+#define BX_MAX_ATA_DEVICES      (BX_MAX_ATA_INTERFACES*2)
+
+#define BX_USE_ATADRV           1
+#define BX_ELTORITO_BOOT        1
+#define BX_APM                  1
+
+#ifdef VBOX_WITH_SCSI
+/* Enough for now */
+#    define BX_MAX_SCSI_DEVICES 4
+#    define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
+
+/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
+#    define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
+#    define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
+#else
+#    define BX_MAX_STORAGE_DEVICES  BX_MAX_ATA_DEVICES
+#endif
+
+
+#if 1 //BX_USE_ATADRV
+
+//@todo: does the struct really have to be misaligned?
+#pragma pack(0)
+
+typedef struct {
+    uint16_t    heads;      // # heads
+    uint16_t    cylinders;  // # cylinders
+    uint16_t    spt;        // # sectors / track
+} chs_t;
+
+  // DPTE definition
+typedef struct {
+    uint16_t    iobase1;
+    uint16_t    iobase2;
+    uint8_t     prefix;
+    uint8_t     unused;
+    uint8_t     irq;
+    uint8_t     blkcount;
+    uint8_t     dma;
+    uint8_t     pio;
+    uint16_t    options;
+    uint16_t    reserved;
+    uint8_t     revision;
+    uint8_t     checksum;
+} dpte_t;
+
+typedef struct {
+    uint8_t     iface;        // ISA or PCI
+    uint16_t    iobase1;      // IO Base 1
+    uint16_t    iobase2;      // IO Base 2
+    uint8_t     irq;          // IRQ
+} ata_channel_t;
+
+typedef struct {
+    uint8_t     type;         // Detected type of ata (ata/atapi/none/unknown/scsi)
+    uint8_t     device;       // Detected type of attached devices (hd/cd/none)
+    uint8_t     removable;    // Removable device flag
+    uint8_t     lock;         // Locks for removable devices
+    uint8_t     mode;         // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
+    uint16_t    blksize;      // block size
+
+    uint8_t     translation;  // type of translation
+    chs_t       lchs;         // Logical CHS
+    chs_t       pchs;         // Physical CHS
+
+    uint32_t    sectors;      // Total sectors count
+} ata_device_t;
+
+typedef struct {
+    // ATA channels info
+    ata_channel_t channels[BX_MAX_ATA_INTERFACES];
+
+    // ATA devices info
+    ata_device_t  devices[BX_MAX_ATA_DEVICES];
+    //
+    // map between (bios hd id - 0x80) and ata channels and scsi disks.
+    uint8_t     hdcount, hdidmap[BX_MAX_STORAGE_DEVICES];
+
+    // map between (bios cd id - 0xE0) and ata channels
+    uint8_t     cdcount, cdidmap[BX_MAX_STORAGE_DEVICES];
+
+    // Buffer for DPTE table
+    dpte_t      dpte;
+
+    // Count of transferred sectors and bytes
+    uint16_t    trsfsectors;
+    uint32_t    trsfbytes;
+} ata_t;
+
+#if BX_ELTORITO_BOOT
+  // ElTorito Device Emulation data
+typedef struct {
+    uint8_t     active;
+    uint8_t     media;
+    uint8_t     emulated_drive;
+    uint8_t     controller_index;
+    uint16_t    device_spec;
+    uint32_t    ilba;
+    uint16_t    buffer_segment;
+    uint16_t    load_segment;
+    uint16_t    sector_count;
+
+    // Virtual device
+    chs_t       vdevice;
+} cdemu_t;
+#endif // BX_ELTORITO_BOOT
+
+#ifdef VBOX_WITH_SCSI
+typedef struct {
+    // I/O port this device is attached to.
+    uint16_t        io_base;
+    // Target Id.
+    uint8_t         target_id;
+    // SCSI devices info
+    ata_device_t    device_info;
+} scsi_device_t;
+
+typedef struct {
+    // SCSI device info
+    scsi_device_t   devices[BX_MAX_SCSI_DEVICES];
+    // Number of scsi disks.
+    uint8_t         hdcount;
+} scsi_t;
+#endif
+
+#ifdef VBOX_WITH_BIOS_AHCI
+typedef struct {
+    uint16_t    iobase;
+} ahci_t;
+#endif
+
+typedef struct {
+    uint16_t    lcyl;
+    uint8_t     lhead;
+    uint8_t     sig;
+    uint8_t     spt;
+    uint8_t     resvd1[4];
+    uint16_t    cyl;
+    uint8_t     head;
+    uint8_t     resvd2[2];
+    uint8_t     lspt;
+    uint8_t     csum;
+} fdpt_t;
+
+// for access to EBDA area
+//     The EBDA structure should conform to
+//     http://www.frontiernet.net/~fys/rombios.htm document
+//     I made the ata and cdemu structs begin at 0x121 in the EBDA seg
+/* MS-DOS KEYB.COM may overwrite the word at offset 0x117 in the EBDA. */
+typedef struct {
+    unsigned char filler1[0x3D];
+
+    // FDPT - Can be split into data members if needed
+    fdpt_t  fdpt0;
+    fdpt_t  fdpt1;
+
+    unsigned char filler2[0xC4];
+
+    // ATA Driver data
+    ata_t   ata;
+
+#if BX_ELTORITO_BOOT
+    // El Torito Emulation data
+    cdemu_t cdemu;
+#endif // BX_ELTORITO_BOOT
+
+#ifdef VBOX_WITH_SCSI
+    // SCSI Driver data
+    scsi_t scsi;
+# endif
+
+#ifdef VBOX_WITH_BIOS_AHCI
+    ahci_t ahci;
+#endif
+
+    unsigned char   uForceBootDrive;
+    unsigned char   uForceBootDevice;
+} ebda_data_t;
+
+#pragma pack()
+
+// the last 16 bytes of the EBDA segment are used for the MPS floating
+// pointer structure (though only if an I/O APIC is present)
+
+#define EbdaData ((ebda_data_t *) 0)
+
+// @todo: put this elsewhere (and change/eliminate?)
+#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
+
+#endif
Index: /trunk/src/VBox/Devices/PC/BIOS-new/eltorito.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/eltorito.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/eltorito.c	(revision 38699)
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include <string.h>
+#include "inlines.h"
+#include "biosint.h"
+#include "ebda.h"
+#include "ata.h"
+
+#if DEBUG_ELTORITO
+#  define BX_DEBUG_INT13_ET(...)    BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT13_ET(...)
+#endif
+
+#if DEBUG_INT13_CD
+#  define BX_DEBUG_INT13_CD(...)    BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT13_CD(...)
+#endif
+
+//@todo: call this something else? ET_BOOT?
+#if DEBUG_ELTORITO
+#  define BX_DEBUG_ELTORITO(...)    BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_ELTORITO(...)
+#endif
+
+
+//@todo: put in a header
+#define AX      r.gr.u.r16.ax
+#define BX      r.gr.u.r16.bx
+#define CX      r.gr.u.r16.cx
+#define DX      r.gr.u.r16.dx
+#define SI      r.gr.u.r16.si
+#define DI      r.gr.u.r16.di
+#define BP      r.gr.u.r16.bp
+#define ELDX    r.gr.u.r16.sp
+#define DS      r.ds
+#define ES      r.es
+#define FLAGS   r.ra.flags.u.r16.flags
+
+
+// ---------------------------------------------------------------------------
+// Start of El-Torito boot functions
+// ---------------------------------------------------------------------------
+
+// !! TODO !! convert EBDA accesses to far pointers 
+
+extern  int     diskette_param_table;
+
+
+void BIOSCALL cdemu_init(void)
+{
+    // @TODO: a macro or a function for getting the EBDA segment
+    uint16_t    ebda_seg = read_word(0x0040,0x000E);
+    
+    // the only important data is this one for now
+    write_byte(ebda_seg,(uint16_t)&EbdaData->cdemu.active, 0x00);
+}
+
+uint8_t BIOSCALL cdemu_isactive(void)
+{
+    // @TODO: a macro or a function for getting the EBDA segment
+    uint16_t    ebda_seg = read_word(0x0040,0x000E);
+    
+    return read_byte(ebda_seg,(uint16_t)&EbdaData->cdemu.active);
+}
+
+uint8_t BIOSCALL cdemu_emulated_drive(void)
+{
+    // @TODO: a macro or a function for getting the EBDA segment
+    uint16_t    ebda_seg = read_word(0x0040,0x000E);
+    
+    return read_byte(ebda_seg,(uint16_t)&EbdaData->cdemu.emulated_drive);
+}
+
+// ---------------------------------------------------------------------------
+// Start of int13 for eltorito functions
+// ---------------------------------------------------------------------------
+
+void BIOSCALL int13_eltorito(disk_regs_t r)
+{
+    // @TODO: a macro or a function for getting the EBDA segment
+    uint16_t        ebda_seg=read_word(0x0040,0x000E);
+    cdemu_t __far   *cdemu;
+
+    cdemu = ebda_seg :> &EbdaData->cdemu;
+
+    
+    BX_DEBUG_INT13_ET("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
+    // BX_DEBUG_INT13_ET("%s: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n", __func__, get_SS(), DS, ES, DI, SI);
+    
+    switch (GET_AH()) {
+
+    // FIXME ElTorito Various. Should be implemented
+    case 0x4a: // ElTorito - Initiate disk emu
+    case 0x4c: // ElTorito - Initiate disk emu and boot
+    case 0x4d: // ElTorito - Return Boot catalog
+        BX_PANIC("%s: call with AX=%04x. Please report\n", __func__, AX);
+        goto int13_fail;
+        break;
+
+    case 0x4b: // ElTorito - Terminate disk emu
+        // FIXME ElTorito Hardcoded
+        //@todo: maybe our cdemu struct should match El Torito to allow memcpy()?
+        write_byte(DS,SI+0x00,0x13);
+        write_byte(DS,SI+0x01,cdemu->media);
+        write_byte(DS,SI+0x02,cdemu->emulated_drive);
+        write_byte(DS,SI+0x03,cdemu->controller_index);
+        write_dword(DS,SI+0x04,cdemu->ilba);
+        write_word(DS,SI+0x08,cdemu->device_spec);
+        write_word(DS,SI+0x0a,cdemu->buffer_segment);
+        write_word(DS,SI+0x0c,cdemu->load_segment);
+        write_word(DS,SI+0x0e,cdemu->sector_count);
+        write_byte(DS,SI+0x10,cdemu->vdevice.cylinders);
+        write_byte(DS,SI+0x11,cdemu->vdevice.spt);
+        write_byte(DS,SI+0x12,cdemu->vdevice.heads);
+        
+        // If we have to terminate emulation
+        if(GET_AL() == 0x00) {
+            // FIXME ElTorito Various. Should be handled accordingly to spec
+            cdemu->active = 0;  // bye bye
+        }
+
+        goto int13_success;
+        break;
+
+    default:
+          BX_INFO("%s: unsupported AH=%02x\n", __func__, GET_AH());
+          goto int13_fail;
+          break;
+    }
+
+int13_fail:
+    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+    SET_DISK_RET_STATUS(GET_AH());
+    SET_CF();     // error occurred
+    return;
+
+int13_success:
+    SET_AH(0x00); // no error
+    SET_DISK_RET_STATUS(0x00);
+    CLEAR_CF();   // no error
+    return;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 for eltorito functions
+// ---------------------------------------------------------------------------
+
+static const char isotag[]="CD001";
+static const char eltorito[]="EL TORITO SPECIFICATION";
+//
+// Returns ah: emulated drive, al: error code
+//
+uint16_t cdrom_boot(void)
+{
+    // @TODO: a macro or a function for getting the EBDA segment
+    uint16_t        ebda_seg=read_word(0x0040,0x000E);
+    uint8_t         atacmd[12], buffer[2048];
+    uint32_t        lba;
+    uint16_t        boot_segment, nbsectors, i, error;
+    uint8_t         device;
+    uint8_t         read_try;
+    cdemu_t __far   *cdemu;
+
+    cdemu = ebda_seg :> &EbdaData->cdemu;
+
+    // Find out the first cdrom
+    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;
+    
+    // Read the Boot Record Volume Descriptor
+    _fmemset(&atacmd,0,12);
+    atacmd[0]=0x28;                      // READ command
+    atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
+    atacmd[8]=(0x01 & 0x00ff);           // Sectors
+    atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
+    atacmd[3]=(0x11 & 0x00ff0000) >> 16;
+    atacmd[4]=(0x11 & 0x0000ff00) >> 8;
+    atacmd[5]=(0x11 & 0x000000ff);
+
+    for (read_try = 0; read_try <= 4; read_try++)
+    {
+        error = ata_cmd_packet(device, 12, &atacmd, 0, 2048L, ATA_DATA_IN, &buffer);
+        if (!error)
+            break;
+    }
+    if (error)
+        return 3;
+
+    // Validity checks
+    if(buffer[0]!=0)
+        return 4;
+    for(i=0;i<5;i++){
+        if(buffer[1+i] != isotag[i])
+            return 5;
+    }
+    for(i=0;i<23;i++)
+        if(buffer[7+i] != eltorito[i])
+            return 6;
+
+    //@todo: this swaps the LBA back and forth for no good reason??!
+    // ok, now we calculate the Boot catalog address
+    lba=buffer[0x4A]*0x1000000UL+buffer[0x49]*0x10000UL+buffer[0x48]*0x100UL+buffer[0x47];
+    BX_DEBUG_ELTORITO("BRVD at LBA %lx\n", lba);
+
+    // And we read the Boot Catalog
+    _fmemset(&atacmd,0,12);
+    atacmd[0]=0x28;                      // READ command
+    atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
+    atacmd[8]=(0x01 & 0x00ff);           // Sectors
+    atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
+    atacmd[3]=(lba & 0x00ff0000) >> 16;
+    atacmd[4]=(lba & 0x0000ff00) >> 8;
+    atacmd[5]=(lba & 0x000000ff);
+    if((error = ata_cmd_packet(device, 12, &atacmd, 0, 2048L, ATA_DATA_IN, &buffer)) != 0)
+        return 7;
+    
+    // Validation entry
+    if(buffer[0x00]!=0x01)
+        return 8;   // Header
+    if(buffer[0x01]!=0x00)
+        return 9;   // Platform
+    if(buffer[0x1E]!=0x55)
+        return 10;  // key 1
+    if(buffer[0x1F]!=0xAA)
+        return 10;  // key 2
+    
+    // Initial/Default Entry
+    if(buffer[0x20]!=0x88)
+        return 11; // Bootable
+
+    BX_DEBUG_ELTORITO("Emulate drive %x\n", buffer[0x21]);
+    cdemu->media = buffer[0x21];
+    if(buffer[0x21]==0){
+        // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
+        // Win2000 cd boot needs to know it booted from cd
+        cdemu->emulated_drive = 0xE0;
+    }
+    else if(buffer[0x21]<4)
+        cdemu->emulated_drive = 0x00;
+    else
+        cdemu->emulated_drive = 0x80;
+    
+    cdemu->controller_index = device/2;
+    cdemu->device_spec      = device%2;
+    
+    boot_segment=buffer[0x23]*0x100+buffer[0x22];
+    if(boot_segment==0x0000)boot_segment=0x07C0;
+    
+    cdemu->load_segment   = boot_segment;
+    cdemu->buffer_segment = 0x0000;
+    
+    nbsectors=buffer[0x27]*0x100+buffer[0x26];
+    cdemu->sector_count = nbsectors;
+
+    //@todo: pointless swapping of the LBA value?
+    lba=buffer[0x2B]*0x1000000UL+buffer[0x2A]*0x10000UL+buffer[0x29]*0x100UL+buffer[0x28];
+    cdemu->ilba = lba;
+    
+    // And we read the image in memory
+    _fmemset(&atacmd,0,12);
+    atacmd[0]=0x28;                      // READ command
+    atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8;      // Sectors
+    atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff);           // Sectors
+    atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
+    atacmd[3]=(lba & 0x00ff0000) >> 16;
+    atacmd[4]=(lba & 0x0000ff00) >> 8;
+    atacmd[5]=(lba & 0x000000ff);
+    if((error = ata_cmd_packet(device, 12, &atacmd, 0, nbsectors*512L, ATA_DATA_IN, MK_FP(boot_segment,0))) != 0)
+        return 12;
+    
+    // Remember the media type
+    switch(cdemu->media) {
+    case 0x01:  // 1.2M floppy
+        cdemu->vdevice.spt       = 15;
+        cdemu->vdevice.cylinders = 80;
+        cdemu->vdevice.heads     = 2;
+        break;
+    case 0x02:  // 1.44M floppy
+        cdemu->vdevice.spt       = 18;
+        cdemu->vdevice.cylinders = 80;
+        cdemu->vdevice.heads     = 2;
+        break;
+    case 0x03:  // 2.88M floppy
+        cdemu->vdevice.spt       = 36;
+        cdemu->vdevice.cylinders = 80;
+        cdemu->vdevice.heads     = 2;
+        break;
+    case 0x04:  // Harddrive
+        cdemu->vdevice.spt       = read_byte(boot_segment,446+6)&0x3f;
+        cdemu->vdevice.cylinders = (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1;
+        cdemu->vdevice.heads     = read_byte(boot_segment,446+5) + 1;
+        break;
+    }
+    
+    if(cdemu->media != 0) {
+        // Increase bios installed hardware number of devices
+        if(cdemu->emulated_drive == 0x00)
+            write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
+        else
+            write_byte(ebda_seg,(uint16_t)&EbdaData->ata.hdcount, read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdcount) + 1);
+    }
+    
+    
+    // everything is ok, so from now on, the emulation is active
+    if(cdemu->media !=0 )
+        cdemu->active = 0x01;
+    
+    // return the boot drive + no error
+    return (cdemu->emulated_drive*0x100)+0;
+}
+
+// ---------------------------------------------------------------------------
+// End of El-Torito boot functions
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Start of int13 when emulating a device from the cd
+// ---------------------------------------------------------------------------
+
+void BIOSCALL int13_cdemu(disk_regs_t r)
+{
+    // @TODO: a macro or a function for getting the EBDA segment
+    uint16_t        ebda_seg=read_word(0x0040,0x000E);
+    uint8_t         device, status;
+    uint16_t        vheads, vspt, vcylinders;
+    uint16_t        head, sector, cylinder, nbsectors;
+    uint32_t        vlba, ilba, slba, elba;
+    uint16_t        before, segment, offset;
+    uint8_t         atacmd[12];
+    cdemu_t __far   *cdemu;
+
+    cdemu = ebda_seg :> &EbdaData->cdemu;
+
+    BX_DEBUG_INT13_ET("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
+
+    /* at this point, we are emulating a floppy/harddisk */
+    
+    // Recompute the device number
+    device  = cdemu->controller_index * 2;
+    device += cdemu->device_spec;
+    
+    SET_DISK_RET_STATUS(0x00);
+    
+    /* basic checks : emulation should be active, dl should equal the emulated drive */
+    if( (cdemu->active ==0 )
+      || (cdemu->emulated_drive != GET_DL())) {
+        BX_INFO("%s: function %02x, emulation not active for DL= %02x\n", __func__, GET_AH(), GET_DL());
+        goto int13_fail;
+    }
+    
+    switch (GET_AH()) {
+
+    // all those functions return SUCCESS
+    case 0x00: /* disk controller reset */
+    case 0x09: /* initialize drive parameters */
+    case 0x0c: /* seek to specified cylinder */
+    case 0x0d: /* alternate disk reset */  // FIXME ElTorito Various. should really reset ?
+    case 0x10: /* check drive ready */     // FIXME ElTorito Various. should check if ready ?
+    case 0x11: /* recalibrate */
+    case 0x14: /* controller internal diagnostic */
+    case 0x16: /* detect disk change */
+        goto int13_success;
+        break;
+
+    // all those functions return disk write-protected
+    case 0x03: /* write disk sectors */
+    case 0x05: /* format disk track */
+        SET_AH(0x03);
+        goto int13_fail_noah;
+        break;
+
+    case 0x01: /* read disk status */
+        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 0x02: // read disk sectors
+    case 0x04: // verify disk sectors
+        vspt       = cdemu->vdevice.spt;
+        vcylinders = cdemu->vdevice.cylinders;
+        vheads     = cdemu->vdevice.heads;
+        ilba       = cdemu->ilba;
+        
+        sector    = GET_CL() & 0x003f;
+        cylinder  = (GET_CL() & 0x00c0) << 2 | GET_CH();
+        head      = GET_DH();
+        nbsectors = GET_AL();
+        segment   = ES;
+        offset    = BX;
+        
+        // no sector to read ?
+        if(nbsectors==0)
+            goto int13_success;
+        
+        // sanity checks sco openserver needs this!
+        if ((sector   >  vspt)
+          || (cylinder >= vcylinders)
+          || (head     >= vheads)) {
+            goto int13_fail;
+        }
+        
+        // After validating the input, verify does nothing
+        if (GET_AH() == 0x04)
+            goto int13_success;
+        
+        segment = ES+(BX / 16);
+        offset  = BX % 16;
+        
+        // calculate the virtual lba inside the image
+        vlba=((((uint32_t)cylinder*(uint32_t)vheads)+(uint32_t)head)*(uint32_t)vspt)+((uint32_t)(sector-1));
+        
+        // In advance so we don't lose the count
+        SET_AL(nbsectors);
+        
+        // start lba on cd
+        slba  = (uint32_t)vlba/4;
+        before= (uint32_t)vlba%4;
+        
+        // end lba on cd
+        elba = (uint32_t)(vlba+nbsectors-1)/4;
+        
+        _fmemset(&atacmd,0,12);
+        atacmd[0]=0x28;                      // READ command
+        atacmd[7]=((uint16_t)(elba-slba+1) & 0xff00) >> 8; // Sectors
+        atacmd[8]=((uint16_t)(elba-slba+1) & 0x00ff);      // Sectors
+        atacmd[2]=(ilba+slba & 0xff000000) >> 24;  // LBA
+        atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
+        atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
+        atacmd[5]=(ilba+slba & 0x000000ff);
+        if((status = ata_cmd_packet(device, 12, &atacmd, before*512, nbsectors*512L, ATA_DATA_IN, MK_FP(segment,offset))) != 0) {
+            BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
+            SET_AH(0x02);
+            SET_AL(0);
+            goto int13_fail_noah;
+        }
+        
+        goto int13_success;
+        break;
+
+    case 0x08: /* read disk drive parameters */
+        vspt       = cdemu->vdevice.spt;
+        vcylinders = cdemu->vdevice.cylinders - 1;
+        vheads     = cdemu->vdevice.heads - 1;
+        
+        SET_AL( 0x00 );
+        SET_BL( 0x00 );
+        SET_CH( vcylinders & 0xff );
+        SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt  & 0x3f ));
+        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(cdemu->media) {
+        case 0x01: SET_BL( 0x02 ); break;
+        case 0x02: SET_BL( 0x04 ); break;
+        case 0x03: SET_BL( 0x06 ); break;
+        }
+
+        DI = (uint16_t)&diskette_param_table;   // @todo: or really DPT2?
+        ES = 0xF000;                            // @todo: how to make this relocatable?
+        goto int13_success;
+        break;
+
+    case 0x15: /* read disk drive size */
+        // FIXME ElTorito Harddisk. What geometry to send ?
+        SET_AH(0x03);
+        goto int13_success_noah;
+        break;
+
+    // all those functions return unimplemented
+    case 0x0a: /* read disk sectors with ECC */
+    case 0x0b: /* write disk sectors with ECC */
+    case 0x18: /* set media type for format */
+    case 0x41: // IBM/MS installation check
+      // FIXME ElTorito Harddisk. Darwin would like to use EDD
+    case 0x42: // IBM/MS extended read
+    case 0x43: // IBM/MS extended write
+    case 0x44: // IBM/MS verify sectors
+    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 0x49: // IBM/MS extended media change
+    case 0x4e: // ? - set hardware configuration
+    case 0x50: // ? - send packet command
+    default:
+        BX_INFO("%s: function AH=%02x unsupported, returns fail\n", __func__, 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 BIOSCALL int13_cdrom(uint16_t EHBX, disk_regs_t r)
+{
+    uint16_t        ebda_seg=read_word(0x0040,0x000E);
+    uint8_t         device, status, locks;
+    uint8_t         atacmd[12];
+    uint32_t        lba;
+    uint16_t        count, segment, offset, size;
+    ata_t __far     *ata;
+
+    ata = ebda_seg :> &EbdaData->ata;
+
+    
+    BX_DEBUG_INT13_CD("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, 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_DEBUG("%s: function %02x, ELDL out of range %02x\n", __func__, GET_AH(), GET_ELDL());
+        goto int13_fail;
+    }
+    
+    // Get the ata channel
+    device = ata->cdidmap[GET_ELDL()-0xE0];
+    
+    /* basic check : device has to be valid  */
+    if (device >= BX_MAX_ATA_DEVICES) {
+        BX_DEBUG("%s: function %02x, unmapped device for ELDL=%02x\n", __func__, 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+(uint16_t)&Int13Ext->count);
+      segment=read_word(DS, SI+(uint16_t)&Int13Ext->segment);
+      offset=read_word(DS, SI+(uint16_t)&Int13Ext->offset);
+
+      // Can't use 64 bits lba
+      lba=read_dword(DS, SI+(uint16_t)&Int13Ext->lba2);
+      if (lba != 0L) {
+        BX_PANIC("%s: function %02x. Can't use 64bits lba\n", __func__,GET_AH());
+        goto int13_fail;
+        }
+
+      // Get 32 bits lba
+      lba=read_dword(DS, SI+(uint16_t)&Int13Ext->lba1);
+
+      // If verify or seek
+      if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
+        goto int13_success;
+
+      _fmemset(&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, &atacmd, 0, count*2048L, ATA_DATA_IN, MK_FP(segment,offset));
+
+      count = (uint16_t)(ata->trsfbytes >> 11);
+      write_word(DS, SI+(uint16_t)&Int13Ext->count, count);
+
+      if (status != 0) {
+        BX_INFO("%s: function %02x, status %02x !\n", __func__, 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 = ata->devices[device].lock;
+
+      switch (GET_AL()) {
+        case 0 :  // lock
+          if (locks == 0xff) {
+            SET_AH(0xb4);
+            SET_AL(1);
+            goto int13_fail_noah;
+            }
+          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;
+            }
+          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 = 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
+
+#if 0 //@todo: implement!
+      // 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
+#endif
+
+      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+(uint16_t)&Int13Ext->size);
+
+      // Buffer is too small
+      if(size < 0x1a)
+        goto int13_fail;
+
+      // EDD 1.x
+      if(size >= 0x1a) {
+        uint16_t   blksize;
+
+        blksize   = ata->devices[device].blksize;
+
+        write_word(DS, SI+(uint16_t)&Int13DPT->size, 0x1a);
+        write_word(DS, SI+(uint16_t)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
+        write_dword(DS, SI+(uint16_t)&Int13DPT->cylinders, 0xffffffff);
+        write_dword(DS, SI+(uint16_t)&Int13DPT->heads, 0xffffffff);
+        write_dword(DS, SI+(uint16_t)&Int13DPT->spt, 0xffffffff);
+        write_dword(DS, SI+(uint16_t)&Int13DPT->sector_count1, 0xffffffff);  // FIXME should be Bit64
+        write_dword(DS, SI+(uint16_t)&Int13DPT->sector_count2, 0xffffffff);
+        write_word(DS, SI+(uint16_t)&Int13DPT->blksize, blksize);
+        }
+
+      // EDD 2.x
+      if(size >= 0x1e) {
+        uint8_t  channel, irq, mode, checksum, i;
+        uint16_t iobase1, iobase2, options;
+
+        write_word(DS, SI+(uint16_t)&Int13DPT->size, 0x1e);
+
+        write_word(DS, SI+(uint16_t)&Int13DPT->dpte_segment, ebda_seg);
+        write_word(DS, SI+(uint16_t)&Int13DPT->dpte_offset, (uint16_t)&EbdaData->ata.dpte);
+
+        // Fill in dpte
+        channel = device / 2;
+        iobase1 = ata->channels[channel].iobase1;
+        iobase2 = ata->channels[channel].iobase2;
+        irq     = ata->channels[channel].irq;
+        mode    = 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);
+
+        ata->dpte.iobase1   = iobase1;
+        ata->dpte.iobase2   = iobase2;
+        ata->dpte.prefix    = (0xe | (device % 2))<<4;
+        ata->dpte.unused    = 0xcb;
+        ata->dpte.irq       = irq;
+        ata->dpte.blkcount  = 1 ;
+        ata->dpte.dma       = 0;
+        ata->dpte.pio       = 0;
+        ata->dpte.options   = options;
+        ata->dpte.reserved  = 0;
+        ata->dpte.revision  = 0x11;
+
+        checksum=0;
+        for (i=0; i<15; i++) checksum += read_byte(ebda_seg, (uint16_t)&EbdaData->ata.dpte + i);
+        checksum = -checksum;
+        ata->dpte.checksum = checksum;
+        }
+
+      // EDD 3.x
+      if(size >= 0x42) {
+        uint8_t  channel, iface, checksum, i;
+        uint16_t iobase1;
+
+        channel = device / 2;
+        iface   = ata->channels[channel].iface;
+        iobase1 = ata->channels[channel].iobase1;
+
+        write_word(DS, SI+(uint16_t)&Int13DPT->size, 0x42);
+        write_word(DS, SI+(uint16_t)&Int13DPT->key, 0xbedd);
+        write_byte(DS, SI+(uint16_t)&Int13DPT->dpi_length, 0x24);
+        write_byte(DS, SI+(uint16_t)&Int13DPT->reserved1, 0);
+        write_word(DS, SI+(uint16_t)&Int13DPT->reserved2, 0);
+
+        if (iface==ATA_IFACE_ISA) {
+          write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[0], 'I');
+          write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[1], 'S');
+          write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[2], 'A');
+          write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[3], 0);
+          }
+        else {
+          // FIXME PCI
+          }
+        write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[0], 'A');
+        write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[1], 'T');
+        write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[2], 'A');
+        write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[3], 0);
+
+        if (iface==ATA_IFACE_ISA) {
+          write_word(DS, SI+(uint16_t)&Int13DPT->iface_path[0], iobase1);
+          write_word(DS, SI+(uint16_t)&Int13DPT->iface_path[2], 0);
+          write_dword(DS, SI+(uint16_t)&Int13DPT->iface_path[4], 0L);
+          }
+        else {
+          // FIXME PCI
+          }
+        write_byte(DS, SI+(uint16_t)&Int13DPT->device_path[0], device%2);
+        write_byte(DS, SI+(uint16_t)&Int13DPT->device_path[1], 0);
+        write_word(DS, SI+(uint16_t)&Int13DPT->device_path[2], 0);
+        write_dword(DS, SI+(uint16_t)&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+(uint16_t)&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 */
+    case 0x08: /* read disk drive parameters */
+    case 0x0a: /* read disk sectors with ECC */
+    case 0x0b: /* write disk sectors with ECC */
+    case 0x18: /* set media type for format */
+    case 0x50: // ? - send packet command
+    default:
+      BX_INFO("%s: unsupported AH=%02x\n", __func__, 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;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 for cdrom
+// ---------------------------------------------------------------------------
Index: /trunk/src/VBox/Devices/PC/BIOS-new/floppy.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/floppy.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/floppy.c	(revision 38699)
@@ -0,0 +1,1114 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "inlines.h"
+#include "biosint.h"
+
+//////////////////////
+// FLOPPY functions //
+//////////////////////
+
+void set_diskette_ret_status(uint8_t value)
+{
+    write_byte(0x0040, 0x0041, value);
+}
+
+void set_diskette_current_cyl(uint8_t drive, uint8_t cyl)
+{
+    if (drive > 1)
+        BX_PANIC("set_diskette_current_cyl: drive > 1\n");
+    write_byte(0x0040, 0x0094+drive, cyl);
+}
+
+#if 1 //BX_SUPPORT_FLOPPY
+
+#if DEBUG_INT13_FL
+#  define BX_DEBUG_INT13_FL(...) BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT13_FL(...)
+#endif
+
+#define BX_FLOPPY_ON_CNT    37          /* 2 seconds */
+
+extern  int     diskette_param_table;   /* At a fixed location. */
+
+void floppy_reset_controller(void)
+{
+    uint8_t     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(uint16_t drive)
+{
+    uint8_t     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);
+    
+    // program data rate
+    val8 = read_byte(0x0040, 0x008b);
+    val8 >>= 6;
+    outb(0x03f7, val8);
+    
+    // wait for drive readiness
+    do {
+        val8 = inb(0x3f4);
+    } while ( (val8 & 0xc0) != 0x80 );
+    
+    if (prev_reset == 0) {
+        // turn on interrupts
+        int_enable();
+        // wait on 40:3e bit 7 to become 1
+        do {
+            val8 = read_byte(0x0040, 0x003e);
+        } while ( (val8 & 0x80) == 0 );
+        val8 &= 0x7f;
+        int_disable();
+        write_byte(0x0040, 0x003e, val8);
+    }
+}
+
+bx_bool floppy_media_known(uint16_t drive)
+{
+    uint8_t     val8;
+    uint16_t    media_state_offset;
+    
+    val8 = read_byte(0x0040, 0x003e); // diskette recal status
+    if (drive)
+        val8 >>= 1;
+    val8 &= 0x01;
+    if (val8 == 0)
+        return 0;
+    
+    media_state_offset = 0x0090;
+    if (drive)
+        media_state_offset += 1;
+    
+    val8 = read_byte(0x0040, media_state_offset);
+    val8 = (val8 >> 4) & 0x01;
+    if (val8 == 0)
+        return 0;
+    
+    // checks passed, return KNOWN
+    return 1;
+}
+
+bx_bool floppy_read_id(uint16_t drive)
+{
+    uint8_t     val8;
+    uint8_t     return_status[7];
+    int         i;
+    
+    floppy_prepare_controller(drive);
+    
+    // send Read ID command (2 bytes) to controller
+    outb(0x03f5, 0x4a);  // 4a: Read ID (MFM)
+    outb(0x03f5, drive); // 0=drive0, 1=drive1, head always 0
+    
+    // turn on interrupts
+    int_enable();
+    
+    // wait on 40:3e bit 7 to become 1
+    do {
+        val8 = (read_byte(0x0040, 0x003e) & 0x80);
+    } while ( val8 == 0 );
+    
+    val8 = 0; // separate asm from while() loop
+    // turn off interrupts
+    int_disable();
+    
+    // read 7 return status bytes from controller
+    for (i = 0; i < 7; ++i) {
+        return_status[i] = inb(0x3f5);
+    }
+    
+    if ( (return_status[0] & 0xc0) != 0 )
+        return 0;
+    else
+        return 1;
+}
+
+bx_bool floppy_drive_recal(uint16_t drive)
+{
+    uint8_t     val8;
+    uint16_t    curr_cyl_offset;
+    
+    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
+    int_enable();
+    
+    // wait on 40:3e bit 7 to become 1
+    do {
+        val8 = (read_byte(0x0040, 0x003e) & 0x80);
+    } while ( val8 == 0 );
+    
+    val8 = 0; // separate asm from while() loop
+    // turn off interrupts
+    int_disable();
+    
+    // set 40:3e bit 7 to 0, and calibrated bit
+    val8 = read_byte(0x0040, 0x003e);
+    val8 &= 0x7f;
+    if (drive) {
+        val8 |= 0x02; // Drive 1 calibrated
+        curr_cyl_offset = 0x0095;
+    } 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
+    
+    return 1;
+}
+
+
+bx_bool floppy_media_sense(uint16_t drive)
+{
+    bx_bool     retval;
+    uint16_t    media_state_offset;
+    uint8_t     drive_type, config_data, media_state;
+    
+    if (floppy_drive_recal(drive) == 0)
+        return 0;
+    
+    // Try the diskette data rates in the following order:
+    // 1 Mbps -> 500 Kbps -> 300 Kbps -> 250 Kbps
+    // The 1 Mbps rate is only tried for 2.88M drives.
+    
+    // ** config_data **
+    // Bitfields for diskette media control:
+    // Bit(s)  Description (Table M0028)
+    //  7-6  last data rate set by controller
+    //        00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+    //  5-4  last diskette drive step rate selected
+    //        00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
+    //  3-2  {data rate at start of operation}
+    //  1-0  reserved
+    
+    // ** media_state **
+    // Bitfields for diskette drive media state:
+    // Bit(s)  Description (Table M0030)
+    //  7-6  data rate
+    //    00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+    //  5  double stepping required (e.g. 360kB in 1.2MB)
+    //  4  media type established
+    //  3  drive capable of supporting 4MB media
+    //  2-0  on exit from BIOS, contains
+    //    000 trying 360kB in 360kB
+    //    001 trying 360kB in 1.2MB
+    //    010 trying 1.2MB in 1.2MB
+    //    011 360kB in 360kB established
+    //    100 360kB in 1.2MB established
+    //    101 1.2MB in 1.2MB established
+    //    110 reserved
+    //    111 all other formats/drives
+
+    // @todo: break out drive type determination
+    drive_type = inb_cmos(0x10);
+    if (drive == 0)
+        drive_type >>= 4;
+    else
+        drive_type &= 0x0f;
+    if ( drive_type == 1 ) {
+        // 360K 5.25" drive
+        config_data = 0x00; // 0000 0000
+        media_state = 0x15; // 0001 0101
+        retval = 1;
+    }
+    else if ( drive_type == 2 ) {
+        // 1.2 MB 5.25" drive
+        config_data = 0x00; // 0000 0000
+        media_state = 0x35; // 0011 0101   // need double stepping??? (bit 5)
+        retval = 1;
+    }
+    else if ( drive_type == 3 ) {
+        // 720K 3.5" drive
+        config_data = 0x00; // 0000 0000 ???
+        media_state = 0x17; // 0001 0111
+        retval = 1;
+    }
+    else if ( drive_type == 4 ) {
+        // 1.44 MB 3.5" drive
+        config_data = 0x00; // 0000 0000
+        media_state = 0x17; // 0001 0111
+        retval = 1;
+    }
+    else if ( drive_type == 5 ) {
+        // 2.88 MB 3.5" drive
+        config_data = 0xCC; // 1100 1100
+        media_state = 0xD7; // 1101 0111
+        retval = 1;
+    }
+    // Extended floppy size uses special cmos setting
+    else if ( drive_type == 6 ) {
+        // 160k 5.25" drive
+        config_data = 0x00; // 0000 0000
+        media_state = 0x27; // 0010 0111
+        retval = 1;
+    }
+    else if ( drive_type == 7 ) {
+        // 180k 5.25" drive
+        config_data = 0x00; // 0000 0000
+        media_state = 0x27; // 0010 0111
+        retval = 1;
+    }
+    else if ( drive_type == 8 ) {
+        // 320k 5.25" drive
+        config_data = 0x00; // 0000 0000
+        media_state = 0x27; // 0010 0111
+        retval = 1;
+    }
+    else {
+        // not recognized
+        config_data = 0x00; // 0000 0000
+        media_state = 0x00; // 0000 0000
+        retval = 0;
+    }
+    
+    write_byte(0x0040, 0x008B, config_data);
+    while (!floppy_read_id(drive)) {
+        if ((config_data & 0xC0) == 0x80) {
+            // If even 250 Kbps failed, we can't do much
+            break;
+        }
+        switch (config_data & 0xC0) {
+        case 0xC0:  // 1 Mbps
+            config_data = config_data & 0x3F | 0x00;
+            break;
+        case 0x00:  // 500 Kbps
+            config_data = config_data & 0x3F | 0x40;
+            break;
+        case 0x40:  // 300 Kbps
+            config_data = config_data & 0x3F | 0x80;
+            break;
+        }
+        write_byte(0x0040, 0x008B, config_data);
+    }
+    
+    if (drive == 0)
+        media_state_offset = 0x0090;
+    else
+        media_state_offset = 0x0091;
+    write_byte(0x0040, 0x008B, config_data);
+    write_byte(0x0040, media_state_offset, media_state);
+    
+    return retval;
+}
+
+
+bx_bool floppy_drive_exists(uint16_t drive)
+{
+    uint8_t     drive_type;
+    
+    // check CMOS to see if drive exists
+    // @todo: break out drive type determination
+    drive_type = inb_cmos(0x10);
+    if (drive == 0)
+        drive_type >>= 4;
+    else
+        drive_type &= 0x0f;
+    return drive_type != 0;
+}
+
+//@todo: put in a header
+#define AX      r.gr.u.r16.ax
+#define BX      r.gr.u.r16.bx
+#define CX      r.gr.u.r16.cx
+#define DX      r.gr.u.r16.dx
+#define SI      r.gr.u.r16.si
+#define DI      r.gr.u.r16.di
+#define BP      r.gr.u.r16.bp
+#define ELDX    r.gr.u.r16.sp
+#define DS      r.ds
+#define ES      r.es
+#define FLAGS   r.ra.flags.u.r16.flags
+
+void BIOSCALL int13_diskette_function(disk_regs_t r)
+{
+    uint8_t     drive, num_sectors, track, sector, head;
+    uint16_t    base_address, base_count, base_es;
+    uint8_t     page, mode_register, val8;
+    uint8_t     return_status[7];
+    uint8_t     drive_type, num_floppies, ah;
+    uint16_t    last_addr;
+    int         i;
+    
+    BX_DEBUG_INT13_FL("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
+    
+    ah = GET_AH();
+    
+    switch ( ah ) {
+    case 0x00: // diskette controller reset
+        BX_DEBUG_INT13_FL("floppy f00\n");
+        drive = GET_ELDL();
+        if (drive > 1) {
+            SET_AH(1); // invalid param
+            set_diskette_ret_status(1);
+            SET_CF();
+            return;
+        }
+        // @todo: break out drive type determination
+        drive_type = inb_cmos(0x10);
+        if (drive == 0)
+            drive_type >>= 4;
+        else
+            drive_type &= 0x0f;
+        if (drive_type == 0) {
+            SET_AH(0x80); // drive not responding
+            set_diskette_ret_status(0x80);
+            SET_CF();
+            return;
+        }
+        
+        // force re-calibration etc.
+        write_byte(0x0040, 0x003e, 0);
+        
+        SET_AH(0);
+        set_diskette_ret_status(0);
+        CLEAR_CF(); // successful
+        set_diskette_current_cyl(drive, 0); // current cylinder
+        return;
+    
+    case 0x01: // Read Diskette Status
+        CLEAR_CF();
+        val8 = read_byte(0x0000, 0x0441);
+        SET_AH(val8);
+        if (val8) {
+            SET_CF();
+        }
+        return;
+    
+    case 0x02: // Read Diskette Sectors
+    case 0x03: // Write Diskette Sectors
+    case 0x04: // Verify Diskette Sectors
+        num_sectors = GET_AL();
+        track       = GET_CH();
+        sector      = GET_CL();
+        head        = GET_DH();
+        drive       = GET_ELDL();
+        
+        if ( (drive > 1) || (head > 1) ||
+         (num_sectors == 0) || (num_sectors > 72) ) {
+            BX_INFO("%s: drive>1 || head>1 ...\n", __func__);
+            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) {
+            SET_AH(0x80); // not responding
+            set_diskette_ret_status(0x80);
+            SET_AL(0); // no sectors read
+            SET_CF(); // error occurred
+            return;
+        }
+        
+        // see if media in drive, and type is known
+        if (floppy_media_known(drive) == 0) {
+            if (floppy_media_sense(drive) == 0) {
+                SET_AH(0x0C); // Media type not found
+                set_diskette_ret_status(0x0C);
+                SET_AL(0); // no sectors read
+                SET_CF(); // error occurred
+                return;
+            }
+        }
+        
+        if (ah == 0x02) {
+            // Read Diskette Sectors
+            
+            //-----------------------------------
+            // set up DMA controller for transfer
+            //-----------------------------------
+            
+            // es:bx = pointer to where to place information from diskette
+            // port 04: DMA-1 base and current address, channel 2
+            // port 05: DMA-1 base and current count, channel 2
+            // @todo: merge/factor out pointer normalization
+            page = (ES >> 12);              // upper 4 bits
+            base_es = (ES << 4);            // lower 16bits contributed by ES
+            base_address = base_es + BX;    // lower 16 bits of address
+                                            // contributed by ES:BX
+            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
+            last_addr = base_address + base_count;
+            if (last_addr < base_address) {
+                SET_AH(0x09);
+                set_diskette_ret_status(0x09);
+                SET_AL(0); // no sectors read
+                SET_CF(); // error occurred
+                return;
+            }
+            
+            BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
+            outb(0x000a, 0x06);
+            
+            BX_DEBUG_INT13_FL("clear flip-flop\n");
+            outb(0x000c, 0x00); // clear flip-flop
+            outb(0x0004, base_address);
+            outb(0x0004, base_address>>8);
+            BX_DEBUG_INT13_FL("clear flip-flop\n");
+            outb(0x000c, 0x00); // clear flip-flop
+            outb(0x0005, base_count);
+            outb(0x0005, base_count>>8);
+            BX_DEBUG_INT13_FL("xfer buf at %x:%x\n", page, base_address);
+            
+            // port 0b: DMA-1 Mode Register
+            mode_register = 0x46; // single mode, increment, autoinit disable,
+              // transfer type=write, channel 2
+            BX_DEBUG_INT13_FL("setting mode register\n");
+            outb(0x000b, mode_register);
+            
+            BX_DEBUG_INT13_FL("setting page register\n");
+            // port 81: DMA-1 Page Register, channel 2
+            outb(0x0081, page);
+            
+            BX_DEBUG_INT13_FL("unmask chan 2\n");
+            outb(0x000a, 0x02); // unmask channel 2
+            
+            BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
+            outb(0x000a, 0x02);
+            
+            //--------------------------------------
+            // set up floppy controller for transfer
+            //--------------------------------------
+            floppy_prepare_controller(drive);
+            
+            // send read-normal-data command (9 bytes) to controller
+            outb(0x03f5, 0xe6); // e6: read normal data
+            outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
+            outb(0x03f5, track);
+            outb(0x03f5, head);
+            outb(0x03f5, sector);
+            outb(0x03f5, 2); // 512 byte sector size
+            outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
+            outb(0x03f5, 0); // Gap length
+            outb(0x03f5, 0xff); // Gap length
+            
+            // turn on interrupts
+            int_enable();
+            
+            // wait on 40:3e bit 7 to become 1
+            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
+            int_disable();
+            
+            // set 40:3e bit 7 to 0
+            val8 = read_byte(0x0040, 0x003e);
+            val8 &= 0x7f;
+            write_byte(0x0040, 0x003e, val8);
+            
+            // check port 3f4 for accessibility to status bytes
+            val8 = inb(0x3f4);
+            if ( (val8 & 0xc0) != 0xc0 )
+                BX_PANIC("%s: ctrl not ready\n", __func__);
+
+            // read 7 return status bytes from controller and store in BDA
+            for (i = 0; i < 7; ++i) {
+                return_status[i] = inb(0x3f5);
+                write_byte(0x0040, 0x0042 + i, return_status[i]);
+            }
+            
+            if ( (return_status[0] & 0xc0) != 0 ) {
+                SET_AH(0x20);
+                set_diskette_ret_status(0x20);
+                SET_AL(0); // no sectors read
+                SET_CF(); // error occurred
+                return;
+            }
+            
+            // ??? should track be new val from return_status[3] ?
+            set_diskette_current_cyl(drive, track);
+            // AL = number of sectors read (same value as passed)
+            SET_AH(0x00); // success
+            CLEAR_CF();   // success
+            return;
+        } else if (ah == 0x03) {
+            // Write Diskette Sectors
+            
+            //-----------------------------------
+            // set up DMA controller for transfer
+            //-----------------------------------
+            
+            // es:bx = pointer to where to place information from diskette
+            // port 04: DMA-1 base and current address, channel 2
+            // port 05: DMA-1 base and current count, channel 2
+            // @todo: merge/factor out pointer normalization
+            page = (ES >> 12);              // upper 4 bits
+            base_es = (ES << 4);            // lower 16bits contributed by ES
+            base_address = base_es + BX;    // lower 16 bits of address
+                                            // contributed by ES:BX
+            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
+            last_addr = base_address + base_count;
+            if (last_addr < base_address) {
+                SET_AH(0x09);
+                set_diskette_ret_status(0x09);
+                SET_AL(0); // no sectors read
+                SET_CF(); // error occurred
+                return;
+            }
+            
+            BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
+            outb(0x000a, 0x06);
+            
+            outb(0x000c, 0x00); // clear flip-flop
+            outb(0x0004, base_address);
+            outb(0x0004, base_address>>8);
+            outb(0x000c, 0x00); // clear flip-flop
+            outb(0x0005, base_count);
+            outb(0x0005, base_count>>8);
+            BX_DEBUG_INT13_FL("xfer buf at %x:%x\n", page, base_address);
+            
+            // port 0b: DMA-1 Mode Register
+            mode_register = 0x4a; // single mode, increment, autoinit disable,
+              // transfer type=read, channel 2
+            outb(0x000b, mode_register);
+            
+            // port 81: DMA-1 Page Register, channel 2
+            outb(0x0081, page);
+            
+            BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
+            outb(0x000a, 0x02);
+            
+            //--------------------------------------
+            // set up floppy controller for transfer
+            //--------------------------------------
+            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);
+            outb(0x03f5, head);
+            outb(0x03f5, sector);
+            outb(0x03f5, 2); // 512 byte sector size
+            outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
+            outb(0x03f5, 0); // Gap length
+            outb(0x03f5, 0xff); // Gap length
+            
+            // turn on interrupts
+            int_enable();
+            
+            // wait on 40:3e bit 7 to become 1
+            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 @todo: why??
+            // turn off interrupts
+            int_disable();
+            
+            // set 40:3e bit 7 to 0
+            val8 = read_byte(0x0040, 0x003e);
+            val8 &= 0x7f;
+            write_byte(0x0040, 0x003e, val8);
+            
+            // check port 3f4 for accessibility to status bytes
+            val8 = inb(0x3f4);
+            if ( (val8 & 0xc0) != 0xc0 )
+                BX_PANIC("%s: ctrl not ready\n", __func__);
+            
+            // read 7 return status bytes from controller and store in BDA
+            for (i = 0; i < 7; ++i) {
+                return_status[i] = inb(0x3f5);
+                write_byte(0x0040, 0x0042 + i, return_status[i]);
+            }
+            
+            if ( (return_status[0] & 0xc0) != 0 ) {
+                if ( (return_status[1] & 0x02) != 0 ) {
+                    // diskette not writable.
+                    // AH=status code=0x03 (tried to write on write-protected disk)
+                    // AL=number of sectors written=0
+                    AX = 0x0300;
+                    SET_CF();
+                    return;
+                } else {
+                    BX_PANIC("%s: read error\n", __func__);
+                }
+            }
+            
+            // ??? should track be new val from return_status[3] ?
+            set_diskette_current_cyl(drive, track);
+            // AL = number of sectors read (same value as passed)
+            SET_AH(0x00); // success
+            CLEAR_CF();   // success
+            return;
+        } else {  // if (ah == 0x04)
+            // Verify Diskette Sectors
+            
+            // ??? should track be new val from return_status[3] ?
+            set_diskette_current_cyl(drive, track);
+            // AL = number of sectors verified (same value as passed)
+            CLEAR_CF();   // success
+            SET_AH(0x00); // success
+            return;
+        }
+        break;
+    
+    case 0x05: // format diskette track
+        BX_DEBUG_INT13_FL("floppy f05\n");
+        
+        num_sectors = GET_AL();
+        track       = GET_CH();
+        head        = GET_DH();
+        drive       = GET_ELDL();
+        
+        if ((drive > 1) || (head > 1) || (track > 79) ||
+         (num_sectors == 0) || (num_sectors > 18)) {
+            SET_AH(1);
+            set_diskette_ret_status(1);
+            SET_CF(); // error occurred
+        }
+        
+        // see if drive exists
+        if (floppy_drive_exists(drive) == 0) {
+            SET_AH(0x80); // drive not responding
+            set_diskette_ret_status(0x80);
+            SET_CF(); // error occurred
+            return;
+        }
+        
+        // see if media in drive, and type is known
+        if (floppy_media_known(drive) == 0) {
+            if (floppy_media_sense(drive) == 0) {
+                SET_AH(0x0C); // Media type not found
+                set_diskette_ret_status(0x0C);
+                SET_AL(0); // no sectors read
+                SET_CF(); // error occurred
+            return;
+            }
+        }
+        
+        // set up DMA controller for transfer
+        // @todo: merge/factor out pointer normalization
+        page = (ES >> 12);              // upper 4 bits
+        base_es = (ES << 4);            // lower 16bits contributed by ES
+        base_address = base_es + BX;    // lower 16 bits of address
+                                        // contributed by ES:BX
+        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
+        last_addr = base_address + base_count;
+        if (last_addr < base_address) {
+            SET_AH(0x09);
+            set_diskette_ret_status(0x09);
+            SET_AL(0); // no sectors read
+            SET_CF(); // error occurred
+            return;
+        }
+        
+        outb(0x000a, 0x06);
+        outb(0x000c, 0x00); // clear flip-flop
+        outb(0x0004, base_address);
+        outb(0x0004, base_address>>8);
+        outb(0x000c, 0x00); // clear flip-flop
+        outb(0x0005, base_count);
+        outb(0x0005, base_count>>8);
+        mode_register = 0x4a; // single mode, increment, autoinit disable,
+        // transfer type=read, channel 2
+        outb(0x000b, mode_register);
+        // port 81: DMA-1 Page Register, channel 2
+        outb(0x0081, page);
+        outb(0x000a, 0x02);
+        
+        // set up floppy controller for transfer
+        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
+        outb(0x03f5, num_sectors); // number of sectors per track
+        outb(0x03f5, 0); // Gap length
+        outb(0x03f5, 0xf6); // Fill byte
+        // turn on interrupts
+        int_enable();
+        
+        // wait on 40:3e bit 7 to become 1
+        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
+        int_disable();
+        // set 40:3e bit 7 to 0
+        val8 = read_byte(0x0040, 0x003e);
+        val8 &= 0x7f;
+        write_byte(0x0040, 0x003e, val8);
+        // check port 3f4 for accessibility to status bytes
+        val8 = inb(0x3f4);
+        if ( (val8 & 0xc0) != 0xc0 )
+            BX_PANIC("%s: ctrl not ready\n", __func__);
+        
+        // read 7 return status bytes from controller and store in BDA
+        for (i = 0; i < 7; ++i) {
+            return_status[i] = inb(0x3f5);
+            write_byte(0x0040, 0x0042 + i, return_status[i]);
+        }
+        
+        if ( (return_status[0] & 0xc0) != 0 ) {
+            if ( (return_status[1] & 0x02) != 0 ) {
+                // diskette not writable.
+                // AH=status code=0x03 (tried to write on write-protected disk)
+                // AL=number of sectors written=0
+                AX = 0x0300;
+                SET_CF();
+                return;
+            } else {
+                BX_PANIC("%s: write error\n", __func__);
+            }
+        }
+        
+        SET_AH(0);
+        set_diskette_ret_status(0);
+        set_diskette_current_cyl(drive, 0);
+        CLEAR_CF(); // successful
+        return;
+    
+    
+    case 0x08: // read diskette drive parameters
+        BX_DEBUG_INT13_FL("floppy f08\n");
+        drive = GET_ELDL();
+        
+        if (drive > 1) {
+            AX = 0;
+            BX = 0;
+            CX = 0;
+            DX = 0;
+            ES = 0;
+            DI = 0;
+            SET_DL(num_floppies);
+            SET_CF();
+            return;
+        }
+        
+        // @todo: break out drive type determination
+        drive_type = inb_cmos(0x10);
+        num_floppies = 0;
+        if (drive_type & 0xf0)
+            num_floppies++;
+        if (drive_type & 0x0f)
+            num_floppies++;
+        
+        if (drive == 0)
+            drive_type >>= 4;
+        else
+            drive_type &= 0x0f;
+        
+        SET_BH(0);
+        SET_BL(drive_type);
+        SET_AH(0);
+        SET_AL(0);
+        SET_DL(num_floppies);
+        
+        switch (drive_type) {
+        case 0: // none
+            CX = 0;
+            SET_DH(0);      // max head #
+            break;
+        
+        case 1: // 360KB, 5.25"
+            CX = 0x2709;    // 40 tracks, 9 sectors
+            SET_DH(1);      // max head #
+            break;
+        
+        case 2: // 1.2MB, 5.25"
+            CX = 0x4f0f;    // 80 tracks, 15 sectors
+            SET_DH(1);      // max head #
+            break;
+        
+        case 3: // 720KB, 3.5"
+            CX = 0x4f09;    // 80 tracks, 9 sectors
+            SET_DH(1);      // max head #
+            break;
+        
+        case 4: // 1.44MB, 3.5"
+            CX = 0x4f12;    // 80 tracks, 18 sectors
+            SET_DH(1);      // max head #
+            break;
+        
+        case 5: // 2.88MB, 3.5"
+            CX = 0x4f24;    // 80 tracks, 36 sectors
+            SET_DH(1);      // max head #
+            break;
+        
+        case 6: // 160k, 5.25"
+            CX = 0x2708;    // 40 tracks, 8 sectors
+            SET_DH(0);      // max head #
+            break;
+        
+        case 7: // 180k, 5.25"
+            CX = 0x2709;    // 40 tracks, 9 sectors
+            SET_DH(0);      // max head #
+            break;
+        
+        case 8: // 320k, 5.25"
+            CX = 0x2708;    // 40 tracks, 8 sectors
+            SET_DH(1);      // max head #
+            break;
+        
+        default: // ?
+            BX_PANIC("%s: bad floppy type\n", __func__);
+        }
+        
+        /* set es & di to point to 11 byte diskette param table in ROM */
+        ES = 0xF000;    // @todo: any way to make this relocatable?
+        DI = (uint16_t)&diskette_param_table;
+        CLEAR_CF(); // success
+        /* disk status not changed upon success */
+        return;
+        
+    case 0x15: // read diskette drive type
+        BX_DEBUG_INT13_FL("floppy f15\n");
+        drive = GET_ELDL();
+        if (drive > 1) {
+            SET_AH(0); // only 2 drives supported
+            // set_diskette_ret_status here ???
+            SET_CF();
+            return;
+        }
+        // @todo: break out drive type determination
+        drive_type = inb_cmos(0x10);
+        if (drive == 0)
+            drive_type >>= 4;
+        else
+            drive_type &= 0x0f;
+        CLEAR_CF(); // successful, not present
+        if (drive_type==0) {
+            SET_AH(0); // drive not present
+        }
+        else {
+            SET_AH(1); // drive present, does not support change line
+        }
+        
+        return;
+    
+    case 0x16: // get diskette change line status
+        BX_DEBUG_INT13_FL("floppy f16\n");
+        drive = GET_ELDL();
+        if (drive > 1) {
+            SET_AH(0x01); // invalid drive
+            set_diskette_ret_status(0x01);
+            SET_CF();
+        return;
+        }
+        
+        SET_AH(0x06); // change line not supported
+        set_diskette_ret_status(0x06);
+        SET_CF();
+        return;
+        
+    case 0x17: // set diskette type for format(old)
+        BX_DEBUG_INT13_FL("floppy f17\n");
+        /* not used for 1.44M floppies */
+        SET_AH(0x01); // not supported
+        set_diskette_ret_status(1); /* not supported */
+        SET_CF();
+        return;
+    
+    case 0x18: // set diskette type for format(new)
+        BX_DEBUG_INT13_FL("floppy f18\n");
+        SET_AH(0x01); // do later
+        set_diskette_ret_status(1);
+        SET_CF();
+        return;
+    
+    default:
+        BX_INFO("%s: unsupported AH=%02x\n", __func__, GET_AH());
+    
+        // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
+        SET_AH(0x01); // ???
+        set_diskette_ret_status(1);
+        SET_CF();
+        return;
+        //   }
+    }
+}
+
+#else  // #if BX_SUPPORT_FLOPPY
+
+void BIOSCALL int13_diskette_function(disk_regs_t r)
+{
+    uint8_t  val8;
+    
+    switch ( GET_AH() ) {
+    
+    case 0x01: // Read Diskette Status
+        CLEAR_CF();
+        val8 = read_byte(0x0000, 0x0441);
+        SET_AH(val8);
+        if (val8) {
+            SET_CF();
+        }
+        return;
+    
+    default:
+        SET_CF();
+        write_byte(0x0000, 0x0441, 0x01);
+        SET_AH(0x01);
+    }
+}
+
+#endif  // #if BX_SUPPORT_FLOPPY
+
+#if 0
+void determine_floppy_media(uint16_t drive)
+{
+    uint8_t     val8, DOR, ctrl_info;
+    
+    ctrl_info = read_byte(0x0040, 0x008F);
+    if (drive==1)
+        ctrl_info >>= 4;
+    else
+        ctrl_info &= 0x0f;
+
+#if 0
+    if (drive == 0) {
+        DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
+    }
+    else {
+        DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
+    }
+#endif
+
+    if ( (ctrl_info & 0x04) != 0x04 ) {
+        // Drive not determined means no drive exists, done.
+        return;
+    }
+
+#if 0
+    // check Main Status Register for readiness
+    val8 = inb(0x03f4) & 0x80; // Main Status Register
+    if (val8 != 0x80)
+    BX_PANIC("d_f_m: MRQ bit not set\n");
+    
+    // change line
+    
+    // existing BDA values
+    
+    // turn on drive motor
+    outb(0x03f2, DOR); // Digital Output Register
+    //
+#endif
+    BX_PANIC("d_f_m: OK so far\n");
+}
+#endif
+
Index: /trunk/src/VBox/Devices/PC/BIOS-new/font8x8.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/font8x8.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/font8x8.inc	(revision 38699)
@@ -0,0 +1,133 @@
+; 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 in the public domain
+
+font8x8:
+		db	000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+		db	07eh, 081h, 0a5h, 081h, 0bdh, 099h, 081h, 07eh
+		db	07eh, 0ffh, 0dbh, 0ffh, 0c3h, 0e7h, 0ffh, 07eh
+		db	06ch, 0feh, 0feh, 0feh, 07ch, 038h, 010h, 000h
+		db	010h, 038h, 07ch, 0feh, 07ch, 038h, 010h, 000h
+		db	038h, 07ch, 038h, 0feh, 0feh, 07ch, 038h, 07ch
+		db	010h, 010h, 038h, 07ch, 0feh, 07ch, 038h, 07ch
+		db	000h, 000h, 018h, 03ch, 03ch, 018h, 000h, 000h
+		db	0ffh, 0ffh, 0e7h, 0c3h, 0c3h, 0e7h, 0ffh, 0ffh
+		db	000h, 03ch, 066h, 042h, 042h, 066h, 03ch, 000h
+		db	0ffh, 0c3h, 099h, 0bdh, 0bdh, 099h, 0c3h, 0ffh
+		db	00fh, 007h, 00fh, 07dh, 0cch, 0cch, 0cch, 078h
+		db	03ch, 066h, 066h, 066h, 03ch, 018h, 07eh, 018h
+		db	03fh, 033h, 03fh, 030h, 030h, 070h, 0f0h, 0e0h
+		db	07fh, 063h, 07fh, 063h, 063h, 067h, 0e6h, 0c0h
+		db	099h, 05ah, 03ch, 0e7h, 0e7h, 03ch, 05ah, 099h
+		db	080h, 0e0h, 0f8h, 0feh, 0f8h, 0e0h, 080h, 000h
+		db	002h, 00eh, 03eh, 0feh, 03eh, 00eh, 002h, 000h
+		db	018h, 03ch, 07eh, 018h, 018h, 07eh, 03ch, 018h
+		db	066h, 066h, 066h, 066h, 066h, 000h, 066h, 000h
+		db	07fh, 0dbh, 0dbh, 07bh, 01bh, 01bh, 01bh, 000h
+		db	03eh, 063h, 038h, 06ch, 06ch, 038h, 0cch, 078h
+		db	000h, 000h, 000h, 000h, 07eh, 07eh, 07eh, 000h
+		db	018h, 03ch, 07eh, 018h, 07eh, 03ch, 018h, 0ffh
+		db	018h, 03ch, 07eh, 018h, 018h, 018h, 018h, 000h
+		db	018h, 018h, 018h, 018h, 07eh, 03ch, 018h, 000h
+		db	000h, 018h, 00ch, 0feh, 00ch, 018h, 000h, 000h
+		db	000h, 030h, 060h, 0feh, 060h, 030h, 000h, 000h
+		db	000h, 000h, 0c0h, 0c0h, 0c0h, 0feh, 000h, 000h
+		db	000h, 024h, 066h, 0ffh, 066h, 024h, 000h, 000h
+		db	000h, 018h, 03ch, 07eh, 0ffh, 0ffh, 000h, 000h
+		db	000h, 0ffh, 0ffh, 07eh, 03ch, 018h, 000h, 000h
+		db	000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+		db	030h, 078h, 078h, 030h, 030h, 000h, 030h, 000h
+		db	06ch, 06ch, 06ch, 000h, 000h, 000h, 000h, 000h
+		db	06ch, 06ch, 0feh, 06ch, 0feh, 06ch, 06ch, 000h
+		db	030h, 07ch, 0c0h, 078h, 00ch, 0f8h, 030h, 000h
+		db	000h, 0c6h, 0cch, 018h, 030h, 066h, 0c6h, 000h
+		db	038h, 06ch, 038h, 076h, 0dch, 0cch, 076h, 000h
+		db	060h, 060h, 0c0h, 000h, 000h, 000h, 000h, 000h
+		db	018h, 030h, 060h, 060h, 060h, 030h, 018h, 000h
+		db	060h, 030h, 018h, 018h, 018h, 030h, 060h, 000h
+		db	000h, 066h, 03ch, 0ffh, 03ch, 066h, 000h, 000h
+		db	000h, 030h, 030h, 0fch, 030h, 030h, 000h, 000h
+		db	000h, 000h, 000h, 000h, 000h, 030h, 030h, 060h
+		db	000h, 000h, 000h, 0fch, 000h, 000h, 000h, 000h
+		db	000h, 000h, 000h, 000h, 000h, 030h, 030h, 000h
+		db	006h, 00ch, 018h, 030h, 060h, 0c0h, 080h, 000h
+		db	07ch, 0c6h, 0ceh, 0deh, 0f6h, 0e6h, 07ch, 000h
+		db	030h, 070h, 030h, 030h, 030h, 030h, 0fch, 000h
+		db	078h, 0cch, 00ch, 038h, 060h, 0cch, 0fch, 000h
+		db	078h, 0cch, 00ch, 038h, 00ch, 0cch, 078h, 000h
+		db	01ch, 03ch, 06ch, 0cch, 0feh, 00ch, 01eh, 000h
+		db	0fch, 0c0h, 0f8h, 00ch, 00ch, 0cch, 078h, 000h
+		db	038h, 060h, 0c0h, 0f8h, 0cch, 0cch, 078h, 000h
+		db	0fch, 0cch, 00ch, 018h, 030h, 030h, 030h, 000h
+		db	078h, 0cch, 0cch, 078h, 0cch, 0cch, 078h, 000h
+		db	078h, 0cch, 0cch, 07ch, 00ch, 018h, 070h, 000h
+		db	000h, 030h, 030h, 000h, 000h, 030h, 030h, 000h
+		db	000h, 030h, 030h, 000h, 000h, 030h, 030h, 060h
+		db	018h, 030h, 060h, 0c0h, 060h, 030h, 018h, 000h
+		db	000h, 000h, 0fch, 000h, 000h, 0fch, 000h, 000h
+		db	060h, 030h, 018h, 00ch, 018h, 030h, 060h, 000h
+		db	078h, 0cch, 00ch, 018h, 030h, 000h, 030h, 000h
+		db	07ch, 0c6h, 0deh, 0deh, 0deh, 0c0h, 078h, 000h
+		db	030h, 078h, 0cch, 0cch, 0fch, 0cch, 0cch, 000h
+		db	0fch, 066h, 066h, 07ch, 066h, 066h, 0fch, 000h
+		db	03ch, 066h, 0c0h, 0c0h, 0c0h, 066h, 03ch, 000h
+		db	0f8h, 06ch, 066h, 066h, 066h, 06ch, 0f8h, 000h
+		db	0feh, 062h, 068h, 078h, 068h, 062h, 0feh, 000h
+		db	0feh, 062h, 068h, 078h, 068h, 060h, 0f0h, 000h
+		db	03ch, 066h, 0c0h, 0c0h, 0ceh, 066h, 03eh, 000h
+		db	0cch, 0cch, 0cch, 0fch, 0cch, 0cch, 0cch, 000h
+		db	078h, 030h, 030h, 030h, 030h, 030h, 078h, 000h
+		db	01eh, 00ch, 00ch, 00ch, 0cch, 0cch, 078h, 000h
+		db	0e6h, 066h, 06ch, 078h, 06ch, 066h, 0e6h, 000h
+		db	0f0h, 060h, 060h, 060h, 062h, 066h, 0feh, 000h
+		db	0c6h, 0eeh, 0feh, 0feh, 0d6h, 0c6h, 0c6h, 000h
+		db	0c6h, 0e6h, 0f6h, 0deh, 0ceh, 0c6h, 0c6h, 000h
+		db	038h, 06ch, 0c6h, 0c6h, 0c6h, 06ch, 038h, 000h
+		db	0fch, 066h, 066h, 07ch, 060h, 060h, 0f0h, 000h
+		db	078h, 0cch, 0cch, 0cch, 0dch, 078h, 01ch, 000h
+		db	0fch, 066h, 066h, 07ch, 06ch, 066h, 0e6h, 000h
+		db	078h, 0cch, 0e0h, 070h, 01ch, 0cch, 078h, 000h
+		db	0fch, 0b4h, 030h, 030h, 030h, 030h, 078h, 000h
+		db	0cch, 0cch, 0cch, 0cch, 0cch, 0cch, 0fch, 000h
+		db	0cch, 0cch, 0cch, 0cch, 0cch, 078h, 030h, 000h
+		db	0c6h, 0c6h, 0c6h, 0d6h, 0feh, 0eeh, 0c6h, 000h
+		db	0c6h, 0c6h, 06ch, 038h, 038h, 06ch, 0c6h, 000h
+		db	0cch, 0cch, 0cch, 078h, 030h, 030h, 078h, 000h
+		db	0feh, 0c6h, 08ch, 018h, 032h, 066h, 0feh, 000h
+		db	078h, 060h, 060h, 060h, 060h, 060h, 078h, 000h
+		db	0c0h, 060h, 030h, 018h, 00ch, 006h, 002h, 000h
+		db	078h, 018h, 018h, 018h, 018h, 018h, 078h, 000h
+		db	010h, 038h, 06ch, 0c6h, 000h, 000h, 000h, 000h
+		db	000h, 000h, 000h, 000h, 000h, 000h, 000h, 0ffh
+		db	030h, 030h, 018h, 000h, 000h, 000h, 000h, 000h
+		db	000h, 000h, 078h, 00ch, 07ch, 0cch, 076h, 000h
+		db	0e0h, 060h, 060h, 07ch, 066h, 066h, 0dch, 000h
+		db	000h, 000h, 078h, 0cch, 0c0h, 0cch, 078h, 000h
+		db	01ch, 00ch, 00ch, 07ch, 0cch, 0cch, 076h, 000h
+		db	000h, 000h, 078h, 0cch, 0fch, 0c0h, 078h, 000h
+		db	038h, 06ch, 060h, 0f0h, 060h, 060h, 0f0h, 000h
+		db	000h, 000h, 076h, 0cch, 0cch, 07ch, 00ch, 0f8h
+		db	0e0h, 060h, 06ch, 076h, 066h, 066h, 0e6h, 000h
+		db	030h, 000h, 070h, 030h, 030h, 030h, 078h, 000h
+		db	00ch, 000h, 00ch, 00ch, 00ch, 0cch, 0cch, 078h
+		db	0e0h, 060h, 066h, 06ch, 078h, 06ch, 0e6h, 000h
+		db	070h, 030h, 030h, 030h, 030h, 030h, 078h, 000h
+		db	000h, 000h, 0cch, 0feh, 0feh, 0d6h, 0c6h, 000h
+		db	000h, 000h, 0f8h, 0cch, 0cch, 0cch, 0cch, 000h
+		db	000h, 000h, 078h, 0cch, 0cch, 0cch, 078h, 000h
+		db	000h, 000h, 0dch, 066h, 066h, 07ch, 060h, 0f0h
+		db	000h, 000h, 076h, 0cch, 0cch, 07ch, 00ch, 01eh
+		db	000h, 000h, 0dch, 076h, 066h, 060h, 0f0h, 000h
+		db	000h, 000h, 07ch, 0c0h, 078h, 00ch, 0f8h, 000h
+		db	010h, 030h, 07ch, 030h, 030h, 034h, 018h, 000h
+		db	000h, 000h, 0cch, 0cch, 0cch, 0cch, 076h, 000h
+		db	000h, 000h, 0cch, 0cch, 0cch, 078h, 030h, 000h
+		db	000h, 000h, 0c6h, 0d6h, 0feh, 0feh, 06ch, 000h
+		db	000h, 000h, 0c6h, 06ch, 038h, 06ch, 0c6h, 000h
+		db	000h, 000h, 0cch, 0cch, 0cch, 07ch, 00ch, 0f8h
+		db	000h, 000h, 0fch, 098h, 030h, 064h, 0fch, 000h
+		db	01ch, 030h, 030h, 0e0h, 030h, 030h, 01ch, 000h
+		db	018h, 018h, 018h, 000h, 018h, 018h, 018h, 000h
+		db	0e0h, 030h, 030h, 01ch, 030h, 030h, 0e0h, 000h
+		db	076h, 0dch, 000h, 000h, 000h, 000h, 000h, 000h
+		db	000h, 010h, 038h, 06ch, 0c6h, 0c6h, 0feh, 000h
Index: /trunk/src/VBox/Devices/PC/BIOS-new/inlines.h
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/inlines.h	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/inlines.h	(revision 38699)
@@ -0,0 +1,80 @@
+/** @file
+ * Inline routines for Watcom C.
+ */
+
+/*
+ * Copyright (C) 2010-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+extern unsigned inp(unsigned port);
+extern unsigned outp(unsigned port, unsigned value);
+extern unsigned inpw(unsigned port);
+extern unsigned outpw(unsigned port, unsigned value);
+#pragma intrinsic(inp,outp,inpw,outpw)
+#define inb(p)      inp(p)
+#define outb(p, v)  outp(p, v)
+#define inw(p)      inpw(p)
+#define outw(p, v)  outpw(p, v)
+
+extern  uint8_t     read_byte(uint16_t seg, uint16_t offset);
+extern  uint16_t    read_word(uint16_t seg, uint16_t offset);
+extern  uint32_t    read_dword(uint16_t seg, uint16_t offset);
+extern  void        write_byte(uint16_t seg, uint16_t offset, uint8_t data);
+extern  void        write_word(uint16_t seg, uint16_t offset, uint16_t data);
+extern  void        write_dword(uint16_t seg, uint16_t offset, uint32_t data);
+
+void int_enable(void);
+#pragma aux int_enable = "sti" modify exact [] nomemory;
+
+void int_disable(void);
+#pragma aux int_disable = "cli" modify exact [] nomemory;
+
+uint16_t int_query(void);
+#pragma aux int_query =     \
+    "pushf"                 \
+    "pop    ax"             \
+    value [ax] modify exact [ax] nomemory;
+
+void int_restore(uint16_t old_flags);
+#pragma aux int_restore =   \
+    "push   ax"             \
+    "popf"                  \
+    parm [ax] modify exact [] nomemory;
+
+void halt(void);
+#pragma aux halt = "hlt" modify exact [] nomemory;
+
+void halt_forever(void);
+#pragma aux halt_forever =  \
+    "forever:"              \
+    "hlt"                   \
+    "jmp forever"           \
+    modify exact [] nomemory aborts;
+
+char __far *rep_insb(char __far *buffer, unsigned nbytes, unsigned port);
+#pragma aux rep_insb = ".286" "rep insb" parm [es di] [cx] [dx] value [es di] modify exact [cx di];
+
+char __far *rep_insw(char __far *buffer, unsigned nwords, unsigned port);
+#pragma aux rep_insw = ".286" "rep insw" parm [es di] [cx] [dx] value [es di] modify exact [cx di];
+
+char __far *rep_insd(char __far *buffer, unsigned ndwords, unsigned port);
+#pragma aux rep_insd = ".386" "rep insd" parm [es di] [cx] [dx] value [es di] modify exact [cx di];
+
+char __far *rep_outsb(char __far *buffer, unsigned nbytes, unsigned port);
+#pragma aux rep_outsb = ".286" "rep outs dx,byte ptr es:[si]" parm [es si] [cx] [dx] value [es si] modify exact [cx si];
+
+char __far *rep_outsw(char __far *buffer, unsigned nwords, unsigned port);
+#pragma aux rep_outsw = ".286" "rep outs dx,word ptr es:[si]" parm [es si] [cx] [dx] value [es si] modify exact [cx si];
+
+char __far *rep_outsd(char __far *buffer, unsigned ndwords, unsigned port);
+#pragma aux rep_outsd = ".386" "rep outs dx,dword ptr es:[si]" parm [es si] [cx] [dx] value [es si] modify exact [cx si];
+
Index: /trunk/src/VBox/Devices/PC/BIOS-new/keyboard.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/keyboard.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/keyboard.c	(revision 38699)
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "inlines.h"
+#include "biosint.h"
+
+#if DEBUG_INT16
+#  define BX_DEBUG_INT16(...) BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT16(...)
+#endif
+
+extern  void    post(void);
+#pragma aux post "*";
+
+void jmp_post(void);
+#pragma aux jmp_post = "jmp far ptr post" aborts;
+
+#define none 0
+#define MAX_SCAN_CODE 0x58
+
+struct {
+    uint16_t    normal;
+    uint16_t    shift;
+    uint16_t    control;
+    uint16_t    alt;
+    uint8_t     lock_flags;
+} static const scan_to_scanascii[MAX_SCAN_CODE + 1] = {
+    {   none,   none,   none,   none, none },
+    { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
+    { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
+    { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
+    { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
+    { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
+    { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
+    { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
+    { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
+    { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
+    { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
+    { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
+    { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
+    { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
+    { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
+    { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
+    { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
+    { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
+    { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
+    { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
+    { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
+    { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
+    { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
+    { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
+    { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
+    { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
+    { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
+    { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
+    { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
+    {   none,   none,   none,   none, none }, /* L Ctrl */
+    { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
+    { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
+    { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
+    { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
+    { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
+    { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
+    { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
+    { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
+    { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
+    { 0x273b, 0x273a,   none,   none, none }, /* ;: */
+    { 0x2827, 0x2822,   none,   none, none }, /* '" */
+    { 0x2960, 0x297e,   none,   none, none }, /* `~ */
+    {   none,   none,   none,   none, none }, /* L shift */
+    { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
+    { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
+    { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
+    { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
+    { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
+    { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
+    { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
+    { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
+    { 0x332c, 0x333c,   none,   none, none }, /* ,< */
+    { 0x342e, 0x343e,   none,   none, none }, /* .> */
+    { 0x352f, 0x353f,   none,   none, none }, /* /? */
+    {   none,   none,   none,   none, none }, /* R Shift */
+    { 0x372a, 0x372a,   none,   none, none }, /* * */
+    {   none,   none,   none,   none, none }, /* L Alt */
+    { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
+    {   none,   none,   none,   none, none }, /* caps lock */
+    { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
+    { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
+    { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
+    { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
+    { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
+    { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
+    { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
+    { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
+    { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
+    { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
+    {   none,   none,   none,   none, none }, /* Num Lock */
+    {   none,   none,   none,   none, none }, /* Scroll Lock */
+    { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
+    { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
+    { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
+    { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
+    { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
+    { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
+    { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
+    { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
+    { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
+    { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
+    { 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 },
+    { 0x565c, 0x567c,   none,   none, none }, /* \| */
+    { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
+    { 0x8600, 0x8800, 0x8a00, 0x8c00, none }  /* F12 */
+};
+
+
+/* Keyboard initialization. */
+
+//--------------------------------------------------------------------------
+// keyboard_panic
+//--------------------------------------------------------------------------
+void keyboard_panic(uint16_t status)
+{
+    // If you're getting a 993 keyboard panic here,
+    // please see the comment in keyboard_init
+    
+    BX_PANIC("Keyboard error:%u\n",status);
+}
+
+
+//--------------------------------------------------------------------------
+// keyboard_init
+//--------------------------------------------------------------------------
+// this file is based on LinuxBIOS implementation of keyboard.c
+// could convert to #asm to gain space
+void BIOSCALL keyboard_init(void)
+{
+    uint16_t    max;
+
+    /* ------------------- controller side ----------------------*/
+    /* send cmd = 0xAA, self test 8042 */
+    outb(0x64, 0xaa);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
+    if (max==0x0) keyboard_panic(00);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
+    if (max==0x0) keyboard_panic(01);
+
+    /* read self-test result, 0x55 should be returned from 0x60 */
+    if ((inb(0x60) != 0x55)){
+        keyboard_panic(991);
+    }
+
+    /* send cmd = 0xAB, keyboard interface test */
+    outb(0x64,0xab);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
+    if (max==0x0) keyboard_panic(10);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
+    if (max==0x0) keyboard_panic(11);
+
+    /* read keyboard interface test result, */
+    /* 0x00 should be returned form 0x60 */
+    if ((inb(0x60) != 0x00)) {
+        keyboard_panic(992);
+    }
+
+    /* ------------------- keyboard side ------------------------*/
+    /* reset keyboard and self test  (keyboard side) */
+    /* also enables the keyboard interface */
+    outb(0x60, 0xff);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
+    if (max==0x0) keyboard_panic(20);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
+    if (max==0x0) keyboard_panic(21);
+
+    /* keyboard should return ACK */
+    if ((inb(0x60) != 0xfa)) {
+        keyboard_panic(993);
+    }
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
+    if (max==0x0) keyboard_panic(31);
+
+    if ((inb(0x60) != 0xaa && inb(0x60) != 0xaa)) {
+        keyboard_panic(994);
+    }
+
+    /* Disable keyboard */
+    outb(0x60, 0xf5);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
+    if (max==0x0) keyboard_panic(40);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
+    if (max==0x0) keyboard_panic(41);
+
+    /* keyboard should return ACK */
+    if ((inb(0x60) != 0xfa)) {
+        keyboard_panic(995);
+    }
+
+    /* Write Keyboard Mode */
+    outb(0x64, 0x60);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
+    if (max==0x0) keyboard_panic(50);
+
+    /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
+    outb(0x60, 0x65);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
+    if (max==0x0) keyboard_panic(60);
+
+    /* Enable keyboard */
+    outb(0x60, 0xf4);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
+    if (max==0x0) keyboard_panic(70);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
+    if (max==0x0) keyboard_panic(70);
+
+    /* keyboard should return ACK */
+    if ((inb(0x60) != 0xfa)) {
+        keyboard_panic(996);
+    }
+
+    /* Enable aux interface */
+    outb(0x64,0xa8);
+}
+
+
+unsigned int enqueue_key(uint8_t scan_code, uint8_t ascii_code)
+{
+    uint16_t    buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
+    
+#if BX_CPU < 2
+    buffer_start = 0x001E;
+    buffer_end   = 0x003E;
+#else
+    buffer_start = read_word(0x0040, 0x0080);
+    buffer_end   = read_word(0x0040, 0x0082);
+#endif
+    
+    buffer_head = read_word(0x0040, 0x001A);
+    buffer_tail = read_word(0x0040, 0x001C);
+    
+    temp_tail = buffer_tail;
+    buffer_tail += 2;
+    if (buffer_tail >= buffer_end)
+        buffer_tail = buffer_start;
+    
+    if (buffer_tail == buffer_head)
+        return(0);
+    
+    write_byte(0x0040, temp_tail, ascii_code);
+    write_byte(0x0040, temp_tail+1, scan_code);
+    write_word(0x0040, 0x001C, buffer_tail);
+    return(1);
+}
+
+
+/* Keyboard hardware interrupt handler. */
+//@todo: should this be declared as taking arguments at all?
+void BIOSCALL int09_function(uint16_t ES, uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP,
+                             uint16_t BX, uint16_t DX, uint16_t CX, uint16_t AX)
+{
+    uint8_t scancode, asciicode, shift_flags;
+    uint8_t mf2_flags, mf2_state;
+    
+    //
+    // DS has been set to F000 before call
+    //
+    
+    
+    scancode = GET_AL();
+    
+    if (scancode == 0) {
+        BX_INFO("KBD: int09 handler: AL=0\n");
+        return;
+    }
+    
+    
+    shift_flags = read_byte(0x0040, 0x17);
+    mf2_flags = read_byte(0x0040, 0x18);
+    mf2_state = read_byte(0x0040, 0x96);
+    asciicode = 0;
+    
+    switch (scancode) {
+    case 0x3a: /* Caps Lock press */
+        shift_flags ^= 0x40;
+        write_byte(0x0040, 0x17, shift_flags);
+        mf2_flags |= 0x40;
+        write_byte(0x0040, 0x18, mf2_flags);
+        break;
+    case 0xba: /* Caps Lock release */
+        mf2_flags &= ~0x40;
+        write_byte(0x0040, 0x18, mf2_flags);
+        break;
+    
+    case 0x2a: /* L Shift press */
+        shift_flags |= 0x02;
+        write_byte(0x0040, 0x17, shift_flags);
+        break;
+    case 0xaa: /* L Shift release */
+        shift_flags &= ~0x02;
+        write_byte(0x0040, 0x17, shift_flags);
+        break;
+    
+    case 0x36: /* R Shift press */
+        shift_flags |= 0x01;
+        write_byte(0x0040, 0x17, shift_flags);
+        break;
+    case 0xb6: /* R Shift release */
+        shift_flags &= ~0x01;
+        write_byte(0x0040, 0x17, shift_flags);
+        break;
+    
+    case 0x1d: /* Ctrl press */
+        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 */
+        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 & 0x02) {
+            mf2_state |= 0x08;
+            write_byte(0x0040, 0x96, mf2_state);
+        } else {
+            mf2_flags |= 0x02;
+            write_byte(0x0040, 0x18, mf2_flags);
+        }
+        break;
+    case 0xb8: /* Alt release */
+        shift_flags &= ~0x08;
+        write_byte(0x0040, 0x17, shift_flags);
+        if (mf2_state & 0x02) {
+            mf2_state &= ~0x08;
+            write_byte(0x0040, 0x96, mf2_state);
+        } else {
+            mf2_flags &= ~0x02;
+            write_byte(0x0040, 0x18, mf2_flags);
+        }
+        break;
+    
+    case 0x45: /* Num Lock press */
+        if ((mf2_state & 0x03) == 0) {
+            mf2_flags |= 0x20;
+            write_byte(0x0040, 0x18, mf2_flags);
+            shift_flags ^= 0x20;
+            write_byte(0x0040, 0x17, shift_flags);
+        }
+        break;
+    case 0xc5: /* Num Lock release */
+        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;
+        write_byte(0x0040, 0x17, shift_flags);
+        break;
+    
+    case 0xc6: /* Scroll Lock release */
+        mf2_flags &= ~0x10;
+        write_byte(0x0040, 0x18, mf2_flags);
+        break;
+    
+    case 0x53: /* Del press */
+        if ((shift_flags & 0x0f) == 0x0c)
+            jmp_post();
+        /* fall through */
+    
+    default:
+        if (scancode & 0x80) {
+            break; /* toss key releases ... */
+        }
+        if (scancode > MAX_SCAN_CODE) {
+            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 */
+            asciicode = scan_to_scanascii[scancode].control;
+            scancode = scan_to_scanascii[scancode].control >> 8;
+        } 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 {
+                asciicode = scan_to_scanascii[scancode].shift;
+                scancode  = scan_to_scanascii[scancode].shift >> 8;
+            }
+        } 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 {
+                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;
+    }
+    if ((scancode & 0x7f) != 0x1d) {
+        mf2_state &= ~0x01;
+    }
+    mf2_state &= ~0x02;
+    write_byte(0x0040, 0x96, mf2_state);
+}
+
+unsigned int dequeue_key(uint8_t __far *scan_code, uint8_t __far *ascii_code, unsigned incr)
+{
+    uint16_t    buffer_start, buffer_end, buffer_head, buffer_tail;
+    uint8_t     acode, scode;
+    
+#if BX_CPU < 2
+    buffer_start = 0x001E;
+    buffer_end   = 0x003E;
+#else
+    buffer_start = read_word(0x0040, 0x0080);
+    buffer_end   = read_word(0x0040, 0x0082);
+#endif
+    
+    buffer_head = read_word(0x0040, 0x001a);
+    buffer_tail = read_word(0x0040, 0x001c);
+    
+    if (buffer_head != buffer_tail) {
+        acode = read_byte(0x0040, buffer_head);
+        scode = read_byte(0x0040, buffer_head+1);
+        *ascii_code = acode;
+        *scan_code  = scode;
+        
+        if (incr) {
+            buffer_head += 2;
+            if (buffer_head >= buffer_end)
+                buffer_head = buffer_start;
+            write_word(0x0040, 0x001a, buffer_head);
+        }
+        return(1);
+    }
+    else {
+        return(0);
+    }
+}
+
+
+//@todo: move somewhere else?
+#define AX      r.gr.u.r16.ax
+#define BX      r.gr.u.r16.bx
+#define CX      r.gr.u.r16.cx
+#define DX      r.gr.u.r16.dx
+#define SI      r.gr.u.r16.si
+#define DI      r.gr.u.r16.di
+#define BP      r.gr.u.r16.bp
+#define SP      r.gr.u.r16.sp
+#define FLAGS   r.fl.u.r16.flags
+
+/* Interrupt 16h service implementation. */
+
+void BIOSCALL int16_function(volatile kbd_regs_t r)
+{
+    uint8_t     scan_code, ascii_code, shift_flags, led_flags, count;
+    uint16_t    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) {
+        int_disable();    //@todo: interrupts should be disabled already??
+        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);
+        }
+        int_enable();
+    }
+    
+    switch (GET_AH()) {
+    case 0x00: /* read keyboard input */
+        if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
+            BX_PANIC("KBD: int16h: out of keyboard input\n");
+        }
+        if (scan_code !=0 && ascii_code == 0xF0)
+            ascii_code = 0;
+        else if (ascii_code == 0xE0)
+            ascii_code = 0;
+        AX = (scan_code << 8) | ascii_code;
+        break;
+    
+    case 0x01: /* check keyboard status */
+        if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
+            SET_ZF();
+            return;
+        }
+        if (scan_code !=0 && ascii_code == 0xF0)
+            ascii_code = 0;
+        else if (ascii_code == 0xE0)
+            ascii_code = 0;
+        AX = (scan_code << 8) | ascii_code;
+        CLEAR_ZF();
+        break;
+    
+    case 0x02: /* get shift flag status */
+        shift_flags = read_byte(0x0040, 0x17);
+        SET_AL(shift_flags);
+        break;
+    
+    case 0x05: /* store key-stroke into buffer */
+        if ( !enqueue_key(GET_CH(), GET_CL()) ) {
+            SET_AL(1);
+        }
+        else {
+            SET_AL(0);
+        }
+        break;
+    
+    case 0x09: /* GET KEYBOARD FUNCTIONALITY */
+        // bit Bochs Description
+        //  7    0   reserved
+        //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
+        //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
+        //  4    1   INT 16/AH=0Ah supported
+        //  3    0   INT 16/AX=0306h supported
+        //  2    0   INT 16/AX=0305h supported
+        //  1    0   INT 16/AX=0304h supported
+        //  0    0   INT 16/AX=0300h supported
+        //
+        SET_AL(0x30);
+        break;
+        
+    case 0x0A: /* GET KEYBOARD ID */
+        count = 2;
+        kbd_code = 0x0;
+        outb(0x60, 0xf2);
+        /* Wait for data */
+        max=0xffff;
+        while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
+        if (max>0x0) {
+            if ((inb(0x60) == 0xfa)) {
+                do {
+                    max=0xffff;
+                    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
+                    if (max>0x0) {
+                        kbd_code >>= 8;
+                        kbd_code |= (inb(0x60) << 8);
+                    }
+                } while (--count>0);
+            }
+        }
+        BX=kbd_code;
+        break;
+    
+    case 0x10: /* read MF-II keyboard input */
+        if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
+            BX_PANIC("KBD: int16h: out of keyboard input\n");
+        }
+        if (scan_code !=0 && ascii_code == 0xF0)
+            ascii_code = 0;
+        AX = (scan_code << 8) | ascii_code;
+        break;
+    
+    case 0x11: /* check MF-II keyboard status */
+        if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
+            SET_ZF();
+            return;
+        }
+        if (scan_code !=0 && ascii_code == 0xF0)
+            ascii_code = 0;
+        AX = (scan_code << 8) | ascii_code;
+        CLEAR_ZF();
+        break;
+    
+    case 0x12: /* get extended keyboard status */
+        shift_flags = read_byte(0x0040, 0x17);
+        SET_AL(shift_flags);
+        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;
+    
+    case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
+        SET_AH(0x80); // function int16 ah=0x10-0x12 supported
+        break;
+    
+    case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
+        // don't change AH : function int16 ah=0x20-0x22 NOT supported
+        break;
+    
+    //@todo: what's the point of handling this??
+#if 0
+    case 0x6F:
+        if (GET_AL() == 0x08)
+        SET_AH(0x02); // unsupported, aka normal keyboard
+#endif
+    
+    default:
+        BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
+        BX_INFO("AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
+    }
+    BX_DEBUG_INT16("int16ex: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/logo.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/logo.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/logo.c	(revision 38699)
@@ -0,0 +1,497 @@
+/* $Id$ */
+/** @file
+ * Stuff for drawing the BIOS logo.
+ */
+
+/*
+ * Copyright (C) 2004-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <stdint.h>
+#include "biosint.h"
+#include "inlines.h"
+#include "ebda.h"
+
+#define WAIT_HZ              64
+#define WAIT_MS              16
+
+#define F12_SCAN_CODE        0x86
+#define F12_WAIT_TIME        (3 * WAIT_HZ)   /* 3 seconds. Used only if logo disabled. */
+
+#include <VBox/bioslogo.h>
+
+/**
+ * Set video mode (VGA).
+ * @params    New video mode.
+ */
+void set_mode(uint8_t mode);
+#pragma aux set_mode =      \
+    "mov    ah, 0"          \
+    "int    10h"            \
+    parm [al] modify [ax] nomemory;
+
+
+/**
+ * Set VESA video mode.
+ * @params    New video mode.
+ */
+uint16_t vesa_set_mode(uint16_t mode);
+#pragma aux vesa_set_mode = \
+    "mov    ax, 4F02h"      \
+    "int    10h"            \
+    parm [bx] modify [ax] nomemory;
+
+
+/**
+ * Check for keystroke.
+ * @returns    True if keystroke available, False if not.
+ */
+//@todo: INT 16h should already be returning the right value in al; could also use setz
+uint8_t check_for_keystroke(void);
+#pragma aux check_for_keystroke =   \
+    "mov    ax, 100h"               \
+    "int    16h"                    \
+    "jz     no_key"                 \
+    "mov    al, 1"                  \
+    "jmp    done"                   \
+    "no_key:"                       \
+    "xor    al, al"                 \
+    "done:"                         \
+    modify [ax] nomemory;
+
+
+/**
+ * Get keystroke.
+ * @returns    BIOS scan code.
+ */
+uint8_t get_keystroke(void);
+#pragma aux get_keystroke = \
+    "xor    ax, ax"         \
+    "int    16h"            \
+    "xchg   ah, al"         \
+    modify [ax] nomemory;
+
+
+//@todo: This whole business with reprogramming the PIT is rather suspect.
+// The BIOS already has waiting facilities in INT 15h (fn 83h, 86h) which
+// should be utilized instead.
+
+// Set the timer to 16ms ticks (64K / (Hz / (PIT_HZ / 64K)) = count).
+void wait_init(void);
+#pragma aux wait_init = \
+    "mov    al, 34h"    \
+    "out    43h, al"    \
+    "mov    al, 0D3h"   \
+    "out    40h, al"    \
+    "mov    al, 048h"   \
+    "out    40h, al"    \
+    modify [ax] nomemory;
+
+//@todo: using this private interface is not great
+extern void rtc_post(void);
+#pragma aux rtc_post "*";
+
+/* Restore the timer to the default 18.2Hz. Reinitialize the tick
+ * and rollover counts since we've screwed them up by running the
+ * timer at WAIT_HZ for a while.
+ */
+void wait_uninit(void);
+#pragma aux wait_uninit =   \
+    ".386"                  \
+    "mov    al, 34h"        \
+    "out    43h, al"        \
+    "xor    ax, ax"         \
+    "out    40h, al"        \
+    "out    40h, al"        \
+    "pushad"                \
+    "push   ds"             \
+    "mov    ds, ax"         \
+    "call   rtc_post"       \
+    "pop    ds"             \
+    "popad"                 \
+    modify [ax] nomemory;
+
+
+/**
+ * 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.
+ */
+uint8_t wait(uint16_t ticks, uint8_t stop_on_key)
+{
+    long        ticks_to_wait, delta;
+    uint16_t    old_flags;
+    uint32_t    prev_ticks, t;
+    uint8_t     scan_code = 0;
+
+    /*
+     * We may or may not be called with interrupts disabled. For the duration
+     * of this function, interrupts must be enabled.
+     */
+    old_flags = int_query();
+    int_enable();
+
+    /*
+     * 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
+    {
+        halt();
+        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_INFO, "Key pressed: %x\n", scan_code);
+            if (stop_on_key)
+                return scan_code;
+        }
+    } while (ticks_to_wait > 0);
+    int_restore(old_flags);
+    return scan_code;
+}
+
+uint8_t read_logo_byte(uint8_t offset)
+{
+    outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
+    return inb(LOGO_IO_PORT);
+}
+
+uint16_t read_logo_word(uint8_t offset)
+{
+    outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
+    return inw(LOGO_IO_PORT);
+}
+
+// Hide cursor, clear screen and move cursor to starting position
+void clear_screen(void);
+#pragma aux clear_screen =  \
+    "mov    ax, 100h"       \
+    "mov    cx, 1000h"      \
+    "int    10h"            \
+    "mov    ax, 700h"       \
+    "mov    bh, 7"          \
+    "xor    cx, cx"         \
+    "mov    dx, 184Fh"      \
+    "int    10h"            \
+    "mov    ax, 200h"       \
+    "xor    bx, bx"         \
+    "xor    dx, dx"         \
+    "int    10h"            \
+    modify [ax bx cx dx] nomemory;
+
+void print_detected_harddisks(void)
+{
+    uint16_t    ebda_seg=read_word(0x0040,0x000E);
+    uint8_t     hd_count;
+    uint8_t     hd_curr = 0;
+    uint8_t     ide_ctrl_printed = 0;
+    uint8_t     sata_ctrl_printed = 0;
+    uint8_t     scsi_ctrl_printed = 0;
+    uint8_t     device;
+
+    hd_count = read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdcount);
+
+    for (hd_curr = 0; hd_curr < hd_count; hd_curr++)
+    {
+        device = read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdidmap[hd_curr]);
+
+#ifdef VBOX_WITH_SCSI
+        if (!VBOX_IS_SCSI_DEVICE(device))
+#endif
+        {
+
+            if ((device < 4) && (ide_ctrl_printed == 0))
+            {
+                printf("IDE controller:\n");
+                ide_ctrl_printed = 1;
+            }
+            else if ((device >= 4) && (sata_ctrl_printed == 0))
+            {
+                printf("\n\nAHCI controller:\n");
+                sata_ctrl_printed = 1;
+            }
+
+            printf("\n    %d) ", hd_curr+1);
+
+            /*
+             * If actual_device is bigger than or equal 4
+             * this is the next controller and
+             * the positions start at the beginning.
+             */
+            if (device >= 4)
+                device -= 4;
+
+            if (device / 2)
+                printf("Secondary ");
+            else
+                printf("Primary ");
+
+            if (device % 2)
+                printf("Slave");
+            else
+                printf("Master");
+        }
+#ifdef VBOX_WITH_SCSI
+        else
+        {
+            if (scsi_ctrl_printed == 0)
+            {
+                printf("\n\nSCSI controller:\n");
+                scsi_ctrl_printed = 1;
+            }
+
+            printf("\n    %d) Hard disk", hd_curr+1);
+
+        }
+#endif
+    }
+
+    if (   (ide_ctrl_printed == 0)
+        && (sata_ctrl_printed == 0)
+        && (scsi_ctrl_printed == 0))
+        printf("No hard disks found");
+
+    printf("\n");
+}
+
+uint8_t get_boot_drive(uint8_t scode)
+{
+    uint16_t    ebda_seg=read_word(0x0040,0x000E);
+
+    /* Check that the scan code is in the range of detected hard disks. */
+    uint8_t     hd_count = read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdcount);
+
+    /* The key '1' has scancode 0x02 which represents the first disk */
+    scode -= 2;
+
+    if (scode < hd_count)
+        return scode;
+
+    /* Scancode is higher than number of available devices */
+    return 0xff;
+}
+
+void show_logo(void)
+{
+    uint16_t    ebda_seg = read_word(0x0040,0x000E);
+    uint8_t     f12_pressed = 0;
+    uint8_t     scode;
+    uint16_t    tmp, i;
+
+    LOGOHDR     *logo_hdr = 0;
+    uint8_t     is_fade_in, is_fade_out, uBootMenu;
+    uint16_t    logo_time;
+
+
+    // Set PIT to 1ms ticks
+    wait_init();
+
+
+    // Get main signature
+    tmp = read_logo_word((uint8_t)&logo_hdr->u16Signature);
+    if (tmp != 0x66BB)
+        goto done;
+
+    // Get options
+    is_fade_in  = read_logo_byte((uint8_t)&logo_hdr->fu8FadeIn);
+    is_fade_out = read_logo_byte((uint8_t)&logo_hdr->fu8FadeOut);
+    logo_time   = read_logo_word((uint8_t)&logo_hdr->u16LogoMillies);
+    uBootMenu   = read_logo_byte((uint8_t)&logo_hdr->fu8ShowBootMenu);
+
+    // Is Logo disabled?
+    if (!is_fade_in && !is_fade_out && !logo_time)
+        goto done;
+
+    // Set video mode #0x142 640x480x32bpp
+    vesa_set_mode(0x142);
+
+    if (is_fade_in)
+    {
+        for (i = 0; i <= LOGO_SHOW_STEPS; i++)
+        {
+            outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
+            scode = wait(16 / WAIT_MS, 0);
+            if (scode == F12_SCAN_CODE)
+            {
+                f12_pressed = 1;
+                break;
+            }
+        }
+    }
+    else
+        outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | LOGO_SHOW_STEPS);
+
+    // Wait (interval in milliseconds)
+    if (!f12_pressed)
+    {
+        scode = wait(logo_time / WAIT_MS, 1);
+        if (scode == F12_SCAN_CODE)
+            f12_pressed = 1;
+    }
+
+    // Fade out (only if F12 was not pressed)
+    if (is_fade_out && !f12_pressed)
+    {
+        for (i = LOGO_SHOW_STEPS; i > 0 ; i--)
+        {
+            outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
+            scode = wait(16 / WAIT_MS, 0);
+            if (scode == F12_SCAN_CODE)
+            {
+                f12_pressed = 1;
+                break;
+            }
+        }
+    }
+
+done:
+    // Clear forced boot drive setting.
+    write_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice, 0);
+
+    // Don't restore previous video mode
+    // The default text mode should be set up. (defect #1235)
+    set_mode(0x0003);
+
+    // If Setup menu enabled
+    if (uBootMenu)
+    {
+        // If the graphics logo disabled
+        if (!is_fade_in && !is_fade_out && !logo_time)
+        {
+            if (uBootMenu == 2)
+                printf("Press F12 to select boot device.\n");
+
+            // if the user has pressed F12 don't wait here
+            if (!f12_pressed)
+            {
+                // Wait for timeout or keystroke
+                scode = wait(F12_WAIT_TIME, 1);
+                if (scode == F12_SCAN_CODE)
+                    f12_pressed = 1;
+            }
+        }
+
+        // If F12 pressed, show boot menu
+        if (f12_pressed)
+        {
+            uint8_t boot_device = 0;
+            uint8_t boot_drive = 0;
+
+            clear_screen();
+
+            // Show menu. Note that some versions of bcc freak out if we split these strings.
+            printf("\nVirtualBox temporary boot device selection\n\nDetected Hard disks:\n\n");
+            print_detected_harddisks();
+            printf("\nOther boot devices:\n f) Floppy\n c) CD-ROM\n l) LAN\n\n b) Continue booting\n");
+
+
+
+            // Wait for keystroke
+            for (;;)
+            {
+                do
+                {
+                    scode = wait(WAIT_HZ, 1);
+                } while (scode == 0);
+
+                if (scode == 0x30)
+                {
+                    // 'b' ... continue
+                    break;
+                }
+
+                // Check if hard disk was selected
+                if ((scode >= 0x02) && (scode <= 0x09))
+                {
+                    boot_drive = get_boot_drive(scode);
+
+                    /*
+                     * 0xff indicates that there is no mapping
+                     * from the scan code to a hard drive.
+                     * Wait for next keystroke.
+                     */
+                    if (boot_drive == 0xff)
+                        continue;
+
+                    write_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDrive, boot_drive);
+                    boot_device = 0x02;
+                    break;
+                }
+
+                switch (scode)
+                {
+                    case 0x21:
+                        // Floppy
+                        boot_device = 0x01;
+                        break;
+                    case 0x2e:
+                        // CD-ROM
+                        boot_device = 0x03;
+                        break;
+                    case 0x26:
+                        // LAN
+                        boot_device = 0x04;
+                        break;
+                }
+
+                if (boot_device != 0)
+                    break;
+            }
+
+            write_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice, boot_device);
+
+            // Switch to text mode. Clears screen and enables cursor again.
+            set_mode(0x0003);
+        }
+    }
+
+    // Restore PIT ticks
+    wait_uninit();
+
+    return;
+}
+
+
+void delay_boot(uint16_t secs)
+{
+    uint16_t    i;
+
+    if (!secs)
+        return;
+
+    // Set PIT to 1ms ticks
+    wait_init();
+
+    printf("Delaying boot for %d seconds:", secs);
+    for (i = secs; i > 0; i--)
+    {
+        printf(" %d", i);
+        wait(WAIT_HZ, 0);
+    }
+    printf("\n");
+    // Restore PIT ticks
+    wait_uninit();
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/makefile
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/makefile	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/makefile	(revision 38699)
@@ -0,0 +1,50 @@
+# Compiler flags:
+#  -q   no banner
+#  -wx  max warnings
+#  -0   generate 8086 code
+#  -ms  force small model (default)
+#  -s   remove runtime stack checks (required)
+#  -os  optimize for size
+#  -zu  assume that SS != DS (required)
+#  -ecc default to __cdecl calling convention (bad idea)
+#
+CFLAGS = -q -0 -wx -zu -s -oas -d1 -ms
+DEFS   = -DVBOX -DVBOX_LANBOOT_SEG=0xE200 -DVBOX_VERSION_STRING="0.9" &
+ -DVBOX_WITH_SCSI
+
+AFLAGS = -q -0 -wx
+
+INCLS  = -I"../../../../../include"
+
+.c.obj : .autodepend
+	wcc $(CFLAGS) $(DEFS) $<
+
+.asm.obj : .autodepend
+	wasm $(AFLAGS) $(DEFS) $<
+
+OBJS = 	bios.obj print.obj ata.obj floppy.obj eltorito.obj boot.obj &
+	keyboard.obj disk.obj serial.obj system.obj timepci.obj &
+	ps2mouse.obj parallel.obj logo.obj scsi.obj pcibio32.obj orgs.obj
+
+vbxbios.rom : vbxbios.bin
+	biossums $< $@
+
+vbxbios.bin : $(OBJS) $(__MAKEFILES__)
+	wlink name $@ system dos option quiet &
+	 option nofarcalls, map, verbose, statics &
+	 output raw offset=0xF0000 order &
+	 clname DATA segaddr=0xF000 segment _DATA &
+	 clname CODE &
+	 segment _TEXT segaddr=0xF000 offset=0x1400 &
+	 segment BIOS32 segaddr=0xF000 offset=0xDE00 &
+	 segment BIOSSEG segaddr=0xF000 offset=0xE000 &
+	 file { $(OBJS) } &
+	 library clibs.lib &
+	 disable 1014, 1023, 2120
+
+logo.obj : logo.c
+	wcc $(INCLS) $(CFLAGS) $(DEFS) -DVBOX_PC_BIOS $<
+
+clean : .symbolic
+	@rm -f *.obj *.err
+	@rm -f vbxbios.bin vbxbios.rom vbxbios.map
Index: /trunk/src/VBox/Devices/PC/BIOS-new/notes.txt
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/notes.txt	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/notes.txt	(revision 38699)
@@ -0,0 +1,67 @@
+
+ Notes on BIOS usage
+ -------------------
+
+- DOS (including 6.22/7.1) does not need INT 15h or INT 1Ah. Most other
+  operating systems require INT 15h to detect installed memory.
+
+- OS/2 (WSeB/MCP/ACP) appears to be one of the very few operating systems
+  which use the El Torito floppy emulation.
+
+- MS-DOS 6.2/V is a rare user of the INT 15h keyboard intercept routines.
+
+- Some software uses the model byte at F000:FFFE to determine the system
+  type (PC-DOS 3.0, Norton Utilities 8). Other software first tries INT 15h,
+  fn C0h instead (PC-DOS 3.1, MSD).
+
+- DOS 4.01 (both IBM and Microsoft) calls INT 13h to read from disk with less
+  than 100 bytes of stack space early in the boot sequence.
+
+- Very few guests use the 32-bit BIOS interface. One is OS/2 (but falls back),
+  another is Etherboot.
+
+- OS/2 is the only known guest which can run the 16-bit PCI BIOS in protected
+  mode (but only if the 32-bit PCI BIOS is unavailable).
+
+
+ Notes on BIOS implementation
+ ----------------------------
+
+- To return values from functions not declared as __interrupt, the arguments
+  may need to be declared volatile (not ideal, but does the job).
+
+- The way the POST code selectively clears or doesn't clear memory
+  is extremely suspect and will need reworking.
+
+- Need to review string routines wrt direction flag (should be OK now).
+
+- Need to review CMOS access wrt interrupts (possible index reg change by
+  an interrupt handler).
+
+- The POST code zeroes the entire BDA, and then various bits zero specific
+  parts of the BDA again. That's a waste of time.
+
+- After a reset, all interrupts are unmasked. Not sure if that's OK.
+
+- BCC mishandles the following (where buf is an uint8_t array):
+  lba=buf[0x2B]*0x1000000+buf[0x2A]*0x10000+buf[0x29]*0x100+buf[0x28];
+  The buf[x]*100 expression should end up being of type signed int, which
+  causes the sign to be incorrectly propagated. BCC incorrectly keeps
+  the type unsigned.
+
+
+
+ Code size notes (code as of 7/6/2011):
+
+ The following values are the size of the _TEXT segment, i.e. only C code;
+data defined in C is not included, neither are assembly modules.
+
+ Options:                Size (hex):
+ --------                -----------
+ -0 -zu -s -oas -ecc     631A
+ -3 -zu -s -oas -ecc     5C1E
+ -0 -zu -s -oas          578A
+ -3 -zu -s -oas          5452
+ 
+ Both generating 386 code and using register-based calling convention for
+internal functions brings significant size savings (15% when combined).
Index: /trunk/src/VBox/Devices/PC/BIOS-new/orgs.asm
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/orgs.asm	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/orgs.asm	(revision 38699)
@@ -0,0 +1,1788 @@
+;;
+;; Copyright (C) 2006-2011 Oracle Corporation
+;;
+;; This file is part of VirtualBox Open Source Edition (OSE), as
+;; available from http://www.virtualbox.org. This file is free software;
+;; you can redistribute it and/or modify it under the terms of the GNU
+;; General Public License (GPL) as published by the Free Software
+;; Foundation, in version 2 as it comes in the "COPYING" file of the
+;; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+;; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;; --------------------------------------------------------------------
+;;
+;; This code is based on:
+;;
+;;  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+;;
+;;  Copyright (C) 2002  MandrakeSoft S.A.
+;;
+;;    MandrakeSoft S.A.
+;;    43, rue d'Aboukir
+;;    75002 Paris - France
+;;    http://www.linux-mandrake.com/
+;;    http://www.mandrakesoft.com/
+;;
+;;  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
+;;
+;;
+
+
+EBDA_SEG	equ	09FC0h		; starts at 639K
+EBDA_SIZE	equ	1		; 1K
+BASE_MEM_IN_K	equ	(640 - EBDA_SIZE)
+
+CMOS_ADDR	equ	070h
+CMOS_DATA	equ	071h
+
+
+PIC_CMD_EOI	equ	020h
+PIC_MASTER	equ	020h
+PIC_SLAVE	equ	0A0h
+
+BIOS_FIX_BASE	equ	0E000h
+
+SYS_MODEL_ID	equ	0FCh		; PC/AT
+SYS_SUBMODEL_ID	equ	0
+BIOS_REVISION	equ	1
+
+BIOS_BUILD_DATE	equ	'06/23/99'
+BIOS_COPYRIGHT	equ	'Oracle VM VirtualBox BIOS'
+
+;BX_PCIBIOS		equ	1		; defined in pcicfg.inc
+BX_ROMBIOS32		equ	0
+BX_CALL_INT15_4F	equ	1
+
+;; Set a fixed BIOS location, with a marker for verification
+BIOSORG		macro	addr
+		org	addr - BIOS_FIX_BASE - 2
+		db	'XM'
+		endm
+
+;; Set an interrupt vector (not very efficient if multiple vectors are
+;; programmed in one go)
+SET_INT_VECTOR	macro	vec, segm, offs
+		mov	ax, offs
+		mov	ds:[vec*4], ax
+		mov	ax, segm
+		mov	ds:[vec*4+2], ax
+endm
+
+; Set up an environment C code expects. DS must point to the BIOS segment
+; and the direction flag must be cleared(!)
+C_SETUP		macro
+		push	cs
+		pop	ds
+		cld
+endm
+
+;; External function in separate modules
+extrn		_dummy_isr_function:near
+extrn		_log_bios_start:near
+extrn		_nmi_handler_msg:near
+extrn		_int18_panic_msg:near
+extrn		_int09_function:near
+extrn		_int13_diskette_function:near
+extrn		_int13_eltorito:near
+extrn		_int13_cdemu:near
+extrn		_int13_cdrom:near
+extrn		_cdemu_isactive:near
+extrn		_cdemu_emulated_drive:near
+extrn		_int13_harddisk:near
+extrn		_int13_harddisk_ext:near
+extrn		_int14_function:near
+extrn		_int15_function:near
+extrn		_int15_function_mouse:near
+extrn		_int15_function32:near
+extrn		_int16_function:near
+extrn		_int17_function:near
+extrn		_int19_function:near
+extrn		_int1a_function:near
+extrn		_int1a_function_pci:near
+extrn		_int70_function:near
+extrn		_int74_function:near
+extrn		_ata_init:near
+extrn		_scsi_init:near
+extrn		_ata_detect:near
+extrn		_cdemu_init:near
+extrn		_keyboard_init:near
+extrn		_print_bios_banner:near
+
+
+;; Symbols referenced from C code
+public		_diskette_param_table
+public		_pmode_IDT
+public		_rmode_IDT
+public		post
+public		eoi_both_pics
+public		rtc_post
+
+;; Additional publics for easier disassembly and debugging
+DEBUG	equ	1
+ifdef		DEBUG
+
+public		int08_handler
+public		int0e_handler
+public		int11_handler
+public		int12_handler
+public		int13_handler
+public		int13_relocated
+public		int15_handler
+public		int17_handler
+public		int19_handler
+public		int19_relocated
+public		dummy_iret
+public		nmi
+public		rom_fdpt
+public		cpu_reset
+public		normal_post
+public		eoi_jmp_post
+public		eoi_master_pic
+public		ebda_post
+public		hard_drive_post
+public		int13_legacy
+public		int70_handler
+public		int75_handler
+public		int15_handler32
+public		int15_handler_mouse
+public		iret_modify_cf
+public		rom_scan
+public		rom_checksum
+public		init_pic
+public		floppy_post
+public		int13_out
+public		int13_disk
+public		int13_notfloppy
+public		int13_legacy
+public		int13_noeltorito
+public		int1c_handler
+public		int10_handler
+public		int74_handler
+public		int76_handler
+public		detect_parport
+public		detect_serial
+public		font8x8
+
+endif
+
+;; NOTE: The last 8K of the ROM BIOS are peppered with fixed locations which
+;; must be retained for compatibility. As a consequence, some of the space is
+;; going to be wasted, but the gaps should be filled with miscellaneous code
+;; and data when possible.
+
+.286p
+
+BIOSSEG		segment	'CODE'
+		assume	cs:BIOSSEG
+
+;;
+;; Start of fixed code - eoi_jmp_post is kept here to allow short jumps.
+;;
+		BIOSORG	0E030h
+eoi_jmp_post:
+		call	eoi_both_pics
+		xor	ax, ax
+		mov	ds, ax
+		jmp	dword ptr ds:[0467h]
+
+eoi_both_pics:
+		mov	al, PIC_CMD_EOI
+		out	PIC_SLAVE, al
+eoi_master_pic:
+		mov	al, PIC_CMD_EOI
+		out	PIC_MASTER, al
+		ret
+
+;; --------------------------------------------------------
+;; POST entry point
+;; --------------------------------------------------------
+		BIOSORG	0E05Bh
+post:
+		xor	ax, ax
+
+		;; reset the DMA controllers
+		out	00Dh, al
+		out	0DAh, al
+
+		;; then initialize the DMA controllers
+		mov	al, 0C0h
+		out	0D6h, al	; enable channel 4 cascade
+		mov	al, 0
+		out	0D4h, al	; unmask channel 4
+
+		;; read the CMOS shutdown status
+		mov	al, 0Fh
+		out	CMOS_ADDR, al
+		in	al, CMOS_DATA
+
+		;; save status
+		mov	bl, al
+
+		;; reset the shutdown status in CMOS
+		mov	al, 0Fh
+		out	CMOS_ADDR, al
+		mov	al, 0
+		out	CMOS_DATA, al
+
+		;; examine the shutdown status code
+		mov	al, bl
+		cmp	al, 0
+		jz	normal_post
+		cmp	al, 0
+		jae	normal_post
+		cmp	al, 9
+		je	normal_post	;; TODO: really?!
+
+		;; 05h = EOI + jump through 40:67
+		cmp	al, 5
+		je	eoi_jmp_post
+
+		;; any other shutdown status values are ignored
+		;; OpenSolaris sets the status to 0Ah in some cases?
+;		jmp	normal_post
+
+normal_post:
+		;; shutdown code 0: normal startup
+		cli
+		;; Set up the stack top at 0:7800h. The stack should not be
+		;; located above 0:7C00h; that conflicts with PXE, which
+		;; considers anything above that address to be fair game.
+		;; The traditional locations are 30:100 (PC) or 0:400 (PC/AT).
+		mov	ax, 7800h
+		mov	sp, ax
+		xor	ax, ax
+		mov	ds, ax
+		mov	ss, ax
+
+		;; clear the bottom of memory except for the word at 40:72
+		;; TODO:  Why not clear all of it? What's the point?
+		mov	es, ax
+		xor	di, di
+		cld
+		mov	cx, 0472h / 2
+	rep	stosw
+		inc	di
+		inc	di
+		mov	cx, (1000h - 0472h - 2) / 2
+	rep	stosw
+
+		;; clear the remaining base memory except for the top
+		;; of the EBDA (the MP table is planted there)
+		xor	bx, bx
+memory_zero_loop:
+		add	bx, 1000h
+		cmp	bx, 9000h
+		jae	memory_cleared
+		mov	es, bx
+		xor	di, di
+		mov	cx, 8000h	; 32K words
+	rep	stosw
+		jmp	memory_zero_loop
+memory_cleared:
+		mov	es, bx
+		xor	di, di
+		mov	cx, 7E00h	; all but the last 1K
+	rep	stosw
+		xor	bx, bx
+
+
+		C_SETUP
+		call	_log_bios_start
+
+		call	pmode_setup
+
+		;; set all interrupts to default handler
+		xor	bx, bx
+		mov	ds, bx
+		mov	cx, 100h	; 256 interrupts
+		mov	ax, dummy_iret
+		mov	dx, BIOSSEG
+
+post_default_ints:
+		mov	[bx], ax
+		mov	[bx+2], dx
+		add	bx, 4
+		loop	post_default_ints
+
+		;; set vector 79h to zero
+		;; this is used by 'guardian angel' protection system
+		;; TODO: Really? Why?
+
+		;; base memory in K to 40:13
+		mov	ax, BASE_MEM_IN_K
+		mov	ds:[413h], ax
+
+		;; manufacturing test at 40:12
+		;; zeroed out above
+
+		;; set up various service vectors
+		;; TODO: This should use the table at FEF3h instead
+		SET_INT_VECTOR 11h, BIOSSEG, int11_handler
+		SET_INT_VECTOR 12h, BIOSSEG, int12_handler
+		SET_INT_VECTOR 15h, BIOSSEG, int15_handler
+		SET_INT_VECTOR 17h, BIOSSEG, int17_handler
+		SET_INT_VECTOR 18h, BIOSSEG, int18_handler
+		SET_INT_VECTOR 19h, BIOSSEG, int19_handler
+		SET_INT_VECTOR 1Ch, BIOSSEG, int1c_handler
+
+		call	ebda_post
+
+		;; PIT setup
+		SET_INT_VECTOR 08h, BIOSSEG, int08_handler
+		mov	al, 34h		; timer 0, binary, 16-bit, mode 2
+		out	43h, al
+		mov	al, 0		; max count -> ~18.2 Hz
+		out	40h, al
+		out	40h, al
+
+		;; keyboard setup
+		SET_INT_VECTOR 09h, BIOSSEG, int09_handler
+		SET_INT_VECTOR 16h, BIOSSEG, int16_handler
+
+		xor	ax, ax
+		mov	ds, ax
+		;; TODO: What's the point? The BDA is zeroed already?!
+		mov	ds:[417h], al	; keyboard shift flags, set 1
+		mov	ds:[418h], al	; keyboard shift flags, set 2
+		mov	ds:[419h], al	; keyboard Alt-numpad work area
+		mov	ds:[471h], al	; keyboard Ctrl-Break flag
+		mov	ds:[497h], al	; keyboard status flags 4
+		mov	al, 10h
+		mov	ds:[496h], al	; keyboard status flags 3
+
+		mov	bx, 1Eh
+		mov	ds:[41Ah], bx	; keyboard buffer head
+		mov	ds:[41Ch], bx	; keyboard buffer tail
+		mov	ds:[480h], bx	; keyboard buffer start
+		mov	bx, 3Eh
+		mov	ds:[482h], bx	; keyboard buffer end
+
+		push	ds
+		C_SETUP
+		call	_keyboard_init
+		pop	ds
+
+
+		;; store CMOS equipment byte in BDA
+		mov	al, 14h
+		out	CMOS_ADDR, al
+		in	al, CMOS_DATA
+		mov	ds:[410h], al
+
+		;; parallel setup
+		SET_INT_VECTOR 0Fh, BIOSSEG, dummy_iret
+		xor	ax, ax
+		mov	ds, ax
+		xor	bx, bx
+		mov	cl, 14h		; timeout value
+		mov	dx, 378h	; parallel port 1
+		call	detect_parport
+		mov	dx, 278h	; parallel port 2
+		call	detect_parport
+		shl	bx, 0Eh
+		mov	ax, ds:[410h]	; equipment word
+		and	ax, 3FFFh
+		or	ax, bx		; set number of parallel ports
+		mov	ds:[410h], ax	; store in BDA
+
+		;; Serial setup
+		SET_INT_VECTOR 0Bh, BIOSSEG, dummy_isr
+		SET_INT_VECTOR 0Ch, BIOSSEG, dummy_isr
+		SET_INT_VECTOR 14h, BIOSSEG, int14_handler
+		xor	bx, bx
+		mov	cl, 0Ah		; timeout value
+		mov	dx, 3F8h	; first serial address
+		call	detect_serial
+		mov	dx, 2F8h	; second serial address
+		call	detect_serial
+		mov	dx, 3E8h	; third serial address
+		call	detect_serial
+		mov	dx, 2E8h	; fourth serial address
+		call	detect_serial
+		shl	bx, 9
+		mov	ax, ds:[410h]	; equipment word
+		and	ax, 0F1FFh	; bits 9-11 determine serial ports
+		or	ax, bx
+		mov	ds:[410h], ax
+
+		;; CMOS RTC
+		SET_INT_VECTOR 1Ah, BIOSSEG, int1a_handler
+		SET_INT_VECTOR 4Ah, BIOSSEG, dummy_iret	; TODO: redundant?
+		SET_INT_VECTOR 70h, BIOSSEG, int70_handler
+		;; BIOS DATA AREA 4CEh ???
+		call	rtc_post
+
+		;; PS/2 mouse setup
+		SET_INT_VECTOR 74h, BIOSSEG, int74_handler
+
+		;; IRQ 13h (FPU exception) setup
+		SET_INT_VECTOR 75h, BIOSSEG, int75_handler
+
+		;; Video setup
+		SET_INT_VECTOR 10h, BIOSSEG, int10_handler
+
+		call	init_pic
+
+		call	pcibios_init_iomem_bases
+		call	pcibios_init_irqs
+
+		call	rom_scan
+
+		C_SETUP
+		;; ATA/ATAPI driver setup
+		call	_ata_init
+		call	_ata_detect
+
+ifdef VBOX_WITH_SCSI
+		; SCSI driver setup
+		call	_scsi_init
+endif
+
+		call	_print_bios_banner
+
+		;; floppy setup
+		call	floppy_post
+
+		;; hard drive setup
+		call	hard_drive_post
+
+		;; El Torito floppy/hard disk emulation
+		C_SETUP			; in case assembly code changed things
+		call	_cdemu_init
+
+		; TODO: what's the point of enabling interrupts here??
+		sti			; enable interrupts
+		int	19h
+		;; does not return here
+		sti
+wait_forever:
+		hlt
+		jmp	wait_forever
+		cli
+		hlt
+
+
+;; --------------------------------------------------------
+;; NMI handler
+;; --------------------------------------------------------
+		BIOSORG	0E2C3h
+nmi:
+		C_SETUP
+		call	_nmi_handler_msg
+		iret
+
+int75_handler:
+		out	0F0h, al	; clear IRQ13
+		call	eoi_both_pics
+		int	2		; emulate legacy NMI
+		iret
+
+
+hard_drive_post	proc	near
+
+		;; TODO Why? And what about secondary controllers?
+		mov	al, 0Ah		; disable IRQ 14
+		mov	dx, 03F6h
+		out	dx, al
+
+		xor	ax, ax
+		mov	ds, ax
+		;; TODO: Didn't we just clear the entire EBDA?
+		mov	ds:[474h], al	; last HD operation status
+		mov	ds:[477h], al	; HD port offset (XT only???)
+		mov	ds:[48Ch], al	; HD status register
+		mov	ds:[48Dh], al	; HD error register
+		mov	ds:[48Eh], al	; HD task complete flag
+		mov	al, 0C0h
+		mov	ds:[476h], al	; HD control byte
+		;; set up hard disk interrupt vectors
+		SET_INT_VECTOR 13h, BIOSSEG, int13_handler
+		SET_INT_VECTOR 76h, BIOSSEG, int76_handler
+		;; INT 41h/46h: hard disk 0/1 dpt
+		; TODO: This should be done from the code which
+		; builds the DPTs?
+		SET_INT_VECTOR 41h, EBDA_SEG, 3Dh
+		SET_INT_VECTOR 46h, EBDA_SEG, 4Dh
+		ret
+
+hard_drive_post	endp
+
+
+;; --------------------------------------------------------
+;; INT 13h handler - Disk services
+;; --------------------------------------------------------
+		BIOSORG	0E3FEh
+
+int13_handler:
+		jmp	int13_relocated
+
+
+;; --------------------------------------------------------
+;; Fixed Disk Parameter Table
+;; --------------------------------------------------------
+;;		BIOSORG	0E401h - fixed wrt preceding
+
+rom_fdpt:
+
+;; --------------------------------------------------------
+;; INT 19h handler - Boot load service
+;; --------------------------------------------------------
+		BIOSORG	0E6F2h
+
+int19_handler:
+		jmp	int19_relocated
+
+
+
+;; --------------------------------------------------------
+;; System BIOS Configuration Table
+;; --------------------------------------------------------
+;;		BIOSORG	0E6F5h - fixed wrt preceding
+; must match BIOS_CONFIG_TABLE
+bios_cfg_table:
+		dw	9	; table size in bytes
+		db	SYS_MODEL_ID
+		db	SYS_SUBMODEL_ID
+		db	BIOS_REVISION
+		; Feature byte 1
+		; b7: 1=DMA channel 3 used by hard disk
+		; b6: 1=2 interrupt controllers present
+		; b5: 1=RTC present
+		; b4: 1=BIOS calls int 15h/4Fh for every key
+		; b3: 1=wait for extern event supported (Int 15h/41h)
+		; b2: 1=extended BIOS data area used
+		; b1: 0=AT or ESDI bus, 1=MicroChannel
+		; b0: 1=Dual bus (MicroChannel + ISA)
+ifdef BX_CALL_INT15_4F
+		db	74h; or USE_EBDA
+else
+		db	64h; or USE_EBDA
+endif
+		; Feature byte 2
+		; b7: 1=32-bit DMA supported
+		; b6: 1=int16h, function 9 supported
+		; b5: 1=int15h/C6h (get POS data) supported
+		; b4: 1=int15h/C7h (get mem map info) supported
+		; b3: 1=int15h/C8h (en/dis CPU) supported
+		; b2: 1=non-8042 kb controller
+		; b1: 1=data streaming supported
+		; b0: reserved
+		db	40h
+		; Feature byte 3
+		; b7: not used
+		; b6: reserved
+		; b5: reserved
+		; b4: POST supports ROM-to-RAM enable/disable
+		; b3: SCSI on system board
+		; b2: info panel installed
+		; b1: Initial Machine Load (IML) system - BIOS on disk
+		; b0: SCSI supported in IML
+		db	0
+		; Feature byte 4
+		; b7: IBM private
+		; b6: EEPROM present
+		; b5-3: ABIOS presence (011 = not supported)
+		; b2: private
+		; b1: memory split above 16Mb supported
+		; b0: POSTEXT directly supported by POST
+		db	0
+		; Feature byte 5 (IBM)
+		; b1: enhanced mouse
+		; b0: flash EPROM
+		db	0
+
+
+;; --------------------------------------------------------
+;; Baud Rate Generator Table
+;; --------------------------------------------------------
+		BIOSORG	0E729h
+
+
+;; --------------------------------------------------------
+;; INT 14h handler -  Serial Communication Service
+;; --------------------------------------------------------
+		BIOSORG	0E739h
+int14_handler:
+		push	ds
+		push	es
+		pusha
+		C_SETUP
+		call	_int14_function
+		popa
+		pop	es
+		pop	ds
+		iret
+
+
+
+;;
+;; Handler for unexpected hardware interrupts
+;;
+dummy_isr:
+		push	ds
+		push	es
+		pusha
+		C_SETUP
+		call	_dummy_isr_function
+		popa
+		pop	es
+		pop	ds
+		iret
+
+
+rom_checksum 	proc	near
+		push	ax
+ifdef CHECKSUM_ROMS
+		push	bx
+		push	cx
+		xor	ax, ax
+		xor	bx, bx
+		xor	cx, cx
+		mov	ch, ds:[2]
+		shl	cx, 1
+checksum_loop:
+		add	al, [bx]
+		inc	bx
+		loop	checksum_loop
+		and	al, 0FFh	; set flags
+		pop	cx
+		pop	bx
+else
+		xor	al, al
+endif
+		pop	ax
+		ret 
+rom_checksum	endp
+
+
+;;
+;; ROM scan - scan for valid ROMs and initialize them
+;;
+rom_scan:
+		mov	cx, 0C000h	; start at C000
+rom_scan_loop:
+		mov	ds, cx
+		mov	ax, 4		; scan in 2K increments
+		cmp	word ptr ds:[0], 0AA55h	; look for signature
+		jne	rom_scan_increment
+
+		call	rom_checksum
+		jnz	rom_scan_increment
+
+		mov	al, ds:[2]	; set increment to ROM length
+		test	al, 3
+		jz	block_count_rounded
+
+		and	al, 0FCh	; round up
+		add	al, 4		; to nearest 2K
+block_count_rounded:
+		xor	bx, bx
+		mov	ds, bx
+		push	ax
+		push	cx		; push segment...
+		push	3		; ...and offset of ROM entry
+		mov	bp, sp
+		call	dword ptr [bp]	; call ROM init routine
+		cli			; in case ROM enabled interrupts
+		add	sp, 2		; get rid of offset
+		pop	cx		; restore registers
+		pop	ax
+rom_scan_increment:
+		shl	ax, 5		; convert to 16-byte increments
+		add	cx, ax
+		cmp	cx, 0E800h	; must encompass VBOX_LANBOOT_SEG!
+		jbe	rom_scan_loop
+
+		xor	ax, ax		; DS back to zero
+		mov	ds, ax
+		ret
+
+init_pic	proc	near
+
+		mov	al, 11h		; send init commands
+		out	PIC_MASTER, al
+		out	PIC_SLAVE, al
+		mov	al, 08h		; base 08h
+		out	PIC_MASTER+1, al
+		mov	al, 70h		; base 70h
+		out	PIC_SLAVE+1, al
+		mov	al, 04h		; master PIC
+		out	PIC_MASTER+1, al
+		mov	al, 02h		; slave PIC
+		out	PIC_SLAVE+1, al
+		mov	al, 01h
+		out	PIC_MASTER+1, al
+		out	PIC_SLAVE+1, al
+		mov	al, 0B8h	; unmask IRQs 0/1/2/6
+		out	PIC_MASTER+1, al
+		mov	al, 08Fh
+		out	PIC_SLAVE+1, al	; unmask IRQs 12/13/14
+		ret
+
+init_pic	endp
+
+ebda_post	proc	near
+
+		SET_INT_VECTOR 0Dh, BIOSSEG, dummy_isr	; IRQ 5
+		SET_INT_VECTOR 0Fh, BIOSSEG, dummy_isr	; IRQ 7
+		SET_INT_VECTOR 72h, BIOSSEG, dummy_isr	; IRQ 11
+		SET_INT_VECTOR 77h, BIOSSEG, dummy_isr	; IRQ 15
+
+		mov	ax, EBDA_SEG
+		mov	ds, ax
+		mov	byte ptr ds:[0], EBDA_SIZE
+		;; store EBDA seg in 40:0E
+		xor	ax, ax
+		mov	ds, ax
+		mov	word ptr ds:[40Eh], EBDA_SEG
+		ret
+
+ebda_post	endp
+
+
+
+;; --------------------------------------------------------
+;; INT 16h handler - Keyboard service
+;; --------------------------------------------------------
+		BIOSORG	0E82Eh
+int16_handler:
+		sti
+		push	es
+		push	ds
+		;; TODO: the caller already pushed flags (INT instruction)??
+		pushf
+		pusha
+
+		cmp	ah, 0
+		je	int16_F00
+
+		cmp	ah, 10h
+		je	int16_F00
+
+		C_SETUP
+		call	_int16_function
+		popa
+		popf
+		pop	ds
+		pop	es
+		jz	int16_zero_set
+
+		;; TODO: Could use SP directly here (386+)
+int16_zero_clear:
+		push	bp
+		mov	bp, sp
+		and	byte ptr [bp+6], 0BFh
+		pop	bp
+		iret
+
+int16_zero_set:
+		push	bp
+		mov	bp, sp
+		or	byte ptr [bp+6], 040h
+		pop	bp
+		iret
+
+int16_F00:
+		mov	bx, 40h		; TODO: why 40h here and 0 elsewhere?
+		mov	ds, bx
+int16_wait_for_key:
+		cli
+		mov	bx, ds:[1Ah]
+		cmp	bx, ds:[1Ch]
+		jne	int16_key_found
+		sti
+		nop
+; TODO: review/enable?
+if 0
+		push	ax
+		mov	ax, 9002h
+		int	15h
+		pop	ax
+endif
+		jmp	int16_wait_for_key
+
+int16_key_found:
+		C_SETUP
+		call	_int16_function
+		popa
+		popf
+		pop	ds
+		pop	es
+; TODO: review/enable?
+if 0
+		push	ax
+		mov	ax, 9202h
+		int	15h
+		pop	ax
+endif
+		iret
+
+
+;; Quick and dirty protected mode entry/exit routines
+include pmode.inc
+
+;; Initialization code which needs to run in protected mode (LAPIC etc.)
+include pmsetup.inc
+
+
+KBDC_DISABLE	EQU	0ADh
+KBDC_ENABLE	EQU	0AEh
+KBC_CMD		EQU	64h
+KBC_DATA	EQU	60h
+
+;; --------------------------------------------------------
+;; INT 09h handler - Keyboard ISR (IRQ 1)
+;; --------------------------------------------------------
+		BIOSORG	0E987h
+int09_handler:
+		cli			; TODO: why? they're off already!
+		push	ax
+		mov	al, KBDC_DISABLE
+		out	KBC_CMD, al
+
+		mov	al, 0Bh
+		out	PIC_MASTER, al
+		in	al, PIC_MASTER
+		and	al, 2
+		jz	int09_finish
+
+		in	al, KBC_DATA
+		push	ds
+		pusha
+		cld			; Before INT 15h (and any C code)
+ifdef BX_CALL_INT15_4F
+		mov	ah, 4Fh
+		stc
+		int	15h		; keyboard intercept
+		jnc	int09_done
+endif
+		sti			; Only after calling INT 15h
+
+		;; check for extended key
+		cmp	al, 0E0h
+		jne	int09_check_pause
+		xor	ax, ax
+		mov	ds, ax
+		mov	al, ds:[496h]	; mf2_state |= 0x02
+		or	al, 2		; TODO: why not RMW?
+		mov	ds:[496], al
+		jmp	int09_done
+
+int09_check_pause:
+		cmp	al, 0E1h	; pause key?
+		jne	int09_process_key
+		xor	ax, ax
+		mov	ds, ax		; TODO: haven't we just done that??
+		mov	al, ds:[496h]
+		or	al, 1
+		mov	ds:[496h], al	; TODO: why not RMW?
+		jmp	int09_done
+
+int09_process_key:
+		push	es
+		C_SETUP
+		call	_int09_function
+		pop	es
+
+int09_done:
+		popa
+		pop	ds
+		cli
+		call	eoi_master_pic
+
+int09_finish:
+		mov	al, KBDC_ENABLE
+		out	KBC_CMD, al
+		pop	ax
+		iret
+
+
+;; --------------------------------------------------------
+;; INT 13h handler - Diskette service
+;; --------------------------------------------------------
+		BIOSORG	0EC59h
+int13_diskette:
+		jmp	int13_noeltorito
+
+
+
+;; --------------------------------------------------------
+;; INT 13h handler - Disk service
+;; --------------------------------------------------------
+int13_relocated:
+		;; check for an El-Torito function
+		cmp	ah, 4Ah
+		jb	int13_not_eltorito
+
+		cmp	ah, 4Dh
+		ja	int13_not_eltorito
+
+		pusha
+		push	es
+		push	ds
+		C_SETUP			; TODO: setup C envrionment only once?
+		push	int13_out	; simulate a call
+		jmp	_int13_eltorito	; ELDX not used
+
+int13_not_eltorito:
+		push	es
+		push	ax		; TODO: better register save/restore
+		push	bx
+		push	cx
+		push	dx
+
+		;; check if emulation is active
+		call	_cdemu_isactive
+		cmp	al, 0
+		je	int13_cdemu_inactive
+
+		;; check if access to the emulated drive
+		call	_cdemu_emulated_drive
+		pop	dx		; recover dx (destroyed by C code)
+		push	dx
+		cmp	al, dl		; INT 13h on emulated drive
+		jne	int13_nocdemu
+
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	ax
+		pop	es
+
+		pusha
+		push	es
+		push	ds
+		C_SETUP			; TODO: setup environment only once?
+
+		push	int13_out	; simulate a call
+		jmp	_int13_cdemu	; ELDX not used
+
+int13_nocdemu:
+		and	dl, 0E0h	; mask to get device class
+		cmp	al, dl
+		jne	int13_cdemu_inactive
+
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	ax
+		pop	es
+
+		push	ax
+		push	cx
+		push	dx
+		push	bx
+
+		dec	dl		; real drive is dl - 1
+		jmp	int13_legacy
+
+int13_cdemu_inactive:
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	ax
+		pop	es
+
+int13_noeltorito:
+		push	ax
+		push	cx
+		push	dx
+		push	bx
+int13_legacy:
+		push	dx		; push eltorito dx in place of sp
+		push	bp
+		push	si
+		push	di
+		push	es
+		push	ds
+		C_SETUP			; TODO: setup environment only once?
+
+		;; now the registers can be restored with
+		;; pop ds; pop es; popa; iret
+		test	dl, 80h		; non-removable?
+		jnz	int13_notfloppy
+
+		push	int13_out	; simulate a near call
+		jmp	_int13_diskette_function
+
+int13_notfloppy:
+		cmp	dl, 0E0h
+		jb	int13_notcdrom
+
+		;; ebx may be modified, save here
+		;; TODO: check/review 32-bit register use
+		.386
+		shr	ebx, 16
+		push	bx
+		call	_int13_cdrom
+		pop	bx
+		shl	ebx, 16
+		.286
+
+		jmp	int13_out
+
+int13_notcdrom:
+int13_disk:
+		cmp	ah,40h
+		ja	int13x
+		call	_int13_harddisk
+		jmp	int13_out
+
+int13x:
+		call	_int13_harddisk_ext
+
+int13_out:
+		pop	ds
+		pop	es
+		popa
+		iret
+
+
+
+; parallel port detection: port in dx, index in bx, timeout in cl
+detect_parport	proc	near
+
+		push	dx
+		inc	dx
+		inc	dx
+		in	al, dx
+		and	al, 0DFh	; clear input mode
+		out	dx, al
+		pop	dx
+		mov	al, 0AAh
+		out	dx, al
+		in	al, dx
+		cmp	al, 0AAh
+		jne	no_parport
+
+		push	bx
+		shl	bx, 1
+		mov	[bx+408h], dx	; parallel I/O address
+		pop	bx
+		mov	[bx+478h], cl	; parallel printer timeout
+		inc	bx
+no_parport:
+		ret
+
+detect_parport	endp
+		
+; setial port detection: port in dx, index in bx, timeout in cl
+detect_serial	proc	near
+
+		push	dx
+		inc	dx
+		mov	al, 2
+		out	dx, al
+		in	al, dx
+		cmp	al, 2
+		jne	no_serial
+
+		inc	dx
+		in	al, dx
+		cmp	al, 2
+		jne	no_serial
+
+		dec	dx
+		xor	al, al
+		pop	dx
+		push	bx
+		shl	bx, 1
+		mov	[bx+400h], dx	; serial I/O address
+		pop	bx
+		mov	[bx+47Ch], cl	; serial timeout
+		inc	bx
+		ret
+
+no_serial:
+		pop	dx
+		ret
+
+detect_serial	endp
+
+
+;;
+;; POST: Floppy drive
+;;
+floppy_post	proc	near
+
+		xor	ax, ax
+		mov	ds, ax
+
+		;; TODO: This code is really stupid. Zeroing the BDA byte
+		;; by byte is dumb, and it's been already zeroed elsewhere!
+		mov	al, 0
+		mov	ds:[43Eh], al	; drive 0/1 uncalibrated, no IRQ
+		mov	ds:[43Fh], al	; motor status
+		mov	ds:[440h], al	; motor timeout counter
+		mov	ds:[441h], al	; controller status return code
+		mov	ds:[442h], al	; hd/floppy ctlr status register
+		mov	ds:[443h], al	; controller status register 1
+		mov	ds:[444h], al	; controller status register 2
+		mov	ds:[445h], al	; cylinder number
+		mov	ds:[446h], al	; head number
+		mov	ds:[447h], al	; sector number
+		mov	ds:[448h], al	; bytes written
+
+		mov	ds:[48Bh], al	; configuration data
+
+		mov	al, 10h		; floppy drive type
+		out	CMOS_ADDR, al
+		in	al, CMOS_DATA
+		mov	ah, al		; save drive type byte
+
+look_drive0:
+		; TODO: pre-init bl to reduce jumps
+		shr	al, 4		; drive 0 in high nibble
+		jz	f0_missing	; jump if no drive
+		mov	bl, 7		; drv0 determined, multi-rate, chgline
+		jmp	look_drive1
+
+f0_missing:
+		mov	bl, 0		; no drive 0
+
+look_drive1:
+		mov	al, ah		; restore CMOS data
+		and	al, 0Fh		; drive 1 in low nibble
+		jz	f1_missing
+		or	bl, 70h		; drv1 determined, multi-rate, chgline
+f1_missing:
+		mov	ds:[48Fh], bl	; store in BDA
+
+		;; TODO: See above. Dumb *and* redundant!
+		mov	al, 0	
+		mov	ds:[490h], al	; drv0 media state
+		mov	ds:[491h], al	; drv1 media state
+		mov	ds:[492h], al	; drv0 operational state
+		mov	ds:[493h], al	; drv1 operational state
+		mov	ds:[494h], al	; drv0 current cylinder
+		mov	ds:[495h], al	; drv1 current cylinder
+
+		mov	al, 2
+		out	0Ah, al		; unmask DMA channel 2
+
+		SET_INT_VECTOR 1Eh, BIOSSEG, _diskette_param_table
+		SET_INT_VECTOR 40h, BIOSSEG, int13_diskette
+		SET_INT_VECTOR 0Eh, BIOSSEG, int0e_handler	; IRQ 6
+
+		ret
+
+floppy_post	endp
+
+
+bcd_to_bin	proc	near
+
+		;; in : AL in packed BCD format
+		;; out: AL in binary, AH always 0
+		shl	ax, 4
+		shr	al, 4
+		aad
+		ret
+
+bcd_to_bin	endp
+
+rtc_post	proc	near
+
+		.386
+		;; get RTC seconds
+		xor	eax, eax
+		mov	al, 0
+		out	CMOS_ADDR, al
+		in	al, CMOS_DATA	; RTC seconds, in BCD
+		call	bcd_to_bin	; eax now has seconds in binary
+		mov	edx, 18206507
+		mul	edx
+		mov	ebx, 1000000
+		xor	edx, edx
+		div	ebx
+		mov	ecx, eax	; total ticks in ecx
+
+		;; get RTC minutes
+		xor	eax, eax
+		mov	al, 2
+		out	CMOS_ADDR, al
+		in	al, CMOS_DATA	; RTC minutes, in BCD
+		call	bcd_to_bin	; eax now has minutes in binary
+		mov	edx, 10923904
+		mul	edx
+		mov	ebx, 10000
+		xor	edx, edx
+		div	ebx
+		add	ecx, eax	; add to total ticks
+
+		;; get RTC hours
+		xor	eax, eax
+		mov	al, 4
+		out	CMOS_ADDR, al
+		in 	al, CMOS_DATA	; RTC hours, in BCD
+		call	bcd_to_bin	; eax now has hours in binary
+		mov	edx, 65543427
+		mul	edx
+		mov	ebx, 1000
+		xor	edx, edx
+		div	ebx
+		add	ecx, eax	; add to total ticks
+
+		mov	ds:[46Ch], ecx	; timer tick count
+		xor	al, al		; TODO: redundant?
+		mov	ds:[470h], al	; rollover flag
+		.286
+		ret
+
+rtc_post	endp
+
+
+
+;; --------------------------------------------------------
+;; INT 0Eh handler - Diskette IRQ 6 ISR
+;; --------------------------------------------------------
+		BIOSORG	0EF57h
+int0e_handler:
+		push	ax
+		push	dx
+		mov	dx, 3F4h
+		in	al, dx
+		and	al, 0C0h
+		cmp	al, 0C0h
+		je	int0e_normal
+		mov	dx, 3F5h
+		mov	al, 08h		; sense interrupt
+		out	dx, al
+int0e_loop1:
+		mov	dx, 3F4h	; TODO: move out of the loop?
+		in	al, dx
+		and	al, 0C0h
+		cmp	al, 0C0h
+		jne	int0e_loop1
+
+int0e_loop2:
+		mov	dx, 3F5h	; TODO: inc/dec dx instead
+		in	al, dx
+		mov	dx, 3F4h
+		in	al, dx
+		and	al, 0C0h
+		cmp	al, 0C0h
+		je	int0e_loop2
+
+int0e_normal:
+		push	ds
+		xor	ax, ax
+		mov	ds, ax
+		call	eoi_master_pic
+		; indicate that an interrupt occurred
+		or	byte ptr ds:[43Eh], 80h
+		pop	ds
+		pop	dx
+		pop	ax
+		iret
+
+
+;; --------------------------------------------------------
+;; Diskette Parameter Table
+;; --------------------------------------------------------
+		BIOSORG	0EFC7h
+_diskette_param_table:
+		db	0AFh
+		db	2		; HLT=1, DMA mode
+		db	025h
+		db	2
+		db	18		; SPT
+		db	01Bh
+		db	0FFh
+		db	06Ch
+		db	0F6h		; format filler
+		db	15
+		db	8
+
+
+;; Protected mode IDT descriptor
+;;
+;; The limit is 0 to cause a shutdown if an exception occurs
+;; in protected mode. TODO: Is that what we really want?
+;;
+;; Set base to F0000 to correspond to beginning of BIOS,
+;; in case an IDT is defined later.
+
+_pmode_IDT:
+		dw	0		; limit 15:0
+		dw	0		; base  15:0
+		dw	0Fh		; base  23:16
+
+
+;; Real mode IDT descriptor
+;;
+;; Set to typical real-mode values.
+;; base  = 000000
+;; limit =   03ff
+
+_rmode_IDT:
+		dw	3FFh		; limit 15:00
+		dw	0		; base  15:00
+		dw	0		; base  23:16
+
+
+
+;; --------------------------------------------------------
+;; INT 17h handler - Printer service
+;; --------------------------------------------------------
+;;		BIOSORG	0EFD2h - fixed WRT preceding code
+int17_handler:
+		push	ds
+		push	es
+		pusha
+		C_SETUP
+		call	_int17_function
+		popa
+		pop	es
+		pop	ds
+		iret
+		
+
+;;
+;; INT 1Ch
+;;
+;; TODO: Why does this need a special handler?
+int1c_handler:	;; user timer tick
+		iret
+
+
+
+;; --------------------------------------------------------
+;; INT 10h functions 0-Fh entry point
+;; --------------------------------------------------------
+		BIOSORG 0F045h
+i10f0f_entry:
+		iret
+
+
+;; --------------------------------------------------------
+;; INT 10h handler - MDA/CGA video
+;; --------------------------------------------------------
+		BIOSORG 0F065h
+int10_handler:
+		;; do nothing - assumes VGA
+		iret
+
+
+;; --------------------------------------------------------
+;; MDA/CGA Video Parameter Table (INT 1Dh)
+;; --------------------------------------------------------
+		BIOSORG 0F0A4h
+mdacga_vpt:
+
+
+;;
+;; INT 18h - boot failure
+;;
+int18_handler:
+		C_SETUP
+		call	_int18_panic_msg
+		;; TODO: handle failure better?
+		hlt
+		iret
+
+;;
+;; INT 19h - boot service - relocated
+;;
+int19_relocated:
+; If an already booted OS calls int 0x19 to reboot, it is not sufficient
+; just to try booting from the configured drives. All BIOS variables and
+; interrupt vectors need to be reset, otherwise strange things may happen.
+; The approach used is faking a warm reboot (which just skips showing the
+; logo), which is a bit more than what we need, but hey, it's fast.
+		mov	bp, sp
+		mov	ax, [bp+2]	; TODO: redundant? address via sp?
+		cmp	ax, BIOSSEG	; check caller's segment
+		jz	bios_initiated_boot
+
+		xor	ax, ax
+		mov	ds, ax
+		mov	ax, 1234h
+		mov	ds:[472], ax
+		jmp	post
+
+bios_initiated_boot:
+		;; The C worker function returns the boot drive in bl and
+		;; the boot segment in ax. In case of failure, the boot
+		;; segment will be zero.
+		C_SETUP			; TODO: Here? Now?
+		push	bp
+		mov	bp, sp
+
+		;; 1st boot device
+		mov	ax, 1
+		push	ax
+		call	_int19_function
+		inc	sp
+		inc	sp
+		test	ax, ax		; if 0, try next device
+		jnz	boot_setup
+
+		;; 2nd boot device
+		mov	ax, 2
+		push	ax
+		call	_int19_function
+		inc	sp
+		inc	sp
+		test	ax, ax		; if 0, try next device
+		jnz	boot_setup
+
+		; 3rd boot device
+		mov	ax, 3
+		push	3
+		call	_int19_function
+		inc	sp
+		inc	sp
+		test	ax, ax		; if 0, try next device
+		jnz	boot_setup
+
+		; 4th boot device
+		mov	ax, 4
+		push	ax
+		call	_int19_function
+		inc	sp
+		inc	sp
+		test	ax, ax		; if 0, invoke INT 18h
+		jz	int18_handler
+
+boot_setup:
+; TODO: the drive should be in dl already??
+;;		mov	dl, bl		; tell guest OS what boot drive is
+		.386	; NB: We're getting garbage into high eax bits
+		shl	eax, 4		; convert seg to ip
+		mov	[bp+2], ax	; set ip
+
+		shr	eax, 4		; get cs back
+		.286
+		and	ax, BIOSSEG	; remove what went in ip
+		mov	[bp+4], ax	; set cs
+		xor	ax, ax
+		mov	ds, ax
+		mov	es, ax
+		mov	[bp], ax	; TODO: what's this?!
+		mov	ax, 0AA55h	; set ok flag ; TODO: and this?
+
+		pop	bp		; TODO: why'd we just zero it??
+		iret			; beam me up scotty
+
+;; PCI BIOS
+
+include pcibios.inc
+include pirq.inc
+
+
+;; --------------------------------------------------------
+;; INT 12h handler - Memory size
+;; --------------------------------------------------------
+		BIOSORG	0F841h
+int12_handler:
+		;; Don't touch - fixed size!
+		sti
+		push	ds
+		mov	ax, 40h
+		mov	ds, ax
+		mov	ax, ds:[13h]
+		pop	ds
+		iret
+
+
+;; --------------------------------------------------------
+;; INT 11h handler - Equipment list service
+;; --------------------------------------------------------
+;;		BIOSORG	0F84Dh - fixed wrt preceding code
+int11_handler:
+		;; Don't touch - fixed size!
+		sti
+		push	ds
+		mov	ax, 40h
+		mov	ds, ax
+		mov	ax, ds:[10h]
+		pop	ds
+		iret
+
+
+;; --------------------------------------------------------
+;; INT 15h handler - System services
+;; --------------------------------------------------------
+;;		BIOSORG	0F859h - fixed wrt preceding code
+int15_handler:
+		pushf
+		cmp	ah, 53h		; APM function?
+		je	apm_call
+		push	ds
+		push	es
+		C_SETUP
+		cmp	ah, 86h
+		je	int15_handler32
+		cmp	ah, 0E8h
+		je	int15_handler32
+		pusha
+		cmp	ah, 0C2h
+		je	int15_handler_mouse
+
+		call	_int15_function
+int15_handler_mouse_ret:
+		popa
+int15_handler32_ret:
+		pop	es
+		pop	ds
+		popf
+		jmp	iret_modify_cf
+
+apm_call:
+; TODO!!
+		popf
+		stc
+		jmp	iret_modify_cf
+;		jmp	apmreal_entry
+
+int15_handler_mouse:
+		call	_int15_function_mouse
+		jmp	int15_handler_mouse_ret
+
+int15_handler32:
+		;; need to save/restore 32-bit registers
+		.386
+		pushad
+		call	_int15_function32
+		popad
+		.286
+		jmp	int15_handler32_ret
+
+;;
+;; Perform an IRET but retain the current carry flag value
+;;
+iret_modify_cf:
+		jc	carry_set
+		push	bp
+		mov	bp, sp
+		and	byte ptr [bp + 6], 0FEh
+		pop	bp
+		iret
+carry_set:
+		push	bp
+		mov	bp, sp
+		or	byte ptr [bp + 6], 1
+		pop	bp
+		iret
+
+;;
+;; INT 74h handler - PS/2 mouse (IRQ 12)
+;;
+int74_handler	proc
+
+		sti
+		pusha
+		push	es
+		push	ds
+		push	0		; placeholder for status
+		push	0		; placeholder for X
+		push	0		; placeholder for Y
+		push	0		; placeholder for Z
+		push	0		; placeholder for make_far_call bool
+		C_SETUP
+		call	_int74_function
+		pop	cx		; pop make_far_call flag
+		jcxz	int74_done
+
+		;; make far call to EBDA:0022
+		push	0
+		pop	ds
+		push	ds:[40Eh]
+		pop	ds
+		call	far ptr ds:[22h]
+int74_done:
+		cli
+		call	eoi_both_pics
+		add	sp, 8		; remove status, X, Y, Z
+		pop	ds
+		pop	es
+		popa
+		iret
+
+int74_handler	endp
+
+int76_handler	proc
+
+		;; record completion in BIOS task complete flag
+		push	ax
+		push	ds
+		mov	ax, 40h
+		mov	ds, ax
+		mov	byte ptr ds:[8Eh], 0FFh
+		call	eoi_both_pics
+		pop	ds
+		pop	ax
+		iret
+		
+int76_handler	endp	
+
+;; --------------------------------------------------------
+;; 8x8 font (first 128 characters)
+;; --------------------------------------------------------
+		BIOSORG	0FA6Eh
+include font8x8.inc
+
+
+;; --------------------------------------------------------
+;; INT 1Ah handler - Time of the day + PCI BIOS
+;; --------------------------------------------------------
+;;		BIOSORG	0FE6Eh - fixed wrt preceding table
+int1a_handler:
+		cmp	ah, 0B1h
+		jne	int1a_normal
+
+		call	pcibios_real
+		jc	pcibios_error
+
+		retf	2
+pcibios_error:
+;		mov	bl, ah
+;		mov	ah, 0B1h
+		pusha
+;		mov	ax, ss	; set readable descriptor to DS for calling
+;		mov	ds, ax	; PCI BIOS from 16-bit protected mode
+		; TODO: C environment?!
+		call	_int1a_function_pci
+		popa
+		iret
+
+int1a_normal:
+		push	es
+		push	ds
+		pusha
+		C_SETUP
+int1a_callfunction:
+		call	_int1a_function
+		popa
+		pop	ds
+		pop	es
+		iret
+
+
+;;
+;; IRQ 8 handler (RTC)
+;;
+int70_handler:
+		push	es
+		push	ds
+		pusha
+		C_SETUP
+		call	_int70_function
+		popa
+		pop	ds
+		pop	es
+		iret
+
+
+;; --------------------------------------------------------
+;; Timer tick - IRQ 0 handler
+;; --------------------------------------------------------
+		BIOSORG	0FEA5h
+int08_handler:
+		.386
+		sti
+		push	eax
+		push	ds
+		xor	ax, ax
+		mov	ds, ax
+
+		;; time to turn off floppy driv motor(s)?
+		mov	al, ds:[440h]
+		or	al, al
+		jz	int08_floppy_off
+		;; turn motor(s) off
+		push	dx
+		mov	dx, 03F2h
+		in	al, dx
+		and	al, 0CFh
+		out	dx, al
+		pop	dx
+
+int08_floppy_off:
+		mov	eax, ds:[46Ch]	; get ticks dword
+		inc	eax
+
+		;; compare eax to one day's worth of ticks (at 18.2 Hz)
+		cmp	eax, 1700B0h
+		jb	int08_store_ticks
+		;; there has been a midnight rollover
+		xor	eax, eax
+		inc	byte ptr ds:[470h]	; increment rollover flag
+
+int08_store_ticks:
+		mov	ds:[46Ch], eax
+		int	1Ch		; call the user timer handler
+		cli
+		call	eoi_master_pic
+		pop	ds
+		pop	eax
+		.286
+		iret
+
+
+;; --------------------------------------------------------
+;; Initial interrupt vector offsets for POST
+;; --------------------------------------------------------
+		BIOSORG	0FEF3h
+vector_table:
+
+
+
+;; --------------------------------------------------------
+;; BIOS copyright string
+;; --------------------------------------------------------
+		BIOSORG	0FF00h
+bios_string:
+		db	BIOS_COPYRIGHT
+
+
+;; --------------------------------------------------------
+;; IRET - default interrupt handler
+;; --------------------------------------------------------
+		BIOSORG	0FF53h
+
+dummy_iret:
+		iret
+
+
+;; --------------------------------------------------------
+;; INT 05h - Print Screen service
+;; --------------------------------------------------------
+;;		BIOSORG	0FF54h - fixed wrt preceding
+int05_handler:
+		;; Not implemented
+		iret
+
+include smidmi.inc
+
+;; --------------------------------------------------------
+;; Processor reset entry point
+;; --------------------------------------------------------
+		BIOSORG	0FFF0h
+cpu_reset:
+		;; This is where the CPU starts executing after a reset
+		jmp	far ptr post
+
+		;; BIOS build date
+		db	BIOS_BUILD_DATE
+		db	0			; padding
+		;; System model ID
+		db	SYS_MODEL_ID
+		;; Checksum byte
+		db	0FFh
+
+
+BIOSSEG		ends
+
+		end
Index: /trunk/src/VBox/Devices/PC/BIOS-new/parallel.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/parallel.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/parallel.c	(revision 38699)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "biosint.h"
+#include "inlines.h"
+
+void BIOSCALL int17_function(pusha_regs_t regs, uint16_t es, uint16_t ds, iret_addr_t iret_addr)
+{
+    uint16_t    addr,timeout;
+    uint8_t     val8;
+
+    int_enable();
+    
+    addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
+    if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
+        timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
+        if (regs.u.r8.ah == 0) {
+            outb(addr, regs.u.r8.al);
+            val8 = inb(addr+2);
+            outb(addr+2, val8 | 0x01); // send strobe
+            outb(addr+2, val8 & ~0x01);
+            while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
+                timeout--;
+            }
+        }
+        if (regs.u.r8.ah == 1) {
+            val8 = inb(addr+2);
+            outb(addr+2, val8 & ~0x04); // send init
+            outb(addr+2, val8 | 0x04);
+        }
+        val8 = inb(addr+1);
+        regs.u.r8.ah = (val8 ^ 0x48);
+        if (!timeout) regs.u.r8.ah |= 0x01;
+        ClearCF(iret_addr.flags);
+    } else {
+        SetCF(iret_addr.flags); // Unsupported
+    }
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/pcibio32.asm
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/pcibio32.asm	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/pcibio32.asm	(revision 38699)
@@ -0,0 +1,281 @@
+;;
+;; Copyright (C) 2006-2011 Oracle Corporation
+;;
+;; This file is part of VirtualBox Open Source Edition (OSE), as
+;; available from http://www.virtualbox.org. This file is free software;
+;; you can redistribute it and/or modify it under the terms of the GNU
+;; General Public License (GPL) as published by the Free Software
+;; Foundation, in version 2 as it comes in the "COPYING" file of the
+;; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+;; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;; --------------------------------------------------------------------
+;;
+;; This code is based on:
+;;
+;;  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+;;
+;;  Copyright (C) 2002  MandrakeSoft S.A.
+;;
+;;    MandrakeSoft S.A.
+;;    43, rue d'Aboukir
+;;    75002 Paris - France
+;;    http://www.linux-mandrake.com/
+;;    http://www.mandrakesoft.com/
+;;
+;;  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
+;;
+;;
+
+include	pcicfg.inc
+
+if BX_PCIBIOS
+
+.386
+
+BIOS32		segment	public 'CODE' use32
+
+public		pcibios_protected
+
+align   16
+bios32_structure:
+		db	'_32_'		; signature
+		dw	bios32_entry_point, 0Fh ;; 32 bit physical address
+		db	0		; revision level
+		db	1		; length in paragraphs
+		db	0		; checksum (updated externally)
+		db 	0,0,0,0,0	; reserved
+
+align 16
+bios32_entry_point:
+		pushfd
+		cmp	eax, 'ICP$'		; 0x49435024 "$PCI"
+		jne	unknown_service
+
+ifdef PCI_FIXED_HOST_BRIDGE_1
+		mov	eax, 80000000h
+		mov	dx, PCI_CFG1
+		out	dx, eax
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		cmp	eax, PCI_FIXED_HOST_BRIDGE_1
+		je	device_ok
+endif
+
+ifdef PCI_FIXED_HOST_BRIDGE_2
+		; 1Eh << 11
+		mov	eax, 8000f000h
+		mov	dx, PCI_CFG1
+		out	dx, eax
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		cmp	eax, PCI_FIXED_HOST_BRIDGE_2
+		je	device_ok
+endif
+		jmp	unknown_service
+device_ok:
+		mov	ebx, 000f0000h
+		mov	ecx, 0
+		mov	edx, pcibios_protected
+		xor	al, al
+		jmp	bios32_end
+
+unknown_service:
+		mov	al, 80h
+bios32_end:
+		popfd
+		retf
+
+align 16
+pcibios_protected:
+		pushfd
+		cli
+		push	esi
+		push	edi
+		cmp	al, 1		; installation check
+		jne	pci_pro_f02
+
+		mov	bx, 0210h
+		mov	cx, 0
+		mov	edx, ' ICP'	; 0x20494350 "PCI "
+		mov	al, 1
+		jmp	pci_pro_ok
+
+pci_pro_f02: ;; find pci device
+		cmp	al, 2
+		jne	pci_pro_f03
+
+		shl	ecx, 16
+		mov	cx, dx
+		xor	ebx, ebx
+		mov	di, 0
+pci_pro_devloop:
+		call	pci_pro_select_reg
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		cmp	eax, ecx
+		jne	pci_pro_nextdev
+
+		cmp	si, 0
+		je	pci_pro_ok
+
+		dec	si
+pci_pro_nextdev:
+		inc	ebx
+		cmp	ebx, 10000h
+		jne	pci_pro_devloop
+
+		mov	ah, 86h
+		jmp	pci_pro_fail
+
+pci_pro_f03: ;; find class code
+		cmp	al, 3
+		jne	pci_pro_f08
+
+		xor	ebx, ebx
+		mov	di, 8
+pci_pro_devloop2:
+		call	pci_pro_select_reg
+		mov	dx, PCI_CFG2
+		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	ebx
+		cmp	ebx, 10000h
+		jne	pci_pro_devloop2
+
+		mov	ah, 86h
+		jmp	pci_pro_fail
+
+pci_pro_f08: ;; read configuration byte
+		cmp	al, 8
+		jne	pci_pro_f09
+
+		call	pci_pro_select_reg
+		push	edx
+		mov	dx, di
+		and	dx, 3
+		add	dx, PCI_CFG2
+		in	al, dx
+		pop	edx
+		mov	cl, al
+		jmp	 pci_pro_ok
+
+pci_pro_f09: ;; read configuration word
+		cmp	al, 9
+		jne	pci_pro_f0a
+
+		call	pci_pro_select_reg
+		push	edx
+		mov	dx, di
+		and	dx, 2
+		add	dx, PCI_CFG2
+		in	ax, dx
+		pop	edx
+		mov	cx, ax
+		jmp	pci_pro_ok
+
+pci_pro_f0a: ;; read configuration dword
+		cmp	al, 0Ah
+		jne	pci_pro_f0b
+
+		call	pci_pro_select_reg
+		push	edx
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		pop	edx
+		mov	ecx, eax
+		jmp	pci_pro_ok
+
+pci_pro_f0b: ;; write configuration byte
+		cmp	al, 0Bh
+		jne	pci_pro_f0c
+
+		call	pci_pro_select_reg
+		push	edx
+		mov	dx, di
+		and	dx, 3
+		add	dx, PCI_CFG2
+		mov	al, cl
+		out	dx, al
+		pop	edx
+		jmp	pci_pro_ok
+
+pci_pro_f0c: ;; write configuration word
+		cmp	al, 0Ch
+		jne	pci_pro_f0d
+
+		call	pci_pro_select_reg
+		push	edx
+		mov	dx, di
+		and	dx, 2
+		add	dx, PCI_CFG2
+		mov	ax, cx
+		out	dx, ax
+		pop	edx
+		jmp	pci_pro_ok
+
+pci_pro_f0d: ;; write configuration dword
+		cmp	al, 0Dh
+		jne	pci_pro_unknown
+		call	pci_pro_select_reg
+		push	edx
+		mov	dx, PCI_CFG2
+		mov	eax, ecx
+		out	dx, eax
+		pop	edx
+		jmp	pci_pro_ok
+
+pci_pro_unknown:
+		mov	ah, 81h
+pci_pro_fail:
+		pop	edi
+		pop	esi
+		popfd
+		stc
+		retf
+
+pci_pro_ok:
+		xor	ah, ah
+		pop	edi
+		pop	esi
+		popfd
+		clc
+		retf
+
+pci_pro_select_reg:
+		push	edx
+		mov	eax, 800000h
+		mov	ax,  bx
+		shl	eax, 8
+		and	di,  0FFh
+		or	ax,  di
+		and	al,  0FCh
+		mov	dx,  PCI_CFG1
+		out	dx,  eax
+		pop	edx
+		ret
+
+BIOS32		ends
+
+endif		 ; BX_PCIBIOS
+
+		end
Index: /trunk/src/VBox/Devices/PC/BIOS-new/pcibios.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/pcibios.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/pcibios.inc	(revision 38699)
@@ -0,0 +1,564 @@
+;;
+;; Copyright (C) 2006-2011 Oracle Corporation
+;;
+;; This file is part of VirtualBox Open Source Edition (OSE), as
+;; available from http://www.virtualbox.org. This file is free software;
+;; you can redistribute it and/or modify it under the terms of the GNU
+;; General Public License (GPL) as published by the Free Software
+;; Foundation, in version 2 as it comes in the "COPYING" file of the
+;; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+;; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;; --------------------------------------------------------------------
+;;
+;; This code is based on:
+;;
+;;  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+;;
+;;  Copyright (C) 2002  MandrakeSoft S.A.
+;;
+;;    MandrakeSoft S.A.
+;;    43, rue d'Aboukir
+;;    75002 Paris - France
+;;    http://www.linux-mandrake.com/
+;;    http://www.mandrakesoft.com/
+;;
+;;  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
+;;
+;;
+
+include	pcicfg.inc
+
+if BX_PCIBIOS
+
+extrn		pcibios_protected:near	; in a 32-bit segment
+
+.386
+pcibios_real:
+		push	eax
+		push	dx
+ifdef PCI_FIXED_HOST_BRIDGE_1
+		mov	eax, 80000000h
+		mov	dx, PCI_CFG1
+		out	dx, eax
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		cmp	eax, PCI_FIXED_HOST_BRIDGE_1
+		je	pci_present
+endif
+
+ifdef PCI_FIXED_HOST_BRIDGE_2
+		; 1Eh << 11
+		mov	eax, 8000f000h
+		mov	dx, PCI_CFG1
+		out	dx, eax
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		cmp	eax, PCI_FIXED_HOST_BRIDGE_2
+		je	pci_present
+endif
+		pop	dx
+		pop	eax
+		mov	ah, 0FFh
+		stc
+		ret
+pci_present:
+		pop	dx
+		pop	eax
+		cmp	al, 1		; installation check
+		jne pci_real_f02
+		mov	ax, 0001h
+		mov	bx, 0210h
+		mov	cx, 0
+		mov	edx, ' ICP'	; #0x20494350 "PCI "
+;; @todo!
+if 0
+		mov	edi, 0f0000h
+		mov	di, pcibios_protected
+else
+		mov	edi, pcibios_protected
+endif
+		clc
+		ret
+
+pci_real_f02: ;; find pci device
+		push	esi
+		push	edi
+		push	edx
+		cmp	al, 2
+		jne	pci_real_f03
+
+		shl	ecx, 16
+		mov	cx, dx
+		xor	ebx, ebx
+		mov	di, 0
+pci_real_devloop:
+		call	pci_real_select_reg
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		cmp	eax, ecx
+		jne	pci_real_nextdev
+
+		cmp	si, 0
+		je	pci_real_ok
+
+		dec	si
+pci_real_nextdev:
+		inc	ebx
+		cmp	ebx, 10000h
+		jne	pci_real_devloop
+
+		mov	dx, cx
+		shr	ecx, 16
+		mov	ax, 8602h
+		jmp	pci_real_fail
+pci_real_f03: ;; find class code
+		cmp	al, 3
+		jne	pci_real_f08
+		xor	ebx, ebx
+		mov	di, 8
+pci_real_devloop2:
+		call	pci_real_select_reg
+		mov	dx, PCI_CFG2
+		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	ebx
+		cmp	ebx, 10000h
+		jne	pci_real_devloop2
+
+		mov	ax, 8603h
+		jmp	pci_real_fail
+
+pci_real_f08: ;; read configuration byte
+		cmp	al, 8
+		jne	pci_real_f09
+
+		call	pci_real_select_reg
+		push	dx
+		mov	dx, di
+		and	dx, 3
+		add	dx, PCI_CFG2
+		in	al, dx
+		pop	dx
+		mov	cl, al
+		jmp	pci_real_ok
+
+pci_real_f09: ;; read configuration word
+		cmp	al, 9
+		jne	pci_real_f0a
+
+		call	pci_real_select_reg
+		push	dx
+		mov	dx, di
+		and	dx, 2
+		add	dx, PCI_CFG2
+		in	ax, dx
+		pop	dx
+		mov	cx, ax
+		jmp	pci_real_ok
+pci_real_f0a: ;; read configuration dword
+		cmp	al, 0Ah
+		jne	pci_real_f0b
+
+		call	pci_real_select_reg
+		push	dx
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		pop	dx
+		mov	ecx, eax
+		jmp	pci_real_ok
+
+pci_real_f0b: ;; write configuration byte
+		cmp	al, 0Bh
+		jne	pci_real_f0c
+
+		call	pci_real_select_reg
+		push	dx
+		mov	dx, di
+		and	dx, 3
+		add	dx, PCI_CFG2
+		mov	al, cl
+		out	dx, al
+		pop	dx
+		jmp	pci_real_ok
+
+pci_real_f0c: ;; write configuration word
+		cmp	al, 0Ch
+		jne	pci_real_f0d
+
+		call	pci_real_select_reg
+		push	dx
+		mov	dx, di
+		and	dx, 2
+		add	dx, PCI_CFG2
+		mov	ax, cx
+		out	dx, ax
+		pop	dx
+		jmp	pci_real_ok
+
+pci_real_f0d: ;; write configuration dword
+		cmp	al, 0Dh
+		jne	pci_real_f0e
+
+		call	pci_real_select_reg
+		push	dx
+		mov	dx, PCI_CFG2
+		mov	eax, ecx
+		out	dx, eax
+		pop	dx
+		jmp	pci_real_ok
+
+pci_real_f0e: ;; get irq routing options
+		cmp	al, 0Eh
+		jne	pci_real_unknown
+
+		cmp	word ptr es:[di], pci_routing_table_structure_end - pci_routing_table_structure_start
+		jb	pci_real_too_small
+
+		mov	word ptr es:[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
+		mov	cx, es:[di+2]
+		mov	es, 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 shl 9) or (1 shl 11) ; #(1 << 9) | (1 << 11)   ;; irq 9 and 11 are used
+		jmp	pci_real_ok
+
+pci_real_too_small:
+		mov	word ptr es:[di], pci_routing_table_structure_end - pci_routing_table_structure_start
+		mov	ah, 89h
+		jmp	pci_real_fail
+
+pci_real_unknown:
+		mov	ah, 81h
+pci_real_fail:
+		pop	edx
+		pop	edi
+		pop	esi
+		stc
+		ret
+pci_real_ok:
+		xor	ah, ah
+		pop	edx
+		pop	edi
+		pop	esi
+		clc
+		ret
+
+;; prepare from reading the PCI config space; on input:
+;; bx = bus/dev/fn
+;; di = offset into config space header
+;; destroys eax and may modify di
+pci_real_select_reg:
+		push	dx
+		mov	eax, 800000h
+		mov	ax,  bx
+		shl	eax, 8
+		and	di,  0FFh
+		or	ax,  di
+		and	al,  0FCh
+		mov	dx,  PCI_CFG1
+		out	dx,  eax
+		pop	dx
+		ret
+
+if not BX_ROMBIOS32
+pci_irq_list:
+		db 11, 10, 9, 5;
+
+pcibios_init_sel_reg:
+		push	eax
+		mov	eax, 800000h
+		mov	ax,  bx
+		shl	eax, 8
+		and	dl,  0FCh
+		or	al,  dl
+		mov	dx,  PCI_CFG1
+		out	dx,  eax
+		pop	eax
+		ret
+
+pcibios_init_iomem_bases:
+		push	bp
+		mov	bp, sp
+		mov	eax, 0E0000000h	; base for memory init
+		push	eax
+		mov	ax, 0C000h	; base for i/o init
+		push	ax
+		mov	ax, 010h	; start at base address #0
+		push	ax
+		mov	bx, 8
+pci_init_io_loop1:
+		mov	dl, 0
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		in	ax, dx
+		cmp	ax, 0FFFFh
+		jz	next_pci_dev
+
+ifndef VBOX ; This currently breaks restoring a previously saved state. */
+		mov	dl, 4	; disable i/o and memory space access
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		in	al, dx
+		and	al, 0FCh
+		out	dx, al
+pci_init_io_loop2:
+		mov	dl, [bp-8]
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		test	al, 1
+		jnz	init_io_base
+
+		mov	ecx, eax
+		mov	eax, 0FFFFFFFFh
+		out	dx, eax
+		in	eax, dx
+		cmp	eax, ecx
+		je	next_pci_base
+		xor	eax, 0FFFFFFFFh
+		mov	ecx, eax
+		mov	eax, [bp-4]
+		out	dx, eax
+		add	eax, ecx	; calculate next free mem base
+		add	eax, 01000000h
+		and	eax, 0FF000000h
+		mov	[bp-4], eax
+		jmp	next_pci_base
+
+init_io_base:
+		mov	cx, ax
+		mov	ax, 0FFFFh
+		out	dx, ax
+		in	ax, dx
+		cmp	ax, cx
+		je	next_pci_base
+
+		xor	ax, 0FFFEh
+		mov	cx, ax
+		mov	ax, [bp-6]
+		out	dx, ax
+		add	ax, cx	; calculate next free i/o base
+		add	ax, 00100h
+		and	ax, 0FF00h
+		mov	[bp-6], ax
+next_pci_base:
+		mov	al, [bp-8]
+		add	al, 4
+		cmp	al, 28h
+		je	enable_iomem_space
+
+		mov	byte ptr[bp-8], al
+		jmp	pci_init_io_loop2
+endif ; !VBOX
+
+enable_iomem_space:
+		mov	dl, 4 ;; enable i/o and memory space access if available
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		in	al, dx
+		or	al, 7
+		out	dx, al
+ifdef VBOX
+		mov	dl, 0	; check if PCI device is AMD PCNet
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		in	eax, dx
+		cmp	eax, 020001022h
+		jne	next_pci_dev
+
+		mov	dl, 10h	; get I/O address
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		in	ax, dx
+		and	ax, 0FFFCh
+		mov	cx, ax
+		mov	dx, cx
+		add	dx, 14h	; reset register if PCNet is in word I/O mode
+		in	ax, dx	; reset is performed by reading the reset register
+		mov	dx, cx
+		add	dx, 18h	; reset register if PCNet is in word I/O mode
+		in	eax, dx	; reset is performed by reading the reset register
+endif ; VBOX 
+next_pci_dev:
+		mov	byte ptr[bp-8], 10h
+		inc	bx
+		cmp	bx, 0100h
+		jne	pci_init_io_loop1
+		mov	sp, bp
+		pop	bp
+		ret
+
+pcibios_init_set_elcr:
+		push	ax
+		push	cx
+		mov	dx, 04D0h
+		test	al, 8
+		jz	is_master_pic
+
+		inc	dx
+		and	al, 7
+is_master_pic:
+		mov	cl, al
+		mov	bl, 1
+		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, 0F000h
+		mov	ds, ax
+		mov	dx, 04D0h ;; reset ELCR1 + ELCR2
+		mov	al, 0
+		out	dx, al
+		inc	dx
+		out	dx, al
+		mov	si, pci_routing_table_structure
+		mov	bh, [si+8]
+		mov	bl, [si+9]
+		mov	dl, 0
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		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, PCI_CFG2
+		mov	ax, 8080h
+		out	dx, ax ;; reset PIRQ route control
+		add	dx, 2
+		out	dx, ax
+		mov	ax, [si+6]
+		sub	ax, 20h
+		shr	ax, 4
+		mov	cx, ax
+		add	si, 20h ;; 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, 0
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		in	ax, dx
+		cmp	ax, 0FFFFh
+		jnz	pci_test_int_pin
+
+		test	bl, 7
+		jz	next_pir_entry
+
+		jmp	next_pci_func
+
+pci_test_int_pin:
+		mov	dl, 3Ch
+		call pcibios_init_sel_reg
+		mov	dx, PCI_CFG2 + 1 ; TODO: was #0x0cfd - is that right?
+		in	al, dx
+		and	al, 7
+		jz	next_pci_func
+
+		dec	al ;; determine pirq reg
+		mov	dl, 3
+		mul	dl
+		add	al, 2
+		xor	ah, ah
+		mov	bx, ax
+		mov	al, [si+bx]
+		mov	dl, al
+		mov	bx, [bp]
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		and	al, 3
+		add	dl, al
+		in	al, dx
+		cmp	al, 80h
+		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, 3Ch
+		call	pcibios_init_sel_reg
+		mov	dx, PCI_CFG2
+		out	dx, al
+next_pci_func:
+		inc	byte ptr[bp-3]
+		inc	bl
+		test	bl, 7
+		jnz	pci_init_irq_loop2
+
+next_pir_entry:
+		add	si, 10h
+		mov	byte ptr[bp-3], 0
+		loop	pci_init_irq_loop1
+
+		mov	sp, bp
+		pop	bx
+pci_init_end:
+		pop		bp
+		pop		ds
+		ret
+
+.286
+
+endif		 ; !BX_ROMBIOS32
+
+endif		 ; BX_PCIBIOS
+
Index: /trunk/src/VBox/Devices/PC/BIOS-new/pcicfg.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/pcicfg.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/pcicfg.inc	(revision 38699)
@@ -0,0 +1,9 @@
+
+BX_PCIBIOS		equ	1		; Enable PCI BIOS
+
+PCI_CFG1        	equ     0CF8h
+PCI_CFG2        	equ     0CFCh
+
+PCI_FIXED_HOST_BRIDGE_1 equ	12378086h	;; i440FX PCI bridge
+PCI_FIXED_HOST_BRIDGE_2 equ	244e8086h	;; ICH9 PCI bridge
+
Index: /trunk/src/VBox/Devices/PC/BIOS-new/pirq.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/pirq.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/pirq.inc	(revision 38699)
@@ -0,0 +1,459 @@
+;;
+;; Copyright (C) 2006-2011 Oracle Corporation
+;;
+;; This file is part of VirtualBox Open Source Edition (OSE), as
+;; available from http://www.virtualbox.org. This file is free software;
+;; you can redistribute it and/or modify it under the terms of the GNU
+;; General Public License (GPL) as published by the Free Software
+;; Foundation, in version 2 as it comes in the "COPYING" file of the
+;; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+;; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;; --------------------------------------------------------------------
+;;
+;; This code is based on:
+;;
+;;  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+;;
+;;  Copyright (C) 2002  MandrakeSoft S.A.
+;;
+;;    MandrakeSoft S.A.
+;;    43, rue d'Aboukir
+;;    75002 Paris - France
+;;    http://www.linux-mandrake.com/
+;;    http://www.mandrakesoft.com/
+;;
+;;  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
+;;
+;;
+
+if BX_PCIBIOS
+
+align 16
+pci_routing_table_structure:
+  db '$PIR'  ;; "$PIR" signature
+  db 0, 1 ;; version
+ifdef VBOX
+  dw 32 + (30 * 16) ;; table size
+else ; !VBOX
+  dw 32 + (6 * 16) ;; table size
+endif ; !VBOX
+  db 0 ;; PCI interrupt router bus
+  db 8 ;; PCI interrupt router DevFunc
+  dw 0000h ;; PCI exclusive IRQs
+  dw 8086h ;; compatible PCI interrupt router vendor ID
+  dw 7000h ;; compatible PCI interrupt router device ID
+  dw 0,0 ;; Miniport data
+  db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
+ifdef VBOX
+  db 0 ;; checksum (set by biossums)
+else ; !VBOX
+  db 7 ;; checksum
+endif ; !VBOX
+pci_routing_table_structure_start:
+  ;; first slot entry PCI-to-ISA (embedded)
+  db 0 ;; pci bus number
+  db 008h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#: pointer into PCI2ISA config space
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 0 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; second slot entry: 1st PCI slot
+  db 0 ;; pci bus number
+  db 010h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 1 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; third slot entry: 2nd PCI slot
+  db 0 ;; pci bus number
+  db 018h ;; pci device number (bit 7-3)
+  db 62h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 63h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 60h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 61h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 2 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 4th slot entry: 3rd PCI slot
+  db 0 ;; pci bus number
+  db 020h ;; pci device number (bit 7-3)
+  db 63h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 60h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 61h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 62h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 3 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 5th slot entry: 4rd PCI slot
+  db 0 ;; pci bus number
+  db 028h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 4 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 6th slot entry: 5rd PCI slot
+  db 0 ;; pci bus number
+  db 030h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 5 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+ifdef VBOX
+  ;; 7th slot entry: 6th PCI slot
+  db 0 ;; pci bus number
+  db 038h ;; pci device number (bit 7-3)
+  db 62h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 63h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 60h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 61h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 6 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 8th slot entry: 7th PCI slot
+  db 0 ;; pci bus number
+  db 040h ;; pci device number (bit 7-3)
+  db 63h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 60h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 61h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 62h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 7 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 9th slot entry: 8th PCI slot
+  db 0 ;; pci bus number
+  db 048h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 8 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 10th slot entry: 9th PCI slot
+  db 0 ;; pci bus number
+  db 050h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 9 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 11th slot entry: 10th PCI slot
+  db 0 ;; pci bus number
+  db 058h ;; pci device number (bit 7-3)
+  db 62h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 63h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 60h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 61h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 10 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 12th slot entry: 11th PCI slot
+  db 0 ;; pci bus number
+  db 60h ;; pci device number (bit 7-3)
+  db 63h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 60h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 61h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 62h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 11 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 13th slot entry: 12th PCI slot
+  db 0 ;; pci bus number
+  db 068h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 12 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 14th slot entry: 13th PCI slot
+  db 0 ;; pci bus number
+  db 070h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 13 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 15th slot entry: 14th PCI slot
+  db 0 ;; pci bus number
+  db 078h ;; pci device number (bit 7-3)
+  db 62h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 63h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 60h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 61h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 14 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 16th slot entry: 15th PCI slot
+  db 0 ;; pci bus number
+  db 080h ;; pci device number (bit 7-3)
+  db 63h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 60h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 61h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 62h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 15 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 17th slot entry: 16th PCI slot
+  db 0 ;; pci bus number
+  db 088h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 16 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 18th slot entry: 17th PCI slot
+  db 0 ;; pci bus number
+  db 090h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 17 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 19th slot entry: 18th PCI slot
+  db 0 ;; pci bus number
+  db 098h ;; pci device number (bit 7-3)
+  db 62h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 63h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 60h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 61h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 18 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 20th slot entry: 19th PCI slot
+  db 0 ;; pci bus number
+  db 0A0h ;; pci device number (bit 7-3)
+  db 63h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 60h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 61h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 62h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 19 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 21st slot entry: 20th PCI slot
+  db 0 ;; pci bus number
+  db 0A8h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 20 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 22nd slot entry: 21st PCI slot
+  db 0 ;; pci bus number
+  db 0B0h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 21 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 23rd slot entry: 22nd PCI slot
+  db 0 ;; pci bus number
+  db 0B8h ;; pci device number (bit 7-3)
+  db 62h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 63h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 60h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 61h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 22 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 24th slot entry: 23rd PCI slot
+  db 0 ;; pci bus number
+  db 0C0h ;; pci device number (bit 7-3)
+  db 63h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 60h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 61h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 62h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 23 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 25th slot entry: 24th PCI slot
+  db 0 ;; pci bus number
+  db 0C8h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 24 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 26th slot entry: 25th PCI slot
+  db 0 ;; pci bus number
+  db 0D0h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 25 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 27th slot entry: 26th PCI slot
+  db 0 ;; pci bus number
+  db 0D8h ;; pci device number (bit 7-3)
+  db 62h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 63h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 60h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 61h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 26 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 28th slot entry: 27th PCI slot
+  db 0 ;; pci bus number
+  db 0E0h ;; pci device number (bit 7-3)
+  db 63h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 60h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 61h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 62h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 27 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 29th slot entry: 28th PCI slot
+  db 0 ;; pci bus number
+  db 0E8h ;; pci device number (bit 7-3)
+  db 60h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 61h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 62h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 63h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 28 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 30th slot entry: 29th PCI slot
+  db 0 ;; pci bus number
+  db 0F0h ;; pci device number (bit 7-3)
+  db 61h ;; link value INTA#
+  dw 0DEF8h ;; IRQ bitmap INTA#
+  db 62h ;; link value INTB#
+  dw 0DEF8h ;; IRQ bitmap INTB#
+  db 63h ;; link value INTC#
+  dw 0DEF8h ;; IRQ bitmap INTC#
+  db 60h ;; link value INTD#
+  dw 0DEF8h ;; IRQ bitmap INTD#
+  db 29 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+endif ; VBOX
+pci_routing_table_structure_end:
+
+endif   ; BX_PCIBIOS
Index: /trunk/src/VBox/Devices/PC/BIOS-new/pmode.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/pmode.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/pmode.inc	(revision 38699)
@@ -0,0 +1,73 @@
+;; @file
+;; Enter and exit a minimal protected-mode environment.
+;;
+
+;;
+;; Copyright (C) 2004-2011 Oracle Corporation
+;;
+;; This file is part of VirtualBox Open Source Edition (OSE), as
+;; available from http://www.virtualbox.org. This file is free software;
+;; you can redistribute it and/or modify it under the terms of the GNU
+;; General Public License (GPL) as published by the Free Software
+;; Foundation, in version 2 as it comes in the "COPYING" file of the
+;; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+;; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;;
+
+;; Caveats: May only be called from the F000 segment (16-bit). Does not
+;; switch stacks. Must be run with disabled interrupts(!), any exceptions
+;; will cause a crash. On return from pmode_enter, DS contains a selector
+;; which can address the entire 4GB address space.
+
+public		pmode_enter
+public		pmode_exit
+public		pmbios_gdt_desc
+public		pmbios_gdt
+
+pmode_enter	proc	near
+
+		push	cs
+		pop 	ds
+		.386p
+		lgdt	fword ptr [pmbios_gdt_desc]
+		mov	eax, cr0
+		or	al, 1
+		mov	cr0, eax
+;		jmp	far ptr 20h:really_enter_pm
+		db	0EAh
+		dw	really_enter_pm
+		dw	20h
+really_enter_pm:
+		mov	ax, 18h
+		mov	ds, ax
+		ret
+
+pmode_enter	endp
+
+
+pmode_exit	proc	near
+
+		mov	eax, cr0
+		and	al, 0FEh
+		mov	cr0, eax
+		.286
+		jmp	far ptr really_exit_pm
+really_exit_pm:
+		ret
+
+pmode_exit	endp
+
+
+
+pmbios_gdt_desc:
+		dw	30h
+		dw	pmbios_gdt
+		dw	000Fh
+
+pmbios_gdt:
+		dw 0, 0, 0, 0
+		dw 0, 0, 0, 0
+		dw 0ffffh, 0, 9b00h, 00cfh	; 32-bit code (0x10)
+		dw 0ffffh, 0, 9300h, 00cfh	; 32-bit data (0x18)
+		dw 0ffffh, 0, 9b0fh, 0000h	; 16-bit code, base=0xf0000
+		dw 0ffffh, 0, 9300h, 0000h	; 16-bit data, base=0x0
Index: /trunk/src/VBox/Devices/PC/BIOS-new/pmsetup.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/pmsetup.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/pmsetup.inc	(revision 38699)
@@ -0,0 +1,53 @@
+;; @file
+;; Initial system setup which needs to run in protected mode.
+;;
+
+;;
+;; Copyright (C) 2004-2011 Oracle Corporation
+;;
+;; This file is part of VirtualBox Open Source Edition (OSE), as
+;; available from http://www.virtualbox.org. This file is free software;
+;; you can redistribute it and/or modify it under the terms of the GNU
+;; General Public License (GPL) as published by the Free Software
+;; Foundation, in version 2 as it comes in the "COPYING" file of the
+;; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+;; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;;
+
+LVT0		equ	0FEE00350h
+LVT1		equ	0FEE00360h
+
+public		pmode_setup
+
+;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
+;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
+
+pmode_setup	proc	near
+
+		.386
+		push	eax
+		push	esi
+		pushf
+		cli			; Interrupts would kill us!
+		call	pmode_enter
+		mov	eax, cr0	; Clear CR0.CD and CR0.NW
+		and	eax, 09FFFFFFFh
+		mov	cr0, eax
+		mov	esi, LVT0	; Program LVT0 to ExtINT and unmask
+		mov	eax, [esi]
+		and	eax, 0FFFE00FFh
+		or	ah,  7
+		mov	[esi], eax
+		mov	esi, LVT1	; Program LVT1 to NMI and unmask
+		mov	eax, [esi]
+		and	eax, 0FFFE00FFh
+		or	ah,  4
+		mov	[esi], eax
+		call	pmode_exit
+		popf
+		pop	esi
+		pop	eax
+		.286
+		ret
+
+pmode_setup	endp
Index: /trunk/src/VBox/Devices/PC/BIOS-new/print.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/print.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/print.c	(revision 38699)
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include <stdarg.h>
+#include "inlines.h"
+#include "biosint.h"
+
+// Debug printf support
+
+/* Redirect INFO output to backdoor logging port. */
+#define PANIC_PORT  0x400
+#define PANIC_PORT2 0x401
+#define INFO_PORT   0x504
+#define DEBUG_PORT  0x403
+
+const char bios_prefix_string[] = "BIOS: ";
+
+void wrch(uint8_t c);
+#pragma aux wrch = "mov ah, 0eh" "int 10h" parm [al] modify exact [ax bx];
+
+void send(uint16_t action, uint8_t c)
+{
+#if BX_DEBUG_SERIAL
+    if (c == '\n')
+        uart_tx_byte(BX_DEBUG_PORT, '\r');
+    uart_tx_byte(BX_DEBUG_PORT, c);
+#endif
+#if BX_VIRTUAL_PORTS
+    if (action & BIOS_PRINTF_DEBUG)
+        outb(DEBUG_PORT, c);
+    if (action & BIOS_PRINTF_INFO)
+        outb(INFO_PORT, c);
+#endif
+    if (action & BIOS_PRINTF_SCREEN) {
+        if (c == '\n')
+            wrch('\r');
+        wrch(c);
+    }
+}
+
+void put_int(uint16_t action, short val, short width, bx_bool neg)
+{
+    short   nval = val / 10;
+    if (nval)
+        put_int(action, nval, width - 1, neg);
+    else {
+        while (--width > 0)
+            send(action, ' ');
+        if (neg)
+            send(action, '-');
+    }
+    send(action, val - (nval * 10) + '0');
+}
+
+void put_uint(uint16_t action, unsigned short val, short width, bx_bool neg)
+{
+    unsigned short nval = val / 10;
+    if (nval)
+        put_uint(action, nval, width - 1, neg);
+    else {
+        while (--width > 0)
+            send(action, ' ');
+        if (neg)
+            send(action, '-');
+    }
+    send(action, val - (nval * 10) + '0');
+}
+
+void put_luint(uint16_t 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(uint16_t action, const char __far *s)
+{
+    uint8_t c;
+
+    while (c = *s) {
+        send(action, c);
+        s++;
+    }
+}
+
+void put_str_near(uint16_t action, const char __near *s)
+{
+    uint8_t c;
+
+    while (c = *s) {
+        send(action, c);
+        s++;
+    }
+}
+
+
+//--------------------------------------------------------------------------
+// bios_printf()
+//   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(uint16_t action, const char *s, ...)
+{
+    uint8_t     c;
+    bx_bool     in_format;
+    int         i;
+    uint16_t    arg, nibble, hibyte, format_width, hexadd;
+    va_list     args; 
+    
+    va_start( args, s );
+    
+    in_format = 0;
+    format_width = 0;
+    
+    if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
+#if BX_VIRTUAL_PORTS
+        outb(PANIC_PORT2, 0x00);
+#endif
+        bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
+    }
+
+    while (c = *s) {
+        if ( c == '%' ) {
+            in_format = 1;
+            format_width = 0;
+        }
+        else if (in_format) {
+            if ( (c>='0') && (c<='9') ) {
+                format_width = (format_width * 10) + (c - '0');
+            }
+            else {
+                arg = va_arg( args, uint16_t );
+                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+hexadd));
+                    }
+                }
+                else if (c == 'u') {
+                    put_uint(action, arg, format_width, 0);
+                }
+                else if (c == 'l') {
+                    s++;
+                    c = *s; /* is it ld,lx,lu? */
+                    hibyte = va_arg( args, uint16_t );
+                    if (c == 'd') {
+                        if (hibyte & 0x8000)
+                            put_luint(action, 0L-(((uint32_t) hibyte << 16) | arg), format_width-1, 1);
+                        else
+                            put_luint(action, ((uint32_t) hibyte << 16) | arg, format_width, 0);
+                    }
+                    else if (c == 'u') {
+                        put_luint(action, ((uint32_t) 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 = ((((uint32_t)hibyte << 16) | arg) >> (4 * i)) & 0x000f;
+                            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
+                        }
+                    }
+                }
+                else if (c == 'd') {
+                    if (arg & 0x8000)
+                        put_int(action, -arg, format_width - 1, 1);
+                    else
+                        put_int(action, arg, format_width, 0);
+                }
+                else if (c == 's') {
+                    put_str(action, (char *)arg);
+                }
+                else if (c == 'S') {
+                    hibyte = arg;
+                    arg = va_arg( args, uint16_t );
+                    put_str(action, hibyte :> (char *)arg);
+                }
+                else if (c == 'c') {
+                    send(action, arg);
+                }
+                else
+                    BX_PANIC("bios_printf: unknown format\n");
+                in_format = 0;
+            }
+        }
+        else {
+            send(action, c);
+        }
+        ++s;
+    }
+    va_end( args );
+    if (action & BIOS_PRINTF_HALT) {
+        // freeze in a busy loop.
+        int_disable();
+        halt_forever();
+    }
+}
+
+// End of printf support
Index: /trunk/src/VBox/Devices/PC/BIOS-new/ps2mouse.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/ps2mouse.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/ps2mouse.c	(revision 38699)
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "biosint.h"
+#include "inlines.h"
+
+
+#if DEBUG_INT15_MS
+#  define BX_DEBUG_INT15_MS(...)    BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT15_MS(...)
+#endif
+
+#if DEBUG_INT74
+#  define BX_DEBUG_INT74(...)       BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT74(...)
+#endif
+
+#if BX_USE_PS2_MOUSE
+
+static  const char  panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
+
+uint8_t send_to_mouse_ctrl(uint8_t sendbyte)
+{
+    // wait for chance to write to ctrl
+    if ( inb(0x64) & 0x02 )
+        BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
+    outb(0x64, 0xD4);
+    outb(0x60, sendbyte);
+    return(0);
+}
+
+
+uint8_t get_mouse_data(uint8_t __far *data)
+{
+    uint8_t     response;
+
+    //@todo: timeout?
+    while ((inb(0x64) & 0x21) != 0x21)
+        ;
+    
+    response = inb(0x60);
+    *data = response;
+    return(0);
+}
+
+void set_kbd_command_byte(uint8_t command_byte)
+{
+    if (inb(0x64) & 0x02)
+        BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
+    
+    outb(0x64, 0x60); // write command byte
+    outb(0x60, command_byte);
+}
+
+
+void BIOSCALL int74_function(volatile uint16_t make_farcall, volatile uint16_t Z,
+                             volatile uint16_t Y, volatile uint16_t X, volatile uint16_t status)
+{
+    uint16_t    ebda_seg=read_word(0x0040,0x000E);
+    uint8_t     in_byte, index, package_count;
+    uint8_t     mouse_flags_1, mouse_flags_2;
+    
+    BX_DEBUG_INT74("entering int74_function\n");
+    make_farcall = 0;
+    
+    in_byte = inb(0x64);
+    if ( (in_byte & 0x21) != 0x21 ) {
+        return;
+    }
+    in_byte = inb(0x60);
+    BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
+    
+    mouse_flags_1 = read_byte(ebda_seg, 0x0026);
+    mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+    
+    if ( (mouse_flags_2 & 0x80) != 0x80 ) {
+        return;
+    }
+    
+    package_count = mouse_flags_2 & 0x07;
+    index = mouse_flags_1 & 0x07;
+    write_byte(ebda_seg, 0x28 + index, in_byte);
+    
+    if ( index >= package_count ) {
+        BX_DEBUG_INT74("int74_function: make_farcall=1\n");
+        status = read_byte(ebda_seg, 0x0028 + 0);
+        X      = read_byte(ebda_seg, 0x0028 + 1);
+        Y      = read_byte(ebda_seg, 0x0028 + 2);
+        Z      = 0;
+        mouse_flags_1 = 0;
+        // check if far call handler installed
+        if (mouse_flags_2 & 0x80)
+            make_farcall = 1;
+    }
+    else {
+        mouse_flags_1++;
+    }
+    write_byte(ebda_seg, 0x0026, mouse_flags_1);
+}
+
+void BIOSCALL int15_function_mouse(pusha_regs_t regs, uint16_t ES, uint16_t DS, volatile uint16_t FLAGS)
+{
+    uint16_t    ebda_seg=read_word(0x0040,0x000E);
+    uint8_t     mouse_flags_1, mouse_flags_2;
+    uint16_t    mouse_driver_seg;
+    uint16_t    mouse_driver_offset;
+    uint8_t     mouse_cmd;
+    uint8_t     ret, mouse_data1, mouse_data2, mouse_data3;
+
+    BX_DEBUG_INT15_MS("int15 AX=%04x\n",regs.u.r16.ax);
+
+    // Return Codes status in AH
+    // =========================
+    // 00: success
+    // 01: invalid subfunction (AL > 7)
+    // 02: invalid input value (out of allowable range)
+    // 03: interface error
+    // 04: resend command received from mouse controller,
+    //     device driver should attempt command again
+    // 05: cannot enable mouse, since no far call has been installed
+    // 80/86: mouse service not implemented
+    
+    if (regs.u.r8.al > 7) {
+        BX_DEBUG_INT15_MS("unsupported subfn\n");
+        // invalid function
+        SET_CF();
+        regs.u.r8.ah = 1;
+        return;
+    }
+    
+    // Valid subfn; disable AUX input and IRQ12, assume no error
+    set_kbd_command_byte(0x65);
+    CLEAR_CF();
+    regs.u.r8.ah = 0;
+    
+    switch (regs.u.r8.al) {
+    case 0: // Disable/Enable Mouse
+        BX_DEBUG_INT15_MS("case 0: ");
+        if (regs.u.r8.bh > 1) {
+            BX_DEBUG_INT15_MS("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
+            // invalid subfunction
+            SET_CF();
+            regs.u.r8.ah = 1;
+            break;
+        }
+        mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+        if ( (mouse_flags_2 & 0x80) == 0 ) {
+            BX_DEBUG_INT15_MS("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
+            SET_CF();
+            regs.u.r8.ah = 5; // no far call installed
+            break;
+        }
+        if (regs.u.r8.bh == 0) {
+            BX_DEBUG_INT15_MS("Disable Mouse\n");
+            mouse_cmd = 0xF5;   // disable mouse command
+        } else {
+            BX_DEBUG_INT15_MS("Enable Mouse\n");
+            mouse_cmd = 0xF4;   // enable mouse command
+        }
+        
+        ret = send_to_mouse_ctrl(mouse_cmd);  // disable mouse command
+        if (ret == 0) {
+            ret = get_mouse_data(&mouse_data1);
+            if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
+                // success
+                break;
+            }
+        }
+        
+        // interface error
+        SET_CF();
+        regs.u.r8.ah = 3;
+        break;
+    
+    case 5: // Initialize Mouse
+        // Valid package sizes are 1 to 8
+        if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
+            SET_CF();
+            regs.u.r8.ah = 2; // invalid input
+            break;
+        }
+        mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+        mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
+        write_byte(ebda_seg, 0x0027, mouse_flags_2);
+        // fall through!
+    
+    case 1: // Reset Mouse
+        BX_DEBUG_INT15_MS("case 1 or 5:\n");
+        // clear current package byte index
+        mouse_flags_1 = read_byte(ebda_seg, 0x0026);
+        mouse_flags_1 = mouse_flags_1 & 0xf8;
+        write_byte(ebda_seg, 0x0026, mouse_flags_1);
+        ret = send_to_mouse_ctrl(0xFF); // reset mouse command
+        if (ret == 0) {
+            ret = get_mouse_data(&mouse_data3);
+            // if no mouse attached, it will return RESEND
+            if (mouse_data3 == 0xfe) {
+                SET_CF();
+                regs.u.r8.ah = 4; // resend
+                break;
+            }
+            if (mouse_data3 != 0xfa)
+                BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
+            if ( ret == 0 ) {
+                ret = get_mouse_data(&mouse_data1);
+                if ( ret == 0 ) {
+                    ret = get_mouse_data(&mouse_data2);
+                    if ( ret == 0 ) {
+                        // success
+                        regs.u.r8.bl = mouse_data1;
+                        regs.u.r8.bh = mouse_data2;
+                        break;
+                    }
+                }
+            }
+        }
+        
+        // interface error
+        SET_CF();
+        regs.u.r8.ah = 3;
+        break;
+    
+    case 2: // Set Sample Rate
+        BX_DEBUG_INT15_MS("case 2:\n");
+        switch (regs.u.r8.bh) {
+        case 0: mouse_data1 = 10; break; //  10 reports/sec
+        case 1: mouse_data1 = 20; break; //  20 reports/sec
+        case 2: mouse_data1 = 40; break; //  40 reports/sec
+        case 3: mouse_data1 = 60; break; //  60 reports/sec
+        case 4: mouse_data1 = 80; break; //  80 reports/sec
+        case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
+        case 6: mouse_data1 = 200; break; // 200 reports/sec
+        default: mouse_data1 = 0;
+        }
+        if (mouse_data1 > 0) {
+            ret = send_to_mouse_ctrl(0xF3); // set sample rate command
+            if (ret == 0) {
+                ret = get_mouse_data(&mouse_data2);
+                ret = send_to_mouse_ctrl(mouse_data1);
+                ret = get_mouse_data(&mouse_data2);
+                // success
+            } else {
+                // interface error
+                SET_CF();
+                regs.u.r8.ah = 3;
+            }
+        } else {
+            // invalid input
+            SET_CF();
+            regs.u.r8.ah = 2;
+        }
+        break;
+    
+    case 3: // Set Resolution
+        BX_DEBUG_INT15_MS("case 3:\n");
+        // BX:
+        //      0 =  25 dpi, 1 count  per millimeter
+        //      1 =  50 dpi, 2 counts per millimeter
+        //      2 = 100 dpi, 4 counts per millimeter
+        //      3 = 200 dpi, 8 counts per millimeter
+        if (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);
+                // success
+            } else {
+                // interface error
+                SET_CF();
+                regs.u.r8.ah = 3;
+            }
+        } else {
+            // invalid input
+            SET_CF();
+            regs.u.r8.ah = 2;
+        }
+        break;
+    
+    case 4: // Get Device ID
+        BX_DEBUG_INT15_MS("case 4:\n");
+        ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
+        if (ret == 0) {
+            ret = get_mouse_data(&mouse_data1);
+            ret = get_mouse_data(&mouse_data2);
+            regs.u.r8.bh = mouse_data2;
+            // success
+        } else {
+            // interface error
+            SET_CF();
+            regs.u.r8.ah = 3;
+        }
+        break;
+    
+    case 6: // Return Status & Set Scaling Factor...
+        BX_DEBUG_INT15_MS("case 6:\n");
+        switch (regs.u.r8.bh) {
+        case 0: // Return Status
+            ret = send_to_mouse_ctrl(0xE9); // get mouse info 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);
+                if (ret == 0) {
+                    ret = get_mouse_data(&mouse_data1);
+                    if ( ret == 0 ) {
+                        ret = get_mouse_data(&mouse_data2);
+                        if ( ret == 0 ) {
+                            ret = get_mouse_data(&mouse_data3);
+                            if ( ret == 0 ) {
+                                regs.u.r8.bl = mouse_data1;
+                                regs.u.r8.cl = mouse_data2;
+                                regs.u.r8.dl = mouse_data3;
+                                // success
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+            
+            // interface error
+            SET_CF();
+            regs.u.r8.ah = 3;
+            break;
+        
+        case 1: // Set Scaling Factor to 1:1
+        case 2: // Set Scaling Factor to 2:1
+            if (regs.u.r8.bh == 1) {
+                ret = send_to_mouse_ctrl(0xE6);
+            } else {
+                ret = send_to_mouse_ctrl(0xE7);
+            }
+            if (ret == 0) {
+                get_mouse_data(&mouse_data1);
+                ret = (mouse_data1 != 0xFA);
+            }
+            if (ret != 0) {
+                // interface error
+                SET_CF();
+                regs.u.r8.ah = 3;
+            }
+            break;
+        
+        default:
+            BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
+            // invalid subfunction
+            SET_CF();
+            regs.u.r8.ah = 1;
+        }
+        break;
+    
+    case 7: // Set Mouse Handler Address
+        BX_DEBUG_INT15_MS("case 7:\n");
+        mouse_driver_seg = ES;
+        mouse_driver_offset = regs.u.r16.bx;
+        write_word(ebda_seg, 0x0022, mouse_driver_offset);
+        write_word(ebda_seg, 0x0024, mouse_driver_seg);
+        mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+        if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
+            /* remove handler */
+            if ( (mouse_flags_2 & 0x80) != 0 ) {
+                mouse_flags_2 &= ~0x80;
+            }
+        }
+        else {
+            /* install handler */
+            mouse_flags_2 |= 0x80;
+        }
+        write_byte(ebda_seg, 0x0027, mouse_flags_2);
+        break;
+    
+    default:
+        BX_PANIC("INT 15h C2 default case entered\n");
+        // invalid subfunction
+        SET_CF();
+        regs.u.r8.ah = 1;
+    }
+    BX_DEBUG_INT15_MS("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
+    // Re-enable AUX input and IRQ12
+    set_kbd_command_byte(0x47);
+}
+#endif // BX_USE_PS2_MOUSE
Index: /trunk/src/VBox/Devices/PC/BIOS-new/scsi.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/scsi.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/scsi.c	(revision 38699)
@@ -0,0 +1,453 @@
+/* $Id$ */
+/** @file
+ * SCSI host adapter driver to boot from SCSI disks
+ */
+
+/*
+ * Copyright (C) 2004-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "biosint.h"
+#include "inlines.h"
+#include "ebda.h"
+#include "ata.h"
+
+
+/* The I/O port of the BusLogic SCSI adapter. */
+#define BUSLOGIC_ISA_IO_PORT 0x330
+/* The I/O port of the LsiLogic SCSI adapter. */
+#define LSILOGIC_ISA_IO_PORT 0x340
+/* The I/O port of the LsiLogic SAS adapter. */
+#define LSILOGIC_SAS_ISA_IO_PORT 0x350
+
+#define VBSCSI_REGISTER_STATUS   0
+#define VBSCSI_REGISTER_COMMAND  0
+#define VBSCSI_REGISTER_DATA_IN  1
+#define VBSCSI_REGISTER_IDENTIFY 2
+#define VBSCSI_REGISTER_RESET    3
+
+#define VBSCSI_MAX_DEVICES 16 /* Maximum number of devices a SCSI device can have. */
+
+/* Command opcodes. */
+#define SCSI_INQUIRY       0x12
+#define SCSI_READ_CAPACITY 0x25
+#define SCSI_READ_10       0x28
+#define SCSI_WRITE_10      0x2a
+
+/* Data transfer direction. */
+#define SCSI_TXDIR_FROM_DEVICE 0
+#define SCSI_TXDIR_TO_DEVICE   1
+
+#define VBSCSI_BUSY (1 << 0)
+
+//#define VBOX_SCSI_DEBUG 1 /* temporary */
+
+#ifdef VBOX_SCSI_DEBUG
+# define VBSCSI_DEBUG(...)    BX_INFO(__VA_ARGS__)
+#else
+# define VBSCSI_DEBUG(...)
+#endif
+
+int scsi_cmd_data_in(uint16_t io_base, uint8_t device_id, uint8_t __far *aCDB,
+                     uint8_t cbCDB, uint8_t __far *buffer, uint16_t cbBuffer)
+{
+    /* Check that the adapter is ready. */
+    uint8_t     status;
+    uint16_t    i;
+
+    do
+    {
+        status = inb(io_base+VBSCSI_REGISTER_STATUS);
+    } while (status & VBSCSI_BUSY);
+
+    /* Write target ID. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, device_id);
+    /* Write transfer direction. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, SCSI_TXDIR_FROM_DEVICE);
+    /* Write the CDB size. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, cbCDB);
+    /* Write buffer size. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, cbBuffer);
+    outb(io_base+VBSCSI_REGISTER_COMMAND, (cbBuffer >> 8));
+    /* Write the CDB. */
+    for (i = 0; i < cbCDB; i++)
+        outb(io_base+VBSCSI_REGISTER_COMMAND, aCDB[i]);
+
+    /* Now wait for the command to complete. */
+    do
+    {
+        status = inb(io_base+VBSCSI_REGISTER_STATUS);
+    } while (status & VBSCSI_BUSY);
+
+    /* Get the read data. */
+    rep_insb(buffer, cbBuffer, io_base + VBSCSI_REGISTER_DATA_IN);
+
+    return 0;
+}
+
+int scsi_cmd_data_out(uint16_t io_base, uint8_t device_id, uint8_t __far *aCDB,
+                      uint8_t cbCDB, uint8_t __far *buffer, uint16_t cbBuffer)
+{
+    /* Check that the adapter is ready. */
+    uint8_t     status;
+    uint16_t    i;
+
+    do
+    {
+        status = inb(io_base+VBSCSI_REGISTER_STATUS);
+    } while (status & VBSCSI_BUSY);
+
+    /* Write target ID. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, device_id);
+    /* Write transfer direction. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, SCSI_TXDIR_TO_DEVICE);
+    /* Write the CDB size. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, cbCDB);
+    /* Write buffer size. */
+    outb(io_base+VBSCSI_REGISTER_COMMAND, cbBuffer);
+    outb(io_base+VBSCSI_REGISTER_COMMAND, (cbBuffer >> 8));
+    /* Write the CDB. */
+    for (i = 0; i < cbCDB; i++)
+        outb(io_base+VBSCSI_REGISTER_COMMAND, aCDB[i]);
+
+    /* Write data to I/O port. */
+    rep_outsb(buffer, cbBuffer, io_base+VBSCSI_REGISTER_DATA_IN);
+
+    /* Now wait for the command to complete. */
+    do
+    {
+        status = inb(io_base+VBSCSI_REGISTER_STATUS);
+    } while (status & VBSCSI_BUSY);
+
+    return 0;
+}
+
+
+/**
+ * Read sectors from an attached scsi device.
+ *
+ * @returns status code.
+ * @param   device_id   Id of the SCSI device to read from.
+ * @param   count       The number of sectors to read.
+ * @param   lba         The start sector to read from.
+ * @param   buffer      A far pointer to the buffer.
+ */
+int scsi_read_sectors(uint8_t device_id, uint16_t count, uint32_t lba, void __far *buffer)
+{
+    uint8_t             rc;
+    uint8_t             aCDB[10];
+    uint16_t            io_base, ebda_seg;
+    uint8_t             target_id;
+    ebda_data_t __far   *ebda_data;
+
+    if (device_id > BX_MAX_SCSI_DEVICES)
+        BX_PANIC("scsi_read_sectors: device_id out of range %d\n", device_id);
+
+    ebda_seg  = read_word(0x0040, 0x000E);
+    ebda_data = MK_FP(ebda_seg, 0);
+
+    // Reset count of transferred data
+    ebda_data->ata.trsfsectors = 0;
+    ebda_data->ata.trsfbytes   = 0;
+
+    /* Prepare CDB */
+    //@todo: make CDB a struct, this is stupid
+    aCDB[0] = SCSI_READ_10;
+    aCDB[1] = 0;
+    aCDB[2] = (uint8_t)(lba >> 24);
+    aCDB[3] = (uint8_t)(lba >> 16);
+    aCDB[4] = (uint8_t)(lba >>  8);
+    aCDB[5] = (uint8_t)(lba);
+    aCDB[6] = 0;
+    aCDB[7] = (uint8_t)(count >> 8);
+    aCDB[8] = (uint8_t)(count);
+    aCDB[9] = 0;
+
+    io_base   = ebda_data->scsi.devices[device_id].io_base;
+    target_id = ebda_data->scsi.devices[device_id].target_id;
+
+    rc = scsi_cmd_data_in(io_base, target_id, aCDB, 10, buffer, (count * 512));
+
+    if (!rc)
+    {
+        ebda_data->ata.trsfsectors = count;
+        ebda_data->ata.trsfbytes   = count * 512;
+    }
+
+    return rc;
+}
+
+/**
+ * Write sectors to an attached scsi device.
+ *
+ * @returns status code.
+ * @param   device_id   Id of the SCSI device to write to.
+ * @param   count       The number of sectors to write.
+ * @param   lba         The start sector to write to.
+ * @param   buffer      A far pointer to the buffer.
+ */
+int scsi_write_sectors(uint8_t device_id, uint16_t count, uint32_t lba, void __far *buffer)
+{
+    uint8_t             rc;
+    uint8_t             aCDB[10];
+    uint16_t            io_base, ebda_seg;
+    uint8_t             target_id;
+    ebda_data_t __far   *ebda_data;
+
+    if (device_id > BX_MAX_SCSI_DEVICES)
+        BX_PANIC("scsi_write_sectors: device_id out of range %d\n", device_id);
+
+    ebda_seg = read_word(0x0040, 0x000E);
+    ebda_data = MK_FP(ebda_seg, 0);
+
+    // Reset count of transferred data
+    ebda_data->ata.trsfsectors = 0;
+    ebda_data->ata.trsfbytes   = 0;
+
+    /* Prepare CDB */
+    //@todo: make CDB a struct, this is stupid
+    aCDB[0] = SCSI_WRITE_10;
+    aCDB[1] = 0;
+    aCDB[2] = (uint8_t)(lba >> 24);
+    aCDB[3] = (uint8_t)(lba >> 16);
+    aCDB[4] = (uint8_t)(lba >>  8);
+    aCDB[5] = (uint8_t)(lba);
+    aCDB[6] = 0;
+    aCDB[7] = (uint8_t)(count >> 8);
+    aCDB[8] = (uint8_t)(count);
+    aCDB[9] = 0;
+
+    io_base   = ebda_data->scsi.devices[device_id].io_base;
+    target_id = ebda_data->scsi.devices[device_id].target_id;
+
+    rc = scsi_cmd_data_out(io_base, target_id, aCDB, 10, buffer, (count * 512));
+
+    if (!rc)
+    {
+        ebda_data->ata.trsfsectors = count;
+        ebda_data->ata.trsfbytes   = (count * 512);
+    }
+
+    return rc;
+}
+
+/**
+ * Enumerate attached devices.
+ *
+ * @returns nothing.
+ * @param   io_base    The I/O base port of the controller.
+ */
+void scsi_enumerate_attached_devices(uint16_t io_base)
+{
+    int                 i;
+    uint8_t             buffer[0x0200];
+    uint16_t            ebda_seg;
+    ebda_data_t __far   *ebda_data;
+
+    ebda_seg  = read_word(0x0040, 0x000E);
+    ebda_data = MK_FP(ebda_seg, 0);
+
+    /* Go through target devices. */
+    for (i = 0; i < VBSCSI_MAX_DEVICES; i++)
+    {
+        uint8_t     rc;
+        uint8_t     aCDB[10];
+
+        aCDB[0] = SCSI_INQUIRY;
+        aCDB[1] = 0;
+        aCDB[2] = 0;
+        aCDB[3] = 0;
+        aCDB[4] = 5; /* Allocation length. */
+        aCDB[5] = 0;
+
+        rc = scsi_cmd_data_in(io_base, i, aCDB, 6, buffer, 5);
+        if (rc != 0)
+            BX_PANIC("scsi_enumerate_attached_devices: SCSI_INQUIRY failed\n");
+
+        /* Check if there is a disk attached. */
+        if (   ((buffer[0] & 0xe0) == 0)
+            && ((buffer[0] & 0x1f) == 0x00))
+        {
+            VBSCSI_DEBUG("scsi_enumerate_attached_devices: Disk detected at %d\n", i);
+
+            /* We add the disk only if the maximum is not reached yet. */
+            if (ebda_data->scsi.hdcount < BX_MAX_SCSI_DEVICES)
+            {
+                uint32_t    sectors, sector_size, cylinders;
+                uint16_t    heads, sectors_per_track;
+                uint8_t     hdcount, hdcount_scsi;
+
+                /* Issue a read capacity command now. */
+                _fmemset(aCDB, 0, sizeof(aCDB));
+                aCDB[0] = SCSI_READ_CAPACITY;
+
+                rc = scsi_cmd_data_in(io_base, i, aCDB, 10, buffer, 8);
+                if (rc != 0)
+                    BX_PANIC("scsi_enumerate_attached_devices: SCSI_READ_CAPACITY failed\n");
+
+                /* Build sector number and size from the buffer. */
+                //@todo: byte swapping for dword sized items should be farmed out...
+                sectors =   ((uint32_t)buffer[0] << 24)
+                          | ((uint32_t)buffer[1] << 16)
+                          | ((uint32_t)buffer[2] << 8)
+                          | ((uint32_t)buffer[3]);
+
+                sector_size =   ((uint32_t)buffer[4] << 24)
+                              | ((uint32_t)buffer[5] << 16)
+                              | ((uint32_t)buffer[6] << 8)
+                              | ((uint32_t)buffer[7]);
+
+                /* We only support the disk if sector size is 512 bytes. */
+                if (sector_size != 512)
+                {
+                    /* Leave a log entry. */
+                    BX_INFO("Disk %d has an unsupported sector size of %u\n", i, sector_size);
+                    continue;
+                }
+
+                /* We need to calculate the geometry for the disk. From 
+                 * the BusLogic driver in the Linux kernel. 
+                 */
+                if (sectors >= 4 * 1024 * 1024)
+                {
+                    heads = 255;
+                    sectors_per_track = 63;
+                }
+                else if (sectors >= 2 * 1024 * 1024)
+                {
+                    heads = 128;
+                    sectors_per_track = 32;
+                }
+                else
+                {
+                    heads = 64;
+                    sectors_per_track = 32;
+                }
+                cylinders = (uint32_t)(sectors / (heads * sectors_per_track));
+                hdcount_scsi = ebda_data->scsi.hdcount;
+
+                ebda_data->scsi.devices[hdcount_scsi].io_base   = io_base;
+                ebda_data->scsi.devices[hdcount_scsi].target_id = i;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.type        = ATA_TYPE_SCSI;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.device      = ATA_DEVICE_HD;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.removable   = 0;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.lock        = 0;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.mode        = ATA_MODE_PIO16;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.blksize     = sector_size;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.translation = ATA_TRANSLATION_LBA;
+
+                /* Write lchs values. */
+                ebda_data->scsi.devices[hdcount_scsi].device_info.lchs.heads = heads;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.lchs.spt   = sectors_per_track;
+                if (cylinders > 1024)
+                    ebda_data->scsi.devices[hdcount_scsi].device_info.lchs.cylinders = 1024;
+                else
+                    ebda_data->scsi.devices[hdcount_scsi].device_info.lchs.cylinders = (uint16_t)cylinders;
+
+                /* Write pchs values. */
+                ebda_data->scsi.devices[hdcount_scsi].device_info.pchs.heads = heads;
+                ebda_data->scsi.devices[hdcount_scsi].device_info.pchs.spt   = sectors_per_track;
+                if (cylinders > 1024)
+                    ebda_data->scsi.devices[hdcount_scsi].device_info.pchs.cylinders = 1024;
+                else
+                    ebda_data->scsi.devices[hdcount_scsi].device_info.pchs.cylinders = (uint16_t)cylinders;
+
+                ebda_data->scsi.devices[hdcount_scsi].device_info.sectors = sectors;
+
+                /* Store the id of the disk in the ata hdidmap. */
+                hdcount = ebda_data->ata.hdcount;
+                ebda_data->ata.hdidmap[hdcount] = hdcount_scsi + BX_MAX_ATA_DEVICES;
+                hdcount++;
+                ebda_data->ata.hdcount = hdcount;
+
+                /* Update hdcount in the BDA. */
+                hdcount = read_byte(0x40, 0x75);
+                hdcount++;
+                write_byte(0x40, 0x75, hdcount);
+
+                hdcount_scsi++;
+                ebda_data->scsi.hdcount = hdcount_scsi;
+            }
+            else
+            {
+                /* We reached the maximum of SCSI disks we can boot from. We can quit detecting. */
+                break;
+            }
+        }
+        else
+            VBSCSI_DEBUG("scsi_enumerate_attached_devices: No disk detected at %d\n", i);
+    }
+}
+
+/**
+ * Init the SCSI driver and detect attached disks.
+ */
+void BIOSCALL scsi_init(void)
+{
+    uint8_t     identifier;
+    uint16_t    ebda_seg;
+
+
+    ebda_seg = read_word(0x0040, 0x000E);
+    write_byte(ebda_seg, (uint16_t)&EbdaData->scsi.hdcount, 0);
+
+    identifier = 0;
+
+    /* Detect BusLogic adapter. */
+    outb(BUSLOGIC_ISA_IO_PORT+VBSCSI_REGISTER_IDENTIFY, 0x55);
+    identifier = inb(BUSLOGIC_ISA_IO_PORT+VBSCSI_REGISTER_IDENTIFY);
+
+    if (identifier == 0x55)
+    {
+        /* Detected - Enumerate attached devices. */
+        VBSCSI_DEBUG("scsi_init: BusLogic SCSI adapter detected\n");
+        outb(BUSLOGIC_ISA_IO_PORT+VBSCSI_REGISTER_RESET, 0);
+        scsi_enumerate_attached_devices(BUSLOGIC_ISA_IO_PORT);
+    }
+    else
+    {
+        VBSCSI_DEBUG("scsi_init: BusLogic SCSI adapter not detected\n");
+    }
+
+    /* Detect LsiLogic adapter. */
+    outb(LSILOGIC_ISA_IO_PORT+VBSCSI_REGISTER_IDENTIFY, 0x55);
+    identifier = inb(LSILOGIC_ISA_IO_PORT+VBSCSI_REGISTER_IDENTIFY);
+
+    if (identifier == 0x55)
+    {
+        /* Detected - Enumerate attached devices. */
+        VBSCSI_DEBUG("scsi_init: LSI Logic SCSI adapter detected\n");
+        outb(LSILOGIC_ISA_IO_PORT+VBSCSI_REGISTER_RESET, 0);
+        scsi_enumerate_attached_devices(LSILOGIC_ISA_IO_PORT);
+    }
+    else
+    {
+        VBSCSI_DEBUG("scsi_init: LSI Logic SCSI adapter not detected\n");
+    }
+
+    /* Detect LsiLogic SAS adapter. */
+    outb(LSILOGIC_SAS_ISA_IO_PORT+VBSCSI_REGISTER_IDENTIFY, 0x55);
+    identifier = inb(LSILOGIC_SAS_ISA_IO_PORT+VBSCSI_REGISTER_IDENTIFY);
+
+    if (identifier == 0x55)
+    {
+        /* Detected - Enumerate attached devices. */
+        VBSCSI_DEBUG("scsi_init: LSI Logic SAS adapter detected\n");
+        outb(LSILOGIC_SAS_ISA_IO_PORT+VBSCSI_REGISTER_RESET, 0);
+        scsi_enumerate_attached_devices(LSILOGIC_SAS_ISA_IO_PORT);
+    }
+    else
+    {
+        VBSCSI_DEBUG("scsi_init: LSI Logic SAS adapter not detected\n");
+    }
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/serial.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/serial.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/serial.c	(revision 38699)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "inlines.h"
+#include "biosint.h"
+
+void BIOSCALL int14_function(pusha_regs_t regs, uint16_t es, uint16_t ds, iret_addr_t iret_addr)
+{
+    uint16_t    addr, timer, val16;
+    uint8_t     timeout;
+
+    int_enable();
+    
+    addr = read_word(0x0040, (regs.u.r16.dx << 1));
+    timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
+    if ((regs.u.r16.dx < 4) && (addr > 0)) {
+        switch (regs.u.r8.ah) {
+        case 0:
+            outb(addr+3, inb(addr+3) | 0x80);
+            if (regs.u.r8.al & 0xE0 == 0) {
+                outb(addr, 0x17);
+                outb(addr+1, 0x04);
+            } else {
+                val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
+                outb(addr, val16 & 0xFF);
+                outb(addr+1, val16 >> 8);
+            }
+            outb(addr+3, regs.u.r8.al & 0x1F);
+            regs.u.r8.ah = inb(addr+5);
+            regs.u.r8.al = inb(addr+6);
+            ClearCF(iret_addr.flags);
+            break;
+        case 1:
+            timer = read_word(0x0040, 0x006C);
+            while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
+                val16 = read_word(0x0040, 0x006C);
+                if (val16 != timer) {
+                    timer = val16;
+                    timeout--;
+                }
+            }
+            if (timeout) outb(addr, regs.u.r8.al);
+            regs.u.r8.ah = inb(addr+5);
+            if (!timeout) regs.u.r8.ah |= 0x80;
+            ClearCF(iret_addr.flags);
+            break;
+        case 2:
+            timer = read_word(0x0040, 0x006C);
+            while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
+                val16 = read_word(0x0040, 0x006C);
+                if (val16 != timer) {
+                    timer = val16;
+                    timeout--;
+                }
+            }
+            if (timeout) {
+                regs.u.r8.ah = 0;
+                regs.u.r8.al = inb(addr);
+            } else {
+                regs.u.r8.ah = inb(addr+5);
+            }
+            ClearCF(iret_addr.flags);
+            break;
+        case 3:
+            regs.u.r8.ah = inb(addr+5);
+            regs.u.r8.al = inb(addr+6);
+            ClearCF(iret_addr.flags);
+            break;
+        default:
+            SetCF(iret_addr.flags); // Unsupported
+        }
+    } else {
+        SetCF(iret_addr.flags); // Unsupported
+    }
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/smidmi.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/smidmi.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/smidmi.inc	(revision 38699)
@@ -0,0 +1,62 @@
+;;
+;; Copyright (C) 2006-2011 Oracle Corporation
+;;
+;; This file is part of VirtualBox Open Source Edition (OSE), as
+;; available from http://www.virtualbox.org. This file is free software;
+;; you can redistribute it and/or modify it under the terms of the GNU
+;; General Public License (GPL) as published by the Free Software
+;; Foundation, in version 2 as it comes in the "COPYING" file of the
+;; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+;; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;; --------------------------------------------------------------------
+;;
+;; This code is based on:
+;;
+;;  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+;;
+;;  Copyright (C) 2002  MandrakeSoft S.A.
+;;
+;;    MandrakeSoft S.A.
+;;    43, rue d'Aboukir
+;;    75002 Paris - France
+;;    http://www.linux-mandrake.com/
+;;    http://www.mandrakesoft.com/
+;;
+;;  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
+;;
+;;
+
+include vbdmismi.inc
+
+; org 0xff30
+align 16
+		;; The SMBIOS header
+		db	'_SM_'		; signature
+		db	0		; checksum (set by biossums)
+		db	01Fh		; EPS length, defined by standard
+		db	VBOX_SMBIOS_MAJOR_VER	; SMBIOS major version
+		db	VBOX_SMBIOS_MINOR_VER	; SMBIOS minor version
+		dw	VBOX_SMBIOS_MAXSS	; Maximum structure size
+		db	0		; Entry point revision
+		db	0, 0, 0, 0, 0	; 16 bytes total
+	
+		;; The DMI header
+		db	'_DMI_'		; signature
+		db	0		; checksum (set by biossums)
+		dw	VBOX_DMI_TABLE_SIZE	; DMI tables length
+		dd	VBOX_DMI_TABLE_BASE	; DMI tables base
+		dw	VBOX_DMI_TABLE_ENTR	; DMI tables entries
+		db	VBOX_DMI_TABLE_VER	; DMI version
+		db	0		; Just for alignment (16 bytes total)
Index: /trunk/src/VBox/Devices/PC/BIOS-new/system.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/system.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/system.c	(revision 38699)
@@ -0,0 +1,799 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "biosint.h"
+#include "inlines.h"
+#include "ebda.h"
+
+#if DEBUG_INT15
+#  define BX_DEBUG_INT15(...) BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT15(...)
+#endif
+
+
+#define UNSUPPORTED_FUNCTION    0x86    /* Specific to INT 15h. */
+
+#define BIOS_CONFIG_TABLE       0xe6f5  /* TODO: configurable? put elsewhere? */
+
+#define ACPI_DATA_SIZE    0x00010000L   /* TODO: configurable? put elsewhere? */
+
+#define BX_CPU                  3
+
+extern  int pmode_IDT;
+extern  int rmode_IDT;
+
+uint16_t read_ss(void);
+#pragma aux read_ss = "mov ax, ss" modify exact [ax] nomemory;
+
+void pm_stack_save(uint16_t cx, uint16_t es, uint16_t si);
+#pragma aux pm_stack_save =     \
+    ".386"                      \
+    "push   ds"                 \
+    "push   eax"                \
+    "xor    eax, eax"           \
+    "mov    ds, ax"             \
+    "mov    ds:[467h], sp"      \
+    "mov    ds:[469h], ss"      \
+    parm [cx] [es] [si] modify nomemory;
+
+/* Uses position independent code... because it was too hard to figure
+ * out how to code the far call in inline assembler.
+ */
+void pm_enter(void);
+#pragma aux pm_enter =              \
+    ".386p"                         \
+    "call   pentry"                 \
+    "pentry:"                       \
+    "pop    di"                     \
+    "add    di, 1Bh"                \
+    "push   20h"                    \
+    "push   di"                     \
+    "lgdt   fword ptr es:[si+8]"    \
+    "lidt   fword ptr cs:pmode_IDT" \
+    "mov    eax, cr0"               \
+    "or     al, 1"                  \
+    "mov    cr0, eax"               \
+    "retf"                          \
+    "pm_pm:"                        \
+    "mov    ax, 28h"                \
+    "mov    ss, ax"                 \
+    "mov    ax, 10h"                \
+    "mov    ds, ax"                 \
+    "mov    ax, 18h"                \
+    "mov    es, ax"                 \
+    modify nomemory;
+
+void pm_copy(void);
+#pragma aux pm_copy =               \
+    "xor    si, si"                 \
+    "xor    di, di"                 \
+    "cld"                           \
+    "rep    movsw"                  \
+    modify nomemory;
+
+/* Restore segment limits to real mode compatible values and
+ * return to real mode.
+ */
+void pm_exit(void);
+#pragma aux pm_exit =               \
+    ".386p"                         \
+    "call   pexit"                  \
+    "pexit:"                        \
+    "pop    ax"                     \
+    "push   0F000h"                 \
+    "add    ax, 18h"                \
+    "push   ax"                     \
+    "mov    ax, 28h"                \
+    "mov    ds, ax"                 \
+    "mov    es, ax"                 \
+    "mov    eax, cr0"               \
+    "and    al, 0FEh"               \
+    "mov    cr0, eax"               \
+    "retf"                          \
+    "real_mode:"                    \
+    "lidt   fword ptr cs:rmode_IDT" \
+    modify nomemory;
+
+void pm_stack_restore(void);
+#pragma aux pm_stack_restore =  \
+    ".386"                      \
+    "xor    ax, ax"             \
+    "mov    ds, ax"             \
+    "lss    sp, ds:[467h]"      \
+    "pop    eax"                \
+    "pop    ds"                 \
+    modify nomemory;
+
+/* The pm_switch has a few crucial differences from pm_enter, hence
+ * it is replicated here. Uses LMSW to avoid trashing high word of eax.
+ */
+void pm_switch(uint16_t reg_si);
+#pragma aux pm_switch =             \
+    ".286p"                         \
+    "call   pentry"                 \
+    "pentry:"                       \
+    "pop    di"                     \
+    "add    di, 18h"                \
+    "push   38h"                    \
+    "push   di"                     \
+    "lgdt   fword ptr es:[si+08h]"  \
+    "lidt   fword ptr es:[si+10h]"  \
+    "mov    ax, 1"                  \
+    "lmsw   ax"                     \
+    "retf"                          \
+    "pm_pm:"                        \
+    "mov    ax, 28h"                \
+    "mov    ss, ax"                 \
+    "mov    ax, 18h"                \
+    "mov    ds, ax"                 \
+    "mov    ax, 20h"                \
+    "mov    es, ax"                 \
+    parm [si] modify nomemory;
+
+/* Return to caller - we do not use IRET because we should not enable
+ * interrupts. Note that AH must be zero on exit.
+ * WARNING: Needs to be adapted if calling sequence is modified!
+ */
+void pm_unwind(uint16_t args);
+#pragma aux pm_unwind =     \
+    ".286"                  \
+    "mov    sp, ax"         \
+    "popa"                  \
+    "add    sp, 6"          \
+    "pop    cx"             \
+    "pop    ax"             \
+    "pop    ax"             \
+    "mov    ax, 30h"        \
+    "push   ax"             \
+    "push   cx"             \
+    "retf"                  \
+    parm [ax] modify nomemory aborts;
+    
+// @todo: This method is silly. The RTC should be programmed to fire an interrupt
+// instead of hogging the CPU with inaccurate code.
+void timer_wait(uint16_t lo, uint16_t hi);
+#pragma aux timer_wait =    \
+    ".386"                  \
+    "shl    eax, 16"        \
+    "mov    ax, dx"         \
+    "mov    ebx, 15"        \
+    "xor    edx, edx"       \
+    "div    ebx"            \
+    "mov    ecx, eax"       \
+    "in     al, 61h"        \
+    "and    al, 10h"        \
+    "mov    ah, al"         \
+    "or     ecx, ecx"       \
+    "je int1586_tick_end"   \
+    "int1586_tick:"         \
+    "in     al, 61h"        \
+    "and    al, 10h"        \
+    "cmp    al, ah"         \
+    "je     int1586_tick"   \
+    "mov    ah, al"         \
+    "dec    ecx"            \
+    "jnz    int1586_tick"   \
+    "int1586_tick_end:"     \
+    parm [dx] [ax] modify [bx cx] nomemory;
+
+
+bx_bool set_enable_a20(bx_bool val)
+{
+    uint8_t     oldval;
+    
+    // Use PS/2 System Control port A to set A20 enable
+    
+    // get current setting first
+    oldval = inb(0x92);
+    
+    // change A20 status
+    if (val)
+        outb(0x92, oldval | 0x02);
+    else
+        outb(0x92, oldval & 0xfd);
+    
+    return((oldval & 0x02) != 0);
+}
+
+typedef struct {
+    uint32_t    start;
+    uint32_t    xstart;
+    uint32_t    len;
+    uint32_t    xlen;
+    uint32_t    type;
+} mem_range_t;
+
+void set_e820_range(uint16_t ES, uint16_t DI, uint32_t start, uint32_t end,
+                    uint8_t extra_start, uint8_t extra_end, uint16_t type)
+{
+    mem_range_t __far   *range;
+
+    range = ES :> (mem_range_t *)DI;
+    range->start  = start;
+    range->xstart = extra_start;
+    end -= start;
+    extra_end -= extra_start;
+    range->len    = end;
+    range->xlen   = extra_end;
+    range->type   = type;
+}
+
+// @todo: move elsewhere?
+#define AX      r.gr.u.r16.ax
+#define BX      r.gr.u.r16.bx
+#define CX      r.gr.u.r16.cx
+#define DX      r.gr.u.r16.dx
+#define SI      r.gr.u.r16.si
+#define DI      r.gr.u.r16.di
+#define BP      r.gr.u.r16.bp
+#define SP      r.gr.u.r16.sp
+#define FLAGS   r.fl.u.r16.flags
+#define EAX     r.gr.u.r32.eax
+#define EBX     r.gr.u.r32.ebx
+#define ECX     r.gr.u.r32.ecx
+#define EDX     r.gr.u.r32.edx
+#define ES      r.es
+
+
+void BIOSCALL int15_function(sys_regs_t r)
+{
+    uint16_t    ebda_seg=read_word(0x0040,0x000E);
+    bx_bool     prev_a20_enable;
+    uint16_t    base15_00;
+    uint8_t     base23_16;
+    uint16_t    ss;
+    uint16_t    bRegister;
+    uint8_t     irqDisable;
+
+    BX_DEBUG_INT15("int15 AX=%04x\n",AX);
+
+    switch (GET_AH()) {
+    case 0x00: /* assorted functions */
+        if (GET_AL() != 0xc0)
+            goto undecoded;
+        /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
+        * which we don't support, but logging that event is annoying. In fact
+        * it is likely that they just misread some specs, because there is a
+        * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
+        * wants to achieve. */
+        SET_CF();
+        SET_AH(UNSUPPORTED_FUNCTION);
+        break;
+    case 0x24: /* A20 Control */
+        switch (GET_AL()) {
+        case 0x00:
+            set_enable_a20(0);
+            CLEAR_CF();
+            SET_AH(0);
+            break;
+        case 0x01:
+            set_enable_a20(1);
+            CLEAR_CF();
+            SET_AH(0);
+            break;
+        case 0x02:
+            SET_AL( (inb(0x92) >> 1) & 0x01 );
+            CLEAR_CF();
+            SET_AH(0);
+            break;
+        case 0x03:
+            CLEAR_CF();
+            SET_AH(0);
+            BX = 3;
+            break;
+        default:
+            BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) GET_AL());
+            SET_CF();
+            SET_AH(UNSUPPORTED_FUNCTION);
+        }
+        break;
+
+    case 0x41:
+        SET_CF();
+        SET_AH(UNSUPPORTED_FUNCTION);
+        break;
+
+    //@todo: Why does this need special handling? All we need is to set CF
+    //       but not handle this as an unknown function (regardless of CPU type).
+    case 0x4f:
+        /* keyboard intercept */
+#if BX_CPU < 2
+        SET_AH(UNSUPPORTED_FUNCTION);
+#else
+        // nop
+#endif
+        SET_CF();
+        break;
+
+    case 0x52:    // removable media eject
+        CLEAR_CF();
+        SET_AH(0);  // "ok ejection may proceed"
+        break;
+
+    case 0x83: {
+        if( GET_AL() ) {
+            // Set Interval requested.
+            if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
+                // Interval not already set.
+                write_byte( 0x40, 0xA0, 1 );  // Set status byte.
+                write_word( 0x40, 0x98, ES ); // Byte location, segment
+                write_word( 0x40, 0x9A, BX ); // Byte location, offset
+                write_word( 0x40, 0x9C, DX ); // Low word, delay
+                write_word( 0x40, 0x9E, CX ); // High word, delay.
+                CLEAR_CF( );
+                irqDisable = inb( 0xA1 );
+                outb( 0xA1, irqDisable & 0xFE );
+                bRegister = inb_cmos( 0xB );  // Unmask IRQ8 so INT70 will get through.
+                outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
+            } else {
+                // Interval already set.
+                BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
+                SET_CF();
+                SET_AH(UNSUPPORTED_FUNCTION);
+            }
+        } else if( GET_AL() == 1 ) {
+            // Clear Interval requested
+            write_byte( 0x40, 0xA0, 0 );  // Clear status byte
+            CLEAR_CF( );
+            bRegister = inb_cmos( 0xB );
+            outb_cmos( 0xB, bRegister & ~0x40 );  // Turn off the Periodic Interrupt timer
+        } else {
+            BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
+            SET_CF();
+            SET_AH(UNSUPPORTED_FUNCTION);
+            SET_AL(GET_AL() - 1);
+        }
+        
+        break;
+        }
+
+    case 0x87:
+#if BX_CPU < 3
+        SET_AH(UNSUPPORTED_FUNCTION);
+        SET_CF();
+#endif
+        // +++ should probably have descriptor checks
+        // +++ should have exception handlers
+        
+        // turn off interrupts
+        int_disable();    //@todo: aren't they disabled already?
+        
+        prev_a20_enable = set_enable_a20(1); // enable A20 line
+        
+        // 128K max of transfer on 386+ ???
+        // source == destination ???
+        
+        // ES:SI points to descriptor table
+        // offset   use     initially  comments
+        // ==============================================
+        // 00..07   Unused  zeros      Null descriptor
+        // 08..0f   GDT     zeros      filled in by BIOS
+        // 10..17   source  ssssssss   source of data
+        // 18..1f   dest    dddddddd   destination of data
+        // 20..27   CS      zeros      filled in by BIOS
+        // 28..2f   SS      zeros      filled in by BIOS
+        
+        //es:si
+        //eeee0
+        //0ssss
+        //-----
+        
+        // check for access rights of source & dest here
+        
+        // Initialize GDT descriptor
+        base15_00 = (ES << 4) + SI;
+        base23_16 = ES >> 12;
+        if (base15_00 < (ES<<4))
+            base23_16++;
+        write_word(ES, SI+0x08+0, 47);       // limit 15:00 = 6 * 8bytes/descriptor
+        write_word(ES, SI+0x08+2, base15_00);// base 15:00
+        write_byte(ES, SI+0x08+4, base23_16);// base 23:16
+        write_byte(ES, SI+0x08+5, 0x93);     // access
+        write_word(ES, SI+0x08+6, 0x0000);   // base 31:24/reserved/limit 19:16
+        
+        // Initialize CS descriptor
+        write_word(ES, SI+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
+        write_word(ES, SI+0x20+2, 0x0000);// base 15:00
+        write_byte(ES, SI+0x20+4, 0x000f);// base 23:16
+        write_byte(ES, SI+0x20+5, 0x9b);  // access
+        write_word(ES, SI+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
+        
+        // Initialize SS descriptor
+        ss = read_ss();
+        base15_00 = ss << 4;
+        base23_16 = ss >> 12;
+        write_word(ES, SI+0x28+0, 0xffff);   // limit 15:00 = normal 64K limit
+        write_word(ES, SI+0x28+2, base15_00);// base 15:00
+        write_byte(ES, SI+0x28+4, base23_16);// base 23:16
+        write_byte(ES, SI+0x28+5, 0x93);     // access
+        write_word(ES, SI+0x28+6, 0x0000);   // base 31:24/reserved/limit 19:16
+        
+        pm_stack_save(CX, ES, SI);
+        pm_enter();
+        pm_copy();
+        pm_exit();
+        pm_stack_restore();
+        
+        set_enable_a20(prev_a20_enable);
+        
+        // turn interrupts back on
+        int_enable();
+        
+        SET_AH(0);
+        CLEAR_CF();
+        break;
+
+    case 0x88:
+        // Get the amount of extended memory (above 1M)
+#if BX_CPU < 2
+        SET_AH(UNSUPPORTED_FUNCTION);
+        SET_CF();
+#else
+        AX = (inb_cmos(0x31) << 8) | inb_cmos(0x30);
+        
+        // According to Ralf Brown's interrupt the limit should be 15M,
+        // but real machines mostly return max. 63M.
+        if(AX > 0xffc0)
+            AX = 0xffc0;
+        
+        CLEAR_CF();
+#endif
+        break;
+
+    case 0x89:
+        // Switch to Protected Mode.
+        // ES:DI points to user-supplied GDT
+        // BH/BL contains starting interrupt numbers for PIC0/PIC1
+        // This subfunction does not return!
+        
+        // turn off interrupts
+        int_disable();  //@todo: aren't they off already?
+        
+        set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
+        
+        // Initialize CS descriptor for BIOS
+        write_word(ES, SI+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
+        write_word(ES, SI+0x38+2, 0x0000);// base 15:00
+        write_byte(ES, SI+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
+        write_byte(ES, SI+0x38+5, 0x9b);  // access
+        write_word(ES, SI+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
+
+        /* Reprogram the PICs. */
+        outb(PIC_MASTER, PIC_CMD_INIT);
+        outb(PIC_SLAVE,  PIC_CMD_INIT);
+        outb(PIC_MASTER + 1, GET_BH());
+        outb(PIC_SLAVE + 1,  GET_BL());
+        outb(PIC_MASTER + 1, 4);
+        outb(PIC_SLAVE + 1,  2);
+        outb(PIC_MASTER + 1, 1);
+        outb(PIC_SLAVE + 1,  1);
+        /* Mask all IRQs, user must re-enable. */
+        outb(PIC_MASTER_MASK, 0xff);
+        outb(PIC_SLAVE_MASK, 0xff);
+
+        pm_switch(SI);
+        pm_unwind((uint16_t)&r);
+
+        break;
+
+    case 0x90:
+        /* Device busy interrupt.  Called by Int 16h when no key available */
+        break;
+
+    case 0x91:
+        /* Interrupt complete.  Called by Int 16h when key becomes available */
+        break;
+
+    case 0xbf:
+        BX_INFO("*** int 15h function AH=bf not yet supported!\n");
+        SET_CF();
+        SET_AH(UNSUPPORTED_FUNCTION);
+        break;
+
+    case 0xC0:
+        CLEAR_CF();
+        SET_AH(0);
+        BX = BIOS_CONFIG_TABLE;
+        ES = 0xF000;
+        break;
+
+    case 0xc1:
+        ES = ebda_seg;
+        CLEAR_CF();
+        break;
+
+    case 0xd8:
+        bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
+        SET_CF();
+        SET_AH(UNSUPPORTED_FUNCTION);
+        break;
+
+    /* Make the BIOS warning for pretty much every Linux kernel start
+    * disappear - it calls with ax=0xe980 to figure out SMI info. */
+    case 0xe9: /* SMI functions (SpeedStep and similar things) */
+        SET_CF();
+        SET_AH(UNSUPPORTED_FUNCTION);
+        break;
+    case 0xec: /* AMD64 target operating mode callback */
+        if (GET_AL() != 0)
+            goto undecoded;
+        SET_AH(0);
+        if (GET_BL() >= 1 && GET_BL() <= 3)
+            CLEAR_CF();   /* Accepted value. */
+        else
+            SET_CF();     /* Reserved, error. */
+        break;
+undecoded:
+    default:
+        BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+                (unsigned) AX, (unsigned) BX_APM);
+        SET_CF();
+        SET_AH(UNSUPPORTED_FUNCTION);
+        break;
+    }
+}
+
+void BIOSCALL int15_function32(sys32_regs_t r)
+{
+    uint32_t    extended_memory_size=0; // 64bits long
+    uint32_t    extra_lowbits_memory_size=0;
+    uint8_t     extra_highbits_memory_size=0;
+    uint32_t    mcfgStart, mcfgSize;
+
+    BX_DEBUG_INT15("int15 AX=%04x\n",AX);
+
+    switch (GET_AH()) {
+    case 0x86:
+        // Wait for CX:DX microseconds. currently using the
+        // refresh request port 0x61 bit4, toggling every 15usec
+        int_enable();
+        timer_wait(DX, CX);
+        break;
+    
+    case 0xe8:
+        switch(GET_AL()) {
+        case 0x20: // coded by osmaker aka K.J.
+            if(EDX == 0x534D4150) {
+                extended_memory_size = inb_cmos(0x35);
+                extended_memory_size <<= 8;
+                extended_memory_size |= inb_cmos(0x34);
+                extended_memory_size *= 64;
+#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
+                // greater than EFF00000???
+                if(extended_memory_size > 0x3bc000) {
+                    extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
+                }
+#endif /* !VBOX */
+                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);
+                }
+
+#ifdef VBOX     /* We've already used the CMOS entries for SATA.
+                   BTW. This is the amount of memory above 4GB measured in 64KB units. */
+                extra_lowbits_memory_size = inb_cmos(0x62);
+                extra_lowbits_memory_size <<= 8;
+                extra_lowbits_memory_size |= inb_cmos(0x61);
+                extra_lowbits_memory_size <<= 16;
+                extra_highbits_memory_size = inb_cmos(0x63);
+                /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
+#else
+                extra_lowbits_memory_size = inb_cmos(0x5c);
+                extra_lowbits_memory_size <<= 8;
+                extra_lowbits_memory_size |= inb_cmos(0x5b);
+                extra_lowbits_memory_size *= 64;
+                extra_lowbits_memory_size *= 1024;
+                extra_highbits_memory_size = inb_cmos(0x5d);
+#endif /* !VBOX */
+
+                mcfgStart = 0;
+                mcfgSize  = 0;
+
+                switch(BX)
+                {
+                    case 0:
+                        set_e820_range(ES, DI,
+#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
+                                       0x0000000L, 0x0009f000L, 0, 0, 1);
+#else
+                                       0x0000000L, 0x0009fc00L, 0, 0, 1);
+#endif
+                        EBX = 1;
+                        break;
+                    case 1:
+                        set_e820_range(ES, DI,
+#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
+                                       0x0009f000L, 0x000a0000L, 0, 0, 2);
+#else
+                                       0x0009fc00L, 0x000a0000L, 0, 0, 2);
+#endif
+                        EBX = 2;
+                        break;
+                    case 2:
+#ifdef VBOX
+                        /* Mark the BIOS as reserved. VBox doesn't currently
+                         * use the 0xe0000-0xeffff area. It does use the
+                         * 0xd0000-0xdffff area for the BIOS logo, but it's
+                         * not worth marking it as reserved. (this is not
+                         * true anymore because the VGA adapter handles the logo stuff)
+                         * The whole 0xe0000-0xfffff can be used for the BIOS.
+                         * Note that various
+                         * Windows versions don't accept (read: in debug builds
+                         * they trigger the "Too many similar traps" assertion)
+                         * a single reserved range from 0xd0000 to 0xffffff.
+                         * A 128K area starting from 0xd0000 works. */
+                        set_e820_range(ES, DI,
+                                       0x000f0000L, 0x00100000L, 0, 0, 2);
+#else /* !VBOX */
+                        set_e820_range(ES, DI,
+                                       0x000e8000L, 0x00100000L, 0, 0, 2);
+#endif /* !VBOX */
+                        EBX = 3;
+                        break;
+                    case 3:
+#if BX_ROMBIOS32 || defined(VBOX)
+                        set_e820_range(ES, DI,
+                                       0x00100000L,
+                                       extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
+                        EBX = 4;
+#else
+                        set_e820_range(ES, DI,
+                                       0x00100000L,
+                                       extended_memory_size, 1);
+                        EBX = 5;
+#endif
+                        break;
+                    case 4:
+                        set_e820_range(ES, DI,
+                                       extended_memory_size - ACPI_DATA_SIZE,
+                                       extended_memory_size, 0, 0, 3); // ACPI RAM
+                        EBX = 5;
+                        break;
+                    case 5:
+                        /* 256KB BIOS area at the end of 4 GB */
+#ifdef VBOX
+                        /* We don't set the end to 1GB here and rely on the 32-bit
+                           unsigned wrap around effect (0-0xfffc0000L). */
+#endif
+                        set_e820_range(ES, DI,
+                                       0xfffc0000L, 0x00000000L, 0, 0, 2);
+                        if (mcfgStart != 0)
+                            EBX = 6;
+                        else
+                        {
+                            if (extra_highbits_memory_size || extra_lowbits_memory_size)
+                                EBX = 7;
+                            else
+                                EBX = 0;
+                        }
+                        break;
+                     case 6:
+                        /* PCI MMIO config space (MCFG) */
+                        set_e820_range(ES, DI,
+                                       mcfgStart, mcfgStart + mcfgSize, 0, 0, 2);
+
+                        if (extra_highbits_memory_size || extra_lowbits_memory_size)
+                            EBX = 7;
+                        else
+                            EBX = 0;
+                        break;
+                    case 7:
+#ifdef VBOX /* Don't succeeded if no memory above 4 GB.  */
+                        /* Mapping of memory above 4 GB if present.
+                           Note: set_e820_range needs do no borrowing in the
+                                 subtraction because of the nice numbers. */
+                        if (extra_highbits_memory_size || extra_lowbits_memory_size)
+                        {
+                            set_e820_range(ES, DI,
+                                           0x00000000L, extra_lowbits_memory_size,
+                                           1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
+                            EBX = 0;
+                        }
+                        break;
+                        /* fall thru */
+#else  /* !VBOX */
+                        /* Mapping of memory above 4 GB */
+                        set_e820_range(ES, DI, 0x00000000L,
+                        extra_lowbits_memory_size, 1, extra_highbits_memory_size
+                                       + 1, 1);
+                        EBX = 0;
+                        break;
+#endif /* !VBOX */
+                    default:  /* AX=E820, DX=534D4150, BX unrecognized */
+                        goto int15_unimplemented;
+                        break;
+                }
+                EAX = 0x534D4150;
+                ECX = 0x14;
+                CLEAR_CF();
+            } 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)
+            CX = (inb_cmos(0x31) << 8) | inb_cmos(0x30);
+            
+            // limit to 15M
+            if(CX > 0x3c00)
+                CX = 0x3c00;
+            
+            // Get the amount of extended memory above 16M in 64k blocks
+            DX = (inb_cmos(0x35) << 8) | inb_cmos(0x34);
+            
+            // Set configured memory equal to extended memory
+            AX = CX;
+            BX = DX;
+            break;
+        default:  /* AH=0xE8?? but not implemented */
+            goto int15_unimplemented;
+        }
+        break;
+    int15_unimplemented:
+       // fall into the default case
+    default:
+        BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+                (unsigned) AX, (unsigned) BX);
+        SET_CF();
+        SET_AL(UNSUPPORTED_FUNCTION);
+        break;
+    }
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/timepci.c
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/timepci.c	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/timepci.c	(revision 38699)
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ *  ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+ *
+ *  Copyright (C) 2002  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  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
+ *
+ */
+
+
+#include <stdint.h>
+#include "biosint.h"
+#include "inlines.h"
+
+#if DEBUG_INT1A
+#  define BX_DEBUG_INT1A(...)   BX_DEBUG(__VA_ARGS__)
+#else
+#  define BX_DEBUG_INT1A(...)
+#endif
+
+// for access to RAM area which is used by interrupt vectors
+// and BIOS Data Area
+
+typedef struct {
+    uint8_t     filler1[0x400];
+    uint8_t     filler2[0x6c];
+    uint16_t    ticks_low;
+    uint16_t    ticks_high;
+    uint8_t     midnight_flag;
+} bios_data_t;
+
+#define BiosData ((bios_data_t __far *) 0)
+
+void init_rtc(void)
+{
+    outb_cmos(0x0a, 0x26);
+    outb_cmos(0x0b, 0x02);
+    inb_cmos(0x0c);
+    inb_cmos(0x0d);
+}
+
+bx_bool rtc_updating(void)
+{
+    // This function checks to see if the update-in-progress bit
+    // is set in CMOS Status Register A.  If not, it returns 0.
+    // If it is set, it tries to wait until there is a transition
+    // to 0, and will return 0 if such a transition occurs.  A 1
+    // is returned only after timing out.  The maximum period
+    // that this bit should be set is constrained to 244useconds.
+    // The count I use below guarantees coverage or more than
+    // this time, with any reasonable IPS setting.
+    
+    uint16_t    iter;
+    
+    iter = 25000;
+    while (--iter != 0) {
+    if ( (inb_cmos(0x0a) & 0x80) == 0 )
+        return 0;
+    }
+    return 1;   // update-in-progress never transitioned to 0
+}
+
+
+extern void eoi_both_pics(void);    /* in assembly code */
+#pragma aux eoi_both_pics "*";
+
+void call_int_4a(void);
+#pragma aux call_int_4a = "int 4Ah";
+
+void BIOSCALL int70_function(pusha_regs_t regs, uint16_t ds, uint16_t es, iret_addr_t iret_addr)
+{
+    // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
+    uint8_t   registerB = 0, registerC = 0;
+    
+    // Check which modes are enabled and have occurred.
+    registerB = inb_cmos( 0xB );
+    registerC = inb_cmos( 0xC );
+    
+    if( ( registerB & 0x60 ) != 0 ) {
+        if( ( registerC & 0x20 ) != 0 ) {
+            // Handle Alarm Interrupt.
+            int_enable();
+            call_int_4a();
+            int_disable();
+        }
+        if( ( registerC & 0x40 ) != 0 ) {
+            // Handle Periodic Interrupt.
+            
+            if( read_byte( 0x40, 0xA0 ) != 0 ) {
+                // Wait Interval (Int 15, AH=83) active.
+                uint32_t    time;
+                
+                time = read_dword( 0x40, 0x9C );  // Time left in microseconds.
+                if( time < 0x3D1 ) {
+                    // Done waiting.
+                    uint16_t    segment, offset;
+                    
+                    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, read_byte(segment, offset) | 0x80 );  // Write to specified flag byte.
+                } else {
+                    // Continue waiting.
+                    time -= 0x3D1;
+                    write_dword( 0x40, 0x9C, time );
+                }
+            }
+        }
+    }
+    eoi_both_pics();
+}
+
+// @todo: the coding style WRT register access is totally inconsistent
+// in the following routines
+
+/* The PCI BIOS routine must be callable from protected mode, and
+ * therefore must not modify any segment registers(!).
+ */
+#if BX_PCIBIOS
+void BIOSCALL int1a_function_pci(i1apci_regs_t r)
+{
+#if 0
+    // real mode PCI BIOS functions now handled in assembler code
+    // this C code handles the error code for information only
+    if (r.gr.u.r8.ah == 0xff) {
+        BX_INFO("PCI BIOS: PCI not present\n");
+    } else if (r.gr.u.r8.ah == 0x81) {
+        BX_INFO("unsupported PCI BIOS function 0x%02x\n", r.gr.u.r8.al);
+    } else if (r.gr.u.r8.ah == 0x83) {
+        BX_INFO("bad PCI vendor ID %04x\n", r.gr.u.r16.dx);
+    } else if (r.gr.u.r8.ah == 0x86) {
+        if (r.gr.u.r8.ah == 0x02) {
+            BX_INFO("PCI device %04x:%04x not found at index %d\n", r.gr.u.r16.dx, r.gr.u.r16.cx, r.gr.u.r16.si);
+        } else {
+            BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", r.gr.u.r8.cl, r.gr.u.r16.dx, r.gr.u.r16.si);
+        }
+    }
+#endif
+    //@todo: OS/2 MCP2 apparently calls us in protected mode with a DS which does not
+    // point to the BIOS segment!?!
+    send(BIOS_PRINTF_INFO, '!');
+    send(BIOS_PRINTF_INFO, '\n');
+    if (!GetCF(r.ra.flags)) {
+        SetCF(r.ra.flags);
+    }
+}
+#endif
+
+
+void BIOSCALL int1a_function(pusha_regs_t regs, uint16_t ds, uint16_t es, iret_addr_t iret_addr)
+{
+    uint8_t     val8;
+
+    BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", 
+                   regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
+    int_enable();    
+    
+    switch (regs.u.r8.ah) {
+    case 0: // get current clock count
+        int_disable();
+        regs.u.r16.cx = BiosData->ticks_high;
+        regs.u.r16.dx = BiosData->ticks_low;
+        regs.u.r8.al  = BiosData->midnight_flag;
+        BiosData->midnight_flag = 0; // reset flag
+        int_enable();
+        // AH already 0
+        ClearCF(iret_addr.flags); // OK
+        break;
+    
+    case 1: // Set Current Clock Count
+        int_disable();
+        BiosData->ticks_high = regs.u.r16.cx;
+        BiosData->ticks_low  = regs.u.r16.dx;
+        BiosData->midnight_flag = 0; // reset flag
+        int_enable();
+        regs.u.r8.ah = 0;
+        ClearCF(iret_addr.flags); // OK
+        break;
+        
+    case 2: // Read CMOS Time
+        if (rtc_updating()) {
+            SetCF(iret_addr.flags);
+            break;
+        }
+        
+        regs.u.r8.dh = inb_cmos(0x00); // Seconds
+        regs.u.r8.cl = inb_cmos(0x02); // Minutes
+        regs.u.r8.ch = inb_cmos(0x04); // Hours
+        regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
+        regs.u.r8.ah = 0;
+        regs.u.r8.al = regs.u.r8.ch;
+        ClearCF(iret_addr.flags); // OK
+        break;
+    
+    case 3: // Set CMOS Time
+        // Using a debugger, I notice the following masking/setting
+        // of bits in Status Register B, by setting Reg B to
+        // a few values and getting its value after INT 1A was called.
+        //
+        //        try#1       try#2       try#3
+        // before 1111 1101   0111 1101   0000 0000
+        // after  0110 0010   0110 0010   0000 0010
+        //
+        // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+        // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
+        if (rtc_updating()) {
+            init_rtc();
+            // fall through as if an update were not in progress
+        }
+        outb_cmos(0x00, regs.u.r8.dh); // Seconds
+        outb_cmos(0x02, regs.u.r8.cl); // Minutes
+        outb_cmos(0x04, regs.u.r8.ch); // Hours
+        // Set Daylight Savings time enabled bit to requested value
+        val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
+        // (reg B already selected)
+        outb_cmos(0x0b, val8);
+        regs.u.r8.ah = 0;
+        regs.u.r8.al = val8; // val last written to Reg B
+        ClearCF(iret_addr.flags); // OK
+        break;
+    
+    case 4: // Read CMOS Date
+        regs.u.r8.ah = 0;
+        if (rtc_updating()) {
+            SetCF(iret_addr.flags);
+            break;
+        }
+        regs.u.r8.cl = inb_cmos(0x09); // Year
+        regs.u.r8.dh = inb_cmos(0x08); // Month
+        regs.u.r8.dl = inb_cmos(0x07); // Day of Month
+        regs.u.r8.ch = inb_cmos(0x32); // Century
+        regs.u.r8.al = regs.u.r8.ch;
+        ClearCF(iret_addr.flags); // OK
+        break;
+    
+    case 5: // Set CMOS Date
+        // Using a debugger, I notice the following masking/setting
+        // of bits in Status Register B, by setting Reg B to
+        // a few values and getting its value after INT 1A was called.
+        //
+        //        try#1       try#2       try#3       try#4
+        // before 1111 1101   0111 1101   0000 0010   0000 0000
+        // after  0110 1101   0111 1101   0000 0010   0000 0000
+        //
+        // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+        // My assumption: RegB = (RegB & 01111111b)
+        if (rtc_updating()) {
+            init_rtc();
+            SetCF(iret_addr.flags);
+            break;
+        }
+        outb_cmos(0x09, regs.u.r8.cl); // Year
+        outb_cmos(0x08, regs.u.r8.dh); // Month
+        outb_cmos(0x07, regs.u.r8.dl); // Day of Month
+        outb_cmos(0x32, regs.u.r8.ch); // Century
+        val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
+        outb_cmos(0x0b, val8);
+        regs.u.r8.ah = 0;
+        regs.u.r8.al = val8; // AL = val last written to Reg B
+        ClearCF(iret_addr.flags); // OK
+        break;
+    
+    case 6: // Set Alarm Time in CMOS
+        // Using a debugger, I notice the following masking/setting
+        // of bits in Status Register B, by setting Reg B to
+        // a few values and getting its value after INT 1A was called.
+        //
+        //        try#1       try#2       try#3
+        // before 1101 1111   0101 1111   0000 0000
+        // after  0110 1111   0111 1111   0010 0000
+        //
+        // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+        // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
+        val8 = inb_cmos(0x0b); // Get Status Reg B
+        regs.u.r16.ax = 0;
+        if (val8 & 0x20) {
+            // Alarm interrupt enabled already
+            SetCF(iret_addr.flags); // Error: alarm in use
+            break;
+        }
+        if (rtc_updating()) {
+            init_rtc();
+            // fall through as if an update were not in progress
+        }
+        outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
+        outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
+        outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
+        outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
+        // enable Status Reg B alarm bit, clear halt clock bit
+        outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
+        ClearCF(iret_addr.flags); // OK
+        break;
+    
+    case 7: // Turn off Alarm
+        // Using a debugger, I notice the following masking/setting
+        // of bits in Status Register B, by setting Reg B to
+        // a few values and getting its value after INT 1A was called.
+        //
+        //        try#1       try#2       try#3       try#4
+        // before 1111 1101   0111 1101   0010 0000   0010 0010
+        // after  0100 0101   0101 0101   0000 0000   0000 0010
+        //
+        // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+        // My assumption: RegB = (RegB & 01010111b)
+        val8 = inb_cmos(0x0b); // Get Status Reg B
+        // clear clock-halt bit, disable alarm bit
+        outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
+        regs.u.r8.ah = 0;
+        regs.u.r8.al = val8; // val last written to Reg B
+        ClearCF(iret_addr.flags); // OK
+        break;
+    
+    default:
+        BX_DEBUG_INT1A("int1a: AX=%04x unsupported\n", regs.u.r16.ax);
+        SetCF(iret_addr.flags); // Unsupported
+    }
+}
Index: /trunk/src/VBox/Devices/PC/BIOS-new/vbdmismi.inc
===================================================================
--- /trunk/src/VBox/Devices/PC/BIOS-new/vbdmismi.inc	(revision 38699)
+++ /trunk/src/VBox/Devices/PC/BIOS-new/vbdmismi.inc	(revision 38699)
@@ -0,0 +1,10 @@
+;; TODO: make dynamic
+
+VBOX_DMI_TABLE_BASE	equ	0E1000h
+VBOX_DMI_TABLE_VER	equ	25h
+VBOX_DMI_TABLE_ENTR	equ	5
+VBOX_DMI_TABLE_SIZE	equ	352
+
+VBOX_SMBIOS_MAJOR_VER	equ	2
+VBOX_SMBIOS_MINOR_VER	equ	5
+VBOX_SMBIOS_MAXSS	equ	0FFh
