mirror of
https://github.com/xcat2/xNBA.git
synced 2025-01-05 11:05:07 +00:00
Split bootsector execution code out into bootsector.c.
Added basic El Torito ISO image boot capability
This commit is contained in:
parent
bde8878eef
commit
2cf1e33df1
111
src/arch/i386/image/bootsector.c
Normal file
111
src/arch/i386/image/bootsector.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* x86 bootsector image format
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <realmode.h>
|
||||
#include <biosint.h>
|
||||
#include <bootsector.h>
|
||||
|
||||
/** Vector for storing original INT 18 handler
|
||||
*
|
||||
* We do not chain to this vector, so there is no need to place it in
|
||||
* .text16.
|
||||
*/
|
||||
static struct segoff int18_vector;
|
||||
|
||||
/** Vector for storing original INT 19 handler
|
||||
*
|
||||
* We do not chain to this vector, so there is no need to place it in
|
||||
* .text16.
|
||||
*/
|
||||
static struct segoff int19_vector;
|
||||
|
||||
/** Restart point for INT 18 or 19 */
|
||||
extern void bootsector_exec_fail ( void );
|
||||
|
||||
/**
|
||||
* Jump to preloaded bootsector
|
||||
*
|
||||
* @v segment Real-mode segment
|
||||
* @v offset Real-mode offset
|
||||
* @v drive Drive number to pass to boot sector
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int call_bootsector ( unsigned int segment, unsigned int offset,
|
||||
unsigned int drive ) {
|
||||
int discard_b, discard_D, discard_d;
|
||||
|
||||
DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset );
|
||||
|
||||
/* Hook INTs 18 and 19 to capture failure paths */
|
||||
hook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
|
||||
&int18_vector );
|
||||
hook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
|
||||
&int19_vector );
|
||||
|
||||
/* Boot the loaded sector
|
||||
*
|
||||
* We assume that the boot sector may completely destroy our
|
||||
* real-mode stack, so we preserve everything we need in
|
||||
* static storage.
|
||||
*/
|
||||
__asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
|
||||
"popw %%cs:saved_retaddr\n\t"
|
||||
/* Save stack pointer */
|
||||
"movw %%ss, %%ax\n\t"
|
||||
"movw %%ax, %%cs:saved_ss\n\t"
|
||||
"movw %%sp, %%cs:saved_sp\n\t"
|
||||
/* Jump to boot sector */
|
||||
"pushw %%bx\n\t"
|
||||
"pushw %%di\n\t"
|
||||
"lret\n\t"
|
||||
/* Preserved variables */
|
||||
"\nsaved_ss: .word 0\n\t"
|
||||
"\nsaved_sp: .word 0\n\t"
|
||||
"\nsaved_retaddr: .word 0\n\t"
|
||||
/* Boot failure return point */
|
||||
"\nbootsector_exec_fail:\n\t"
|
||||
/* Restore stack pointer */
|
||||
"movw %%cs:saved_ss, %%ax\n\t"
|
||||
"movw %%ax, %%ss\n\t"
|
||||
"movw %%cs:saved_sp, %%sp\n\t"
|
||||
/* Return via saved address */
|
||||
"jmp *%%cs:saved_retaddr\n\t" )
|
||||
: "=b" ( discard_b ), "=D" ( discard_D ),
|
||||
"=d" ( discard_d )
|
||||
: "b" ( segment ), "D" ( offset ),
|
||||
"d" ( drive )
|
||||
: "eax", "ecx", "esi", "ebp" );
|
||||
|
||||
DBG ( "Booted disk returned via INT 18 or 19\n" );
|
||||
|
||||
/* Unhook INTs 18 and 19 */
|
||||
unhook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
|
||||
&int18_vector );
|
||||
unhook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
|
||||
&int19_vector );
|
||||
|
||||
return -ECANCELED;
|
||||
}
|
334
src/arch/i386/image/eltorito.c
Normal file
334
src/arch/i386/image/eltorito.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* El Torito bootable ISO image format
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <bootsector.h>
|
||||
#include <int13.h>
|
||||
#include <gpxe/uaccess.h>
|
||||
#include <gpxe/image.h>
|
||||
#include <gpxe/segment.h>
|
||||
#include <gpxe/ramdisk.h>
|
||||
#include <gpxe/shutdown.h>
|
||||
|
||||
#define ISO9660_BLKSIZE 2048
|
||||
#define ELTORITO_VOL_DESC_OFFSET ( 17 * ISO9660_BLKSIZE )
|
||||
|
||||
/** An El Torito Boot Record Volume Descriptor */
|
||||
struct eltorito_vol_desc {
|
||||
/** Boot record indicator; must be 0 */
|
||||
uint8_t record_indicator;
|
||||
/** ISO-9660 identifier; must be "CD001" */
|
||||
uint8_t iso9660_id[5];
|
||||
/** Version, must be 1 */
|
||||
uint8_t version;
|
||||
/** Boot system indicator; must be "EL TORITO SPECIFICATION" */
|
||||
uint8_t system_indicator[32];
|
||||
/** Unused */
|
||||
uint8_t unused[32];
|
||||
/** Boot catalog sector */
|
||||
uint32_t sector;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An El Torito Boot Catalog Validation Entry */
|
||||
struct eltorito_validation_entry {
|
||||
/** Header ID; must be 1 */
|
||||
uint8_t header_id;
|
||||
/** Platform ID
|
||||
*
|
||||
* 0 = 80x86
|
||||
* 1 = PowerPC
|
||||
* 2 = Mac
|
||||
*/
|
||||
uint8_t platform_id;
|
||||
/** Reserved */
|
||||
uint16_t reserved;
|
||||
/** ID string */
|
||||
uint8_t id_string[24];
|
||||
/** Checksum word */
|
||||
uint16_t checksum;
|
||||
/** Signature; must be 0xaa55 */
|
||||
uint16_t signature;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A bootable entry in the El Torito Boot Catalog */
|
||||
struct eltorito_boot_entry {
|
||||
/** Boot indicator
|
||||
*
|
||||
* Must be @c ELTORITO_BOOTABLE for a bootable ISO image
|
||||
*/
|
||||
uint8_t indicator;
|
||||
/** Media type
|
||||
*
|
||||
*/
|
||||
uint8_t media_type;
|
||||
/** Load segment */
|
||||
uint16_t load_segment;
|
||||
/** System type */
|
||||
uint8_t filesystem;
|
||||
/** Unused */
|
||||
uint8_t reserved_a;
|
||||
/** Sector count */
|
||||
uint16_t length;
|
||||
/** Starting sector */
|
||||
uint32_t start;
|
||||
/** Unused */
|
||||
uint8_t reserved_b[20];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Boot indicator for a bootable ISO image */
|
||||
#define ELTORITO_BOOTABLE 0x88
|
||||
|
||||
/** El Torito media types */
|
||||
enum eltorito_media_type {
|
||||
/** No emulation */
|
||||
ELTORITO_NO_EMULATION = 0,
|
||||
};
|
||||
|
||||
struct image_type eltorito_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* Calculate 16-bit word checksum
|
||||
*
|
||||
* @v data Data to checksum
|
||||
* @v len Length (in bytes, must be even)
|
||||
* @ret sum Checksum
|
||||
*/
|
||||
static unsigned int word_checksum ( void *data, size_t len ) {
|
||||
uint16_t *words;
|
||||
uint16_t sum = 0;
|
||||
|
||||
for ( words = data ; len ; words++, len -= 2 ) {
|
||||
sum += *words;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute El Torito image
|
||||
*
|
||||
* @v image El Torito image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int eltorito_exec ( struct image *image ) {
|
||||
struct ramdisk ramdisk;
|
||||
struct int13_drive int13_drive;
|
||||
unsigned int load_segment = image->priv.ul;
|
||||
unsigned int load_offset = ( load_segment ? 0 : 0x7c00 );
|
||||
int rc;
|
||||
|
||||
memset ( &ramdisk, 0, sizeof ( ramdisk ) );
|
||||
init_ramdisk ( &ramdisk, image->data, image->len, ISO9660_BLKSIZE );
|
||||
|
||||
memset ( &int13_drive, 0, sizeof ( int13_drive ) );
|
||||
int13_drive.blockdev = &ramdisk.blockdev;
|
||||
register_int13_drive ( &int13_drive );
|
||||
|
||||
if ( ( rc = call_bootsector ( load_segment, load_offset,
|
||||
int13_drive.drive ) ) != 0 ) {
|
||||
DBGC ( image, "ElTorito %p boot failed: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = -ECANCELED; /* -EIMPOSSIBLE */
|
||||
err:
|
||||
unregister_int13_drive ( &int13_drive );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and verify El Torito Boot Record Volume Descriptor
|
||||
*
|
||||
* @v image El Torito file
|
||||
* @ret catalog_offset Offset of Boot Catalog
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int eltorito_read_voldesc ( struct image *image,
|
||||
unsigned long *catalog_offset ) {
|
||||
static const struct eltorito_vol_desc vol_desc_signature = {
|
||||
.record_indicator = 0,
|
||||
.iso9660_id = "CD001",
|
||||
.version = 1,
|
||||
.system_indicator = "EL TORITO SPECIFICATION",
|
||||
};
|
||||
struct eltorito_vol_desc vol_desc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < ( ELTORITO_VOL_DESC_OFFSET + ISO9660_BLKSIZE ) ) {
|
||||
DBGC ( image, "ElTorito %p too short\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Read and verify Boot Record Volume Descriptor */
|
||||
copy_from_user ( &vol_desc, image->data, ELTORITO_VOL_DESC_OFFSET,
|
||||
sizeof ( vol_desc ) );
|
||||
if ( memcmp ( &vol_desc, &vol_desc_signature,
|
||||
offsetof ( typeof ( vol_desc ), sector ) ) != 0 ) {
|
||||
DBGC ( image, "ElTorito %p invalid Boot Record Volume "
|
||||
"Descriptor\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
*catalog_offset = ( vol_desc.sector * ISO9660_BLKSIZE );
|
||||
|
||||
DBGC ( image, "ElTorito %p boot catalog at offset %#lx\n",
|
||||
image, *catalog_offset );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and verify El Torito Boot Catalog
|
||||
*
|
||||
* @v image El Torito file
|
||||
* @v catalog_offset Offset of Boot Catalog
|
||||
* @ret boot_entry El Torito boot entry
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int eltorito_read_catalog ( struct image *image,
|
||||
unsigned long catalog_offset,
|
||||
struct eltorito_boot_entry *boot_entry ) {
|
||||
struct eltorito_validation_entry validation_entry;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < ( catalog_offset + ISO9660_BLKSIZE ) ) {
|
||||
DBGC ( image, "ElTorito %p bad boot catalog offset %#lx\n",
|
||||
image, catalog_offset );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Read and verify the Validation Entry of the Boot Catalog */
|
||||
copy_from_user ( &validation_entry, image->data, catalog_offset,
|
||||
sizeof ( validation_entry ) );
|
||||
if ( word_checksum ( &validation_entry,
|
||||
sizeof ( validation_entry ) ) != 0 ) {
|
||||
DBGC ( image, "ElTorito %p bad Validation Entry checksum\n",
|
||||
image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Read and verify the Initial/Default entry */
|
||||
copy_from_user ( boot_entry, image->data,
|
||||
( catalog_offset + sizeof ( validation_entry ) ),
|
||||
sizeof ( *boot_entry ) );
|
||||
if ( boot_entry->indicator != ELTORITO_BOOTABLE ) {
|
||||
DBGC ( image, "ElTorito %p not bootable\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if ( boot_entry->media_type != ELTORITO_NO_EMULATION ) {
|
||||
DBGC ( image, "ElTorito %p cannot support media type %d\n",
|
||||
image, boot_entry->media_type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
DBGC ( image, "ElTorito %p media type %d segment %04x\n",
|
||||
image, boot_entry->media_type, boot_entry->load_segment );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load El Torito virtual disk image into memory
|
||||
*
|
||||
* @v image El Torito file
|
||||
* @v boot_entry El Torito boot entry
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int eltorito_load_disk ( struct image *image,
|
||||
struct eltorito_boot_entry *boot_entry ) {
|
||||
unsigned long start = ( boot_entry->start * ISO9660_BLKSIZE );
|
||||
unsigned long length = ( boot_entry->length * ISO9660_BLKSIZE );
|
||||
unsigned int load_segment;
|
||||
userptr_t buffer;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < ( start + length ) ) {
|
||||
DBGC ( image, "ElTorito %p virtual disk lies outside image\n",
|
||||
image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
DBGC ( image, "ElTorito %p virtual disk at %#lx+%#lx\n",
|
||||
image, start, length );
|
||||
|
||||
/* Calculate load address */
|
||||
load_segment = boot_entry->load_segment;
|
||||
buffer = real_to_user ( load_segment, ( load_segment ? 0 : 0x7c00 ) );
|
||||
|
||||
/* Verify and prepare segment */
|
||||
if ( ( rc = prep_segment ( buffer, length, length ) ) != 0 ) {
|
||||
DBGC ( image, "ElTorito %p could not prepare segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Copy image to segment */
|
||||
memcpy_user ( buffer, 0, image->data, start, length );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load El Torito image into memory
|
||||
*
|
||||
* @v image El Torito file
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int eltorito_load ( struct image *image ) {
|
||||
struct eltorito_boot_entry boot_entry;
|
||||
unsigned long bootcat_offset;
|
||||
int rc;
|
||||
|
||||
/* Read Boot Record Volume Descriptor, if present */
|
||||
if ( ( rc = eltorito_read_voldesc ( image, &bootcat_offset ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* This is an El Torito image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &eltorito_image_type;
|
||||
|
||||
/* Read Boot Catalog */
|
||||
if ( ( rc = eltorito_read_catalog ( image, bootcat_offset,
|
||||
&boot_entry ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Load Virtual Disk image */
|
||||
if ( ( rc = eltorito_load_disk ( image, &boot_entry ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Record load segment in image private data field */
|
||||
image->priv.ul = boot_entry.load_segment;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** El Torito image type */
|
||||
struct image_type eltorito_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "El Torito",
|
||||
.load = eltorito_load,
|
||||
.exec = eltorito_exec,
|
||||
};
|
12
src/arch/i386/include/bootsector.h
Normal file
12
src/arch/i386/include/bootsector.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _BOOTSECTOR_H
|
||||
#define _BOOTSECTOR_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86 bootsector image format
|
||||
*/
|
||||
|
||||
extern int call_bootsector ( unsigned int segment, unsigned int offset,
|
||||
unsigned int drive );
|
||||
|
||||
#endif /* _BOOTSECTOR_H */
|
@ -37,6 +37,8 @@ struct block_device;
|
||||
#define INT13_EXTENDED_WRITE 0x43
|
||||
/** Get extended drive parameters */
|
||||
#define INT13_GET_EXTENDED_PARAMETERS 0x48
|
||||
/** Get CD-ROM status / terminate emulation */
|
||||
#define INT13_CDROM_STATUS_TERMINATE 0x4b
|
||||
|
||||
/** @} */
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <realmode.h>
|
||||
#include <bios.h>
|
||||
#include <biosint.h>
|
||||
#include <bootsector.h>
|
||||
#include <int13.h>
|
||||
|
||||
/** @file
|
||||
@ -44,23 +45,6 @@ static struct segoff __text16 ( int13_vector );
|
||||
/** Assembly wrapper */
|
||||
extern void int13_wrapper ( void );
|
||||
|
||||
/** Vector for storing original INT 18 handler
|
||||
*
|
||||
* We do not chain to this vector, so there is no need to place it in
|
||||
* .text16.
|
||||
*/
|
||||
static struct segoff int18_vector;
|
||||
|
||||
/** Vector for storing original INT 19 handler
|
||||
*
|
||||
* We do not chain to this vector, so there is no need to place it in
|
||||
* .text16.
|
||||
*/
|
||||
static struct segoff int19_vector;
|
||||
|
||||
/** Restart point for INT 18 or 19 */
|
||||
extern void int13_exec_fail ( void );
|
||||
|
||||
/** List of registered emulated drives */
|
||||
static LIST_HEAD ( drives );
|
||||
|
||||
@ -114,6 +98,13 @@ static int int13_rw_sectors ( struct int13_drive *drive,
|
||||
unsigned int count;
|
||||
userptr_t buffer;
|
||||
|
||||
/* Validate blocksize */
|
||||
if ( blockdev->blksize != INT13_BLKSIZE ) {
|
||||
DBG ( "Invalid blocksize (%zd) for non-extended read/write\n",
|
||||
blockdev->blksize );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
|
||||
/* Calculate parameters */
|
||||
cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
|
||||
assert ( cylinder < drive->cylinders );
|
||||
@ -129,13 +120,6 @@ static int int13_rw_sectors ( struct int13_drive *drive,
|
||||
DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder,
|
||||
head, sector, lba, ix86->segs.es, ix86->regs.bx, count );
|
||||
|
||||
/* Validate blocksize */
|
||||
if ( blockdev->blksize != INT13_BLKSIZE ) {
|
||||
DBG ( "Invalid blocksize (%zd) for non-extended read/write\n",
|
||||
blockdev->blksize );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
|
||||
/* Read from / write to block device */
|
||||
if ( io ( blockdev, lba, count, buffer ) != 0 )
|
||||
return -INT13_STATUS_READ_ERROR;
|
||||
@ -333,6 +317,38 @@ static int int13_get_extended_parameters ( struct int13_drive *drive,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct int13_cdrom_specification {
|
||||
/** Size of packet in bytes */
|
||||
uint8_t size;
|
||||
/** Boot media type */
|
||||
uint8_t media_type;
|
||||
/** Drive number */
|
||||
uint8_t drive;
|
||||
};
|
||||
|
||||
/**
|
||||
* INT 13, 4b - Get CD-ROM status / terminate emulation
|
||||
*
|
||||
* @v drive Emulated drive
|
||||
* @v ds:si El Torito specification packet to fill in
|
||||
* @ret status Status code
|
||||
*/
|
||||
static int int13_cdrom_status_terminate ( struct int13_drive *drive,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
struct int13_cdrom_specification specification;
|
||||
|
||||
DBG ( "Get CD-ROM emulation parameters to %04x:%04x\n",
|
||||
ix86->segs.ds, ix86->regs.di );
|
||||
|
||||
memset ( &specification, 0, sizeof ( specification ) );
|
||||
specification.size = sizeof ( specification );
|
||||
specification.drive = drive->drive;
|
||||
|
||||
copy_to_real ( ix86->segs.ds, ix86->regs.si, &specification,
|
||||
sizeof ( specification ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* INT 13 handler
|
||||
*
|
||||
@ -346,7 +362,7 @@ static void int13 ( struct i386_all_regs *ix86 ) {
|
||||
if ( drive->drive != ix86->regs.dl )
|
||||
continue;
|
||||
|
||||
DBG ( "INT 13,%02x (%02x): ", command, drive->drive );
|
||||
DBG ( "INT 13,%04x (%02x): ", ix86->regs.ax, drive->drive );
|
||||
|
||||
switch ( command ) {
|
||||
case INT13_RESET:
|
||||
@ -379,6 +395,9 @@ static void int13 ( struct i386_all_regs *ix86 ) {
|
||||
case INT13_GET_EXTENDED_PARAMETERS:
|
||||
status = int13_get_extended_parameters ( drive, ix86 );
|
||||
break;
|
||||
case INT13_CDROM_STATUS_TERMINATE:
|
||||
status = int13_cdrom_status_terminate ( drive, ix86 );
|
||||
break;
|
||||
default:
|
||||
DBG ( "*** Unrecognised INT 13 ***\n" );
|
||||
status = -INT13_STATUS_INVALID;
|
||||
@ -398,6 +417,8 @@ static void int13 ( struct i386_all_regs *ix86 ) {
|
||||
|
||||
/* Set OF to indicate to wrapper not to chain this call */
|
||||
ix86->flags |= OF;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,6 +474,10 @@ static void guess_int13_geometry ( struct int13_drive *drive ) {
|
||||
unsigned long blocks_per_cyl;
|
||||
unsigned int i;
|
||||
|
||||
/* Don't even try when the blksize is invalid for C/H/S access */
|
||||
if ( drive->blockdev->blksize != INT13_BLKSIZE )
|
||||
return;
|
||||
|
||||
/* Scan through partition table and modify guesses for heads
|
||||
* and sectors_per_track if we find any used partitions.
|
||||
*/
|
||||
@ -564,6 +589,7 @@ void unregister_int13_drive ( struct int13_drive *drive ) {
|
||||
int int13_boot ( unsigned int drive ) {
|
||||
int status, signature;
|
||||
int discard_c, discard_d;
|
||||
int rc;
|
||||
|
||||
DBG ( "Booting from INT 13 drive %02x\n", drive );
|
||||
|
||||
@ -593,48 +619,11 @@ int int13_boot ( unsigned int drive ) {
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Hook INTs 18 and 19 to capture failure paths */
|
||||
hook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail,
|
||||
&int18_vector );
|
||||
hook_bios_interrupt ( 0x19, ( unsigned int ) int13_exec_fail,
|
||||
&int19_vector );
|
||||
/* Jump to boot sector */
|
||||
if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) {
|
||||
DBG ( "INT 13 drive %02x boot returned\n", drive );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Boot the loaded sector
|
||||
*
|
||||
* We assume that the boot sector may completely destroy our
|
||||
* real-mode stack, so we preserve everything we need in
|
||||
* static storage.
|
||||
*/
|
||||
__asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
|
||||
"popw %%cs:int13_saved_retaddr\n\t"
|
||||
/* Save stack pointer */
|
||||
"movw %%ss, %%ax\n\t"
|
||||
"movw %%ax, %%cs:int13_saved_ss\n\t"
|
||||
"movw %%sp, %%cs:int13_saved_sp\n\t"
|
||||
/* Jump to boot sector */
|
||||
"ljmp $0, $0x7c00\n\t"
|
||||
/* Preserved variables */
|
||||
"\nint13_saved_ss: .word 0\n\t"
|
||||
"\nint13_saved_sp: .word 0\n\t"
|
||||
"\nint13_saved_retaddr: .word 0\n\t"
|
||||
/* Boot failure return point */
|
||||
"\nint13_exec_fail:\n\t"
|
||||
/* Restore stack pointer */
|
||||
"movw %%cs:int13_saved_ss, %%ax\n\t"
|
||||
"movw %%ax, %%ss\n\t"
|
||||
"movw %%cs:int13_saved_sp, %%sp\n\t"
|
||||
/* Return via saved address */
|
||||
"jmp *%%cs:int13_saved_retaddr\n\t")
|
||||
: "=d" ( discard_d ) : "d" ( drive )
|
||||
: "eax", "ebx", "ecx", "esi", "edi", "ebp" );
|
||||
|
||||
DBG ( "Booted disk returned via INT 18 or 19\n" );
|
||||
|
||||
/* Unhook INTs 18 and 19 */
|
||||
unhook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail,
|
||||
&int18_vector );
|
||||
unhook_bios_interrupt ( 0x19, ( unsigned int ) int13_exec_fail,
|
||||
&int19_vector );
|
||||
|
||||
return -ECANCELED;
|
||||
return -ECANCELED; /* -EIMPOSSIBLE */
|
||||
}
|
||||
|
@ -143,6 +143,9 @@ REQUIRE_OBJECT ( script );
|
||||
#ifdef IMAGE_BZIMAGE
|
||||
REQUIRE_OBJECT ( bzimage );
|
||||
#endif
|
||||
#ifdef IMAGE_ELTORITO
|
||||
REQUIRE_OBJECT ( eltorito );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in all requested commands
|
||||
|
91
src/drivers/block/ramdisk.c
Normal file
91
src/drivers/block/ramdisk.c
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <gpxe/blockdev.h>
|
||||
#include <gpxe/ramdisk.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* RAM disks
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __attribute__ (( always_inline )) struct ramdisk *
|
||||
block_to_ramdisk ( struct block_device *blockdev ) {
|
||||
return container_of ( blockdev, struct ramdisk, blockdev );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read block
|
||||
*
|
||||
* @v blockdev Block device
|
||||
* @v block Block number
|
||||
* @v count Block count
|
||||
* @v buffer Data buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ramdisk_read ( struct block_device *blockdev, uint64_t block,
|
||||
unsigned long count, userptr_t buffer ) {
|
||||
struct ramdisk *ramdisk = block_to_ramdisk ( blockdev );
|
||||
unsigned long offset = ( block * blockdev->blksize );
|
||||
unsigned long length = ( count * blockdev->blksize );
|
||||
|
||||
DBGC ( ramdisk, "RAMDISK %p reading [%lx,%lx)\n",
|
||||
ramdisk, offset, length );
|
||||
|
||||
memcpy_user ( buffer, 0, ramdisk->data, offset, length );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write block
|
||||
*
|
||||
* @v blockdev Block device
|
||||
* @v block Block number
|
||||
* @v count Block count
|
||||
* @v buffer Data buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ramdisk_write ( struct block_device *blockdev, uint64_t block,
|
||||
unsigned long count, userptr_t buffer ) {
|
||||
struct ramdisk *ramdisk = block_to_ramdisk ( blockdev );
|
||||
unsigned long offset = ( block * blockdev->blksize );
|
||||
unsigned long length = ( count * blockdev->blksize );
|
||||
|
||||
DBGC ( ramdisk, "RAMDISK %p writing [%lx,%lx)\n",
|
||||
ramdisk, offset, length );
|
||||
|
||||
memcpy_user ( ramdisk->data, offset, buffer, 0, length );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_ramdisk ( struct ramdisk *ramdisk, userptr_t data, size_t len,
|
||||
unsigned int blksize ) {
|
||||
|
||||
if ( ! blksize )
|
||||
blksize = 512;
|
||||
|
||||
ramdisk->data = data;
|
||||
ramdisk->blockdev.read = ramdisk_read;
|
||||
ramdisk->blockdev.write = ramdisk_write;
|
||||
ramdisk->blockdev.blksize = blksize;
|
||||
ramdisk->blockdev.blocks = ( len / blksize );
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user