disk.c revision 94fde0b66aced35ee31b2218ab4371f2a48888c1
/*
* 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;
* 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:
*
*
* Copyright (C) 2002 MandrakeSoft S.A.
*
* MandrakeSoft S.A.
* 43, rue d'Aboukir
* 75002 Paris - France
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
#include "biosint.h"
#include "inlines.h"
#include "ebda.h"
#include "ata.h"
#if DEBUG_INT13_HD
#else
# define BX_DEBUG_INT13_HD(...)
#endif
/* Controller specific disk access routines. Declared as a union to reduce
* Note that we get away with using near pointers, which is nice.
*/
typedef union {
struct {
} s;
dsk_rw_func a[2];
} dsk_acc_t;
/* Pointers to HW specific disk access routines. */
#ifdef VBOX_WITH_AHCI
#endif
#ifdef VBOX_WITH_SCSI
#endif
};
//@todo: put in a header
{
// basic check : device has to be defined
goto int13_fail;
}
// Get the ata channel
// basic check : device has to be valid
if (device >= BX_MAX_STORAGE_DEVICES) {
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
goto int13_success;
break;
case 0x01: /* read disk status */
/* set CF if error status read */
if (status) goto int13_fail_nostatus;
else goto int13_success_noah;
break;
case 0x02: // read disk sectors
case 0x03: // write disk sectors
case 0x04: // verify disk sectors
/* Segment and offset are in ES:BX. */
goto int13_fail;
}
/* Get the logical CHS geometry. */
/* Sanity check the geometry. */
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;
/* If required, translate LCHS to LBA and execute command. */
//@todo: The IS_SCSI_DEVICE check should be redundant...
if (( (bios_dsk->devices[device].pchs.heads != nlh) || (bios_dsk->devices[device].pchs.spt != 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
}
/* Pass request information to low level disk code. */
// Set nb of sector transferred
if (status != 0) {
SET_AH(0x0c);
goto int13_fail_noah;
}
goto int13_success;
break;
case 0x05: /* format disk track */
BX_INFO("format disk track called\n");
goto int13_success;
return;
break;
case 0x08: /* read disk drive parameters */
/* Get the logical geometry from internal table. */
/* Maximum cylinder number is just one less than the number of cylinders. */
SET_AL(0);
// 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
goto int13_success;
} else {
SET_AH(0xAA);
goto int13_fail_noah;
}
break;
case 0x15: /* read disk drive size */
/* Get the physical geometry from internal table. */
/* Calculate sector count seen by old style INT 13h. */
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 */
goto int13_success;
break;
case 0x0a: /* read disk sectors with ECC */
case 0x0b: /* write disk sectors with ECC */
case 0x18: // set media type for format
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
{
// basic check : device has to be defined
goto int13x_fail;
}
// Get the ata channel
// basic check : device has to be valid
if (device >= BX_MAX_STORAGE_DEVICES) {
goto int13x_fail;
}
switch (GET_AH()) {
goto int13x_success_noah;
break;
/* Get a pointer to the extended structure. */
// Can't use 64 bits lba
if (lba != 0L) {
goto int13x_fail;
}
// Get 32 bits lba and check
goto int13x_fail;
}
/* Don't bother with seek or verify. */
goto int13x_success;
/* Pass request information to low level disk code. */
/* Execute the read or write command. */
if (status != 0) {
SET_AH(0x0c);
goto int13x_fail_noah;
}
goto int13x_success;
break;
goto int13x_success; // Always success for HD
break;
goto int13x_fail_noah; // Always fail for HD
break;
/* Check if buffer is large enough. */
if (size < 0x1a)
goto int13x_fail;
/* Fill in EDD 1.x table. */
if (size >= 0x1a) {
dpt->sector_count2 = 0;
}
/* Fill in EDD 2.x table. */
if (size >= 0x1e) {
// Fill in dpte
checksum = 0;
for (i = 0; i < 15; ++i)
}
/* Fill in EDD 3.x table. */
if(size >= 0x42) {
if (iface == ATA_IFACE_ISA) {
}
else {
// FIXME PCI
}
if (iface == ATA_IFACE_ISA) {
}
else {
// FIXME PCI
}
checksum = 0;
for (i = 30; i < 64; i++)
}
goto int13x_success;
break;
// 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;
default:
goto int13x_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
/* Avoid saving general registers already saved by caller (PUSHA). */