eltorito.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 <string.h>
#include "inlines.h"
#include "biosint.h"
#include "ebda.h"
#include "ata.h"
#if DEBUG_ELTORITO
#else
# define BX_DEBUG_INT13_ET(...)
#endif
#if DEBUG_INT13_CD
#else
# define BX_DEBUG_INT13_CD(...)
#endif
#if DEBUG_CD_BOOT
#else
# define BX_DEBUG_ELTORITO(...)
#endif
//@todo: put in a header
#pragma pack(1)
typedef struct {
} cdb_atapi;
#pragma pack()
// ---------------------------------------------------------------------------
// 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
// the only important data is this one for now
}
{
// @TODO: a macro or a function for getting the EBDA segment
}
{
// @TODO: a macro or a function for getting the EBDA segment
}
// ---------------------------------------------------------------------------
// Start of int13 for eltorito functions
// ---------------------------------------------------------------------------
{
// @TODO: a macro or a function for getting the EBDA segment
// 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
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()?
// If we have to terminate emulation
if(GET_AL() == 0x00) {
// FIXME ElTorito Various. Should be handled accordingly to spec
}
goto int13_success;
break;
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
// ---------------------------------------------------------------------------
// End of int13 for eltorito functions
// ---------------------------------------------------------------------------
/* Utility routine to check if a device is a CD-ROM. */
//@todo: this function is kinda useless as the ATAPI type check is obsolete.
{
if (device >= BX_MAX_STORAGE_DEVICES)
return 0;
// if (bios_dsk->devices[device].type != DSK_TYPE_ATAPI)
// return 0;
return 0;
return 1;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
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
/* Find the first CD-ROM. */
if (device_is_cdrom(device))
break;
}
/* Fail if not found. */
if (device >= BX_MAX_STORAGE_DEVICES)
return 2;
/* Read the Boot Record Volume Descriptor (BRVD). */
{
//@todo: Use indirect calls instead?
if (device > BX_MAX_ATA_DEVICES)
else
if (!error)
break;
}
if (error)
return 3;
/* Check for a valid BRVD. */
if (buffer[0] != 0)
return 4;
//@todo: what's wrong with memcmp()?
for (i = 0; i < 5; ++i) {
return 5;
}
for (i = 0; i < 23; ++i)
return 6;
// ok, now we calculate the Boot catalog address
/* Now we read the Boot Catalog. */
#if 0 // Not necessary as long as previous values are reused
#endif
if (device > BX_MAX_ATA_DEVICES)
else
if (error != 0)
return 7;
//@todo: Define a struct for the Boot Catalog, the hardcoded offsets are so dumb...
/* Check if the Boot Catalog looks valid. */
return 8; // Header
return 9; // Platform
return 10; // key 1
return 10; // key 2
return 11; // Bootable
if (buffer[0x21] == 0) {
// FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
// Win2000 cd boot needs to know it booted from cd
}
else
if (boot_segment == 0)
boot_segment = 0x07C0;
BX_DEBUG_ELTORITO("Emulate drive %02x, type %02x, LBA %lu\n",
/* Read the disk image's boot sector into memory. */
if (device > BX_MAX_ATA_DEVICES)
error = ahci_cmd_packet(device, 12, (char __far *)&atapicmd, 0, nbsectors*512L, ATA_DATA_IN, MK_FP(boot_segment,0));
else
error = ata_cmd_packet(device, 12, (char __far *)&atapicmd, 0, nbsectors*512L, ATA_DATA_IN, MK_FP(boot_segment,0));
if (error != 0)
return 12;
BX_DEBUG_ELTORITO("Emulate drive %02x, type %02x, LBA %lu\n",
/* Set up emulated drive geometry based on the media type. */
case 0x01: /* 1.2M floppy */
break;
case 0x02: /* 1.44M floppy */
break;
case 0x03: /* 2.88M floppy */
break;
case 0x04: /* Hard disk */
break;
}
/* Increase BIOS installed number of drives (floppy or fixed). */
else
write_byte(ebda_seg,(uint16_t)&EbdaData->bdisk.hdcount, read_byte(ebda_seg, (uint16_t)&EbdaData->bdisk.hdcount) + 1);
}
// everything is ok, so from now on, the emulation is active
// return the boot drive + no error
}
// ---------------------------------------------------------------------------
// End of El-Torito boot functions
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// Start of int13 when emulating a device from the cd
// ---------------------------------------------------------------------------
{
// @TODO: a macro or a function for getting the EBDA segment
// Recompute the device number
SET_DISK_RET_STATUS(0x00);
/* basic checks : emulation should be active, dl should equal the emulated drive */
goto int13_fail;
}
switch (GET_AH()) {
// all those functions return SUCCESS
case 0x00: /* disk controller reset */
case 0x09: /* initialize drive parameters */
case 0x0c: /* seek to specified cylinder */
case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
case 0x11: /* recalibrate */
case 0x14: /* controller internal diagnostic */
case 0x16: /* detect disk change */
goto int13_success;
break;
// all those functions return disk write-protected
case 0x03: /* write disk sectors */
case 0x05: /* format disk track */
SET_AH(0x03);
goto int13_fail_noah;
break;
case 0x01: /* read disk status */
/* set CF if error status read */
if (status)
goto int13_fail_nostatus;
else
goto int13_success_noah;
break;
case 0x02: // read disk sectors
case 0x04: // verify disk sectors
// no sector to read ?
if(nbsectors==0)
goto int13_success;
// sanity checks sco openserver needs this!
|| (cylinder >= vcylinders)
goto int13_fail;
}
// After validating the input, verify does nothing
if (GET_AH() == 0x04)
goto int13_success;
// 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
// start lba on cd
// end lba on cd
if (device > BX_MAX_ATA_DEVICES)
status = ahci_cmd_packet(device, 12, (char __far *)&atapicmd, before*512, nbsectors*512L, ATA_DATA_IN, MK_FP(segment,offset));
else
status = ata_cmd_packet(device, 12, (char __far *)&atapicmd, before*512, nbsectors*512L, ATA_DATA_IN, MK_FP(segment,offset));
if (status != 0) {
SET_AH(0x02);
SET_AL(0);
goto int13_fail_noah;
}
goto int13_success;
break;
case 0x08: /* read disk drive parameters */
SET_AL( 0x00 );
SET_BL( 0x00 );
// FIXME ElTorito Harddisk. should send the HD count
}
goto int13_success;
break;
case 0x15: /* read disk drive size */
// FIXME ElTorito Harddisk. What geometry to send ?
SET_AH(0x03);
goto int13_success_noah;
break;
// all those functions return unimplemented
case 0x0a: /* read disk sectors with ECC */
case 0x0b: /* write disk sectors with ECC */
case 0x18: /* set media type for format */
// FIXME ElTorito Harddisk. Darwin would like to use EDD
case 0x4e: // ? - set hardware configuration
case 0x50: // ? - send packet command
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
// ---------------------------------------------------------------------------
// Start of int13 for cdrom
// ---------------------------------------------------------------------------
{
SET_DISK_RET_STATUS(0x00);
/* basic check : device should be 0xE0+ */
goto int13_fail;
}
// Get the ata channel
/* basic check : device has to be valid */
if (device >= BX_MAX_STORAGE_DEVICES) {
goto int13_fail;
}
switch (GET_AH()) {
// all those functions return SUCCESS
case 0x00: /* disk controller reset */
case 0x09: /* initialize drive parameters */
case 0x0c: /* seek to specified cylinder */
case 0x0d: /* alternate disk reset */
case 0x10: /* check drive ready */
case 0x11: /* recalibrate */
case 0x14: /* controller internal diagnostic */
case 0x16: /* detect disk change */
goto int13_success;
break;
// all those functions return disk write-protected
case 0x03: /* write disk sectors */
case 0x05: /* format disk track */
SET_AH(0x03);
goto int13_fail_noah;
break;
case 0x01: /* read disk status */
/* set CF if error status read */
if (status)
goto int13_fail_nostatus;
else
goto int13_success_noah;
break;
case 0x15: /* read disk drive size */
SET_AH(0x02);
goto int13_fail_noah;
break;
goto int13_success_noah;
break;
/* Load the I13X struct pointer. */
// Can't use 64 bits lba
if (lba != 0L) {
goto int13_fail;
}
// Get 32 bits lba
// If verify or seek
goto int13_success;
BX_DEBUG_INT13_CD("%s: read %u sectors @ LBA %lu to %04X:%04X\n",
if (device > BX_MAX_ATA_DEVICES)
status = ahci_cmd_packet(device, 12, (char __far *)&atapicmd, 0, count*2048L, ATA_DATA_IN, MK_FP(segment,offset));
else
status = ata_cmd_packet(device, 12, (char __far *)&atapicmd, 0, count*2048L, ATA_DATA_IN, MK_FP(segment,offset));
if (status != 0) {
SET_AH(0x0c);
goto int13_fail_noah;
}
goto int13_success;
break;
if (GET_AL() > 2)
goto int13_fail;
switch (GET_AL()) {
case 0 : // lock
if (locks == 0xff) {
SET_AH(0xb4);
SET_AL(1);
goto int13_fail_noah;
}
SET_AL(1);
break;
case 1 : // unlock
if (locks == 0x00) {
SET_AH(0xb0);
SET_AL(0);
goto int13_fail_noah;
}
break;
case 2 : // status
break;
}
goto int13_success;
break;
if (locks != 0) {
goto int13_fail_noah;
}
// FIXME should handle 0x31 no media in device
// FIXME should handle 0xb5 valid request failed
#if 0 //@todo: implement!
// Call removable media eject
int #0x15
#endif
if (status != 0) {
goto int13_fail_noah;
}
goto int13_success;
break;
//@todo: Part of this should be merged with analogous code in disk.c
// Buffer is too small
if (size < 0x1a)
goto int13_fail;
// EDD 1.x
if (size >= 0x1a) {
}
// EDD 2.x
if(size >= 0x1e) {
// Fill in dpte
// FIXME atapi device
checksum = 0;
for (i = 0; i < 15; ++i)
}
// EDD 3.x
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 int13_success;
break;
// always send changed ??
SET_AH(06);
goto int13_fail_nostatus;
break;
// DMA, prefetch, PIO maximum not supported
switch (GET_AL()) {
case 0x01:
case 0x03:
case 0x04:
case 0x06:
goto int13_success;
break;
default :
goto int13_fail;
}
break;
// all those functions return unimplemented
case 0x02: /* read sectors */
case 0x04: /* verify sectors */
case 0x08: /* read disk drive parameters */
case 0x0a: /* read disk sectors with ECC */
case 0x0b: /* write disk sectors with ECC */
case 0x18: /* set media type for format */
case 0x50: // ? - send packet command
default:
goto int13_fail;
break;
}
SET_CF(); // error occurred
return;
SET_DISK_RET_STATUS(0x00);
CLEAR_CF(); // no error
return;
}
// ---------------------------------------------------------------------------
// End of int13 for cdrom
// ---------------------------------------------------------------------------