176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2 of the 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * License, or any later version. 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, but 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT ANY WARRANTY; without even the implied warranty of 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Public License for more details. 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <limits.h> 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <byteswap.h> 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <assert.h> 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/list.h> 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/blockdev.h> 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/memmap.h> 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <realmode.h> 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <bios.h> 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <biosint.h> 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <bootsector.h> 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <int13.h> 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** @file 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13 emulation 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This module provides a mechanism for exporting block devices via 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the BIOS INT 13 disk interrupt interface. 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Vector for chaining to other INT 13 handlers */ 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct segoff __text16 ( int13_vector ); 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define int13_vector __use_text16 ( int13_vector ) 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Assembly wrapper */ 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern void int13_wrapper ( void ); 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** List of registered emulated drives */ 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic LIST_HEAD ( drives ); 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Number of BIOS drives 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note that this is the number of drives in the system as a whole 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (i.e. a mirror of the counter at 40:75), rather than a count of the 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * number of emulated drives. 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic uint8_t num_drives; 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Update BIOS drive count 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void int13_set_num_drives ( void ) { 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct int13_drive *drive; 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Get current drive count */ 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Ensure count is large enough to cover all of our emulated drives */ 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( drive, &drives, list ) { 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( num_drives <= ( drive->drive & 0x7f ) ) 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman num_drives = ( ( drive->drive & 0x7f ) + 1 ); 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update current drive count */ 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check number of drives 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void int13_check_num_drives ( void ) { 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t check_num_drives; 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES ); 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( check_num_drives != num_drives ) { 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int13_set_num_drives(); 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT13 fixing up number of drives from %d to %d\n", 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman check_num_drives, num_drives ); 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 00 - Reset disk system 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_reset ( struct int13_drive *drive __unused, 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 __unused ) { 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Reset drive\n" ); 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 01 - Get status of last operation 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_get_last_status ( struct int13_drive *drive, 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 __unused ) { 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Get status of last operation\n" ); 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return drive->last_status; 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Read / write sectors 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v al Number of sectors to read or write (must be nonzero) 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ch Low bits of cylinder number 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cl (bits 7:6) High bits of cylinder number 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cl (bits 5:0) Sector number 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v dh Head number 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v es:bx Data buffer 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v io Read / write method 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret al Number of sectors read or written 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_rw_sectors ( struct int13_drive *drive, 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86, 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ( * io ) ( struct block_device *blockdev, 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t block, 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long count, 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman userptr_t buffer ) ) { 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct block_device *blockdev = drive->blockdev; 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int cylinder, head, sector; 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long lba; 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int count; 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman userptr_t buffer; 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Validate blocksize */ 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( blockdev->blksize != INT13_BLKSIZE ) { 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Invalid blocksize (%zd) for non-extended read/write\n", 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blockdev->blksize ); 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -INT13_STATUS_INVALID; 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Calculate parameters */ 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch ); 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( cylinder < drive->cylinders ); 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman head = ix86->regs.dh; 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( head < drive->heads ); 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sector = ( ix86->regs.cl & 0x3f ); 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( ( sector >= 1 ) && ( sector <= drive->sectors_per_track ) ); 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lba = ( ( ( ( cylinder * drive->heads ) + head ) 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * drive->sectors_per_track ) + sector - 1 ); 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman count = ix86->regs.al; 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buffer = real_to_user ( ix86->segs.es, ix86->regs.bx ); 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder, 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman head, sector, lba, ix86->segs.es, ix86->regs.bx, count ); 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Read from / write to block device */ 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -INT13_STATUS_READ_ERROR; 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 02 - Read sectors 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v al Number of sectors to read (must be nonzero) 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ch Low bits of cylinder number 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cl (bits 7:6) High bits of cylinder number 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cl (bits 5:0) Sector number 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v dh Head number 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v es:bx Data buffer 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret al Number of sectors read 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_read_sectors ( struct int13_drive *drive, 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Read: " ); 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return int13_rw_sectors ( drive, ix86, drive->blockdev->op->read ); 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 03 - Write sectors 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v al Number of sectors to write (must be nonzero) 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ch Low bits of cylinder number 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cl (bits 7:6) High bits of cylinder number 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cl (bits 5:0) Sector number 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v dh Head number 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v es:bx Data buffer 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret al Number of sectors written 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_write_sectors ( struct int13_drive *drive, 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Write: " ); 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return int13_rw_sectors ( drive, ix86, drive->blockdev->op->write ); 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 08 - Get drive parameters 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret ch Low bits of maximum cylinder number 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret cl (bits 7:6) High bits of maximum cylinder number 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret cl (bits 5:0) Maximum sector number 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret dh Maximum head number 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret dl Number of drives 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_get_parameters ( struct int13_drive *drive, 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int max_cylinder = drive->cylinders - 1; 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int max_head = drive->heads - 1; 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int max_sector = drive->sectors_per_track; /* sic */ 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Get drive parameters\n" ); 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.ch = ( max_cylinder & 0xff ); 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector ); 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.dh = max_head; 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES ); 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 15 - Get disk type 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret ah Type code 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret cx:dx Sector count 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code / disk type 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_get_disk_type ( struct int13_drive *drive, 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t blocks; 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Get disk type\n" ); 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blocks = ( ( drive->blockdev->blocks <= 0xffffffffUL ) ? 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->blockdev->blocks : 0xffffffffUL ); 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.cx = ( blocks >> 16 ); 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.dx = ( blocks & 0xffff ); 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return INT13_DISK_TYPE_HDD; 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 41 - Extensions installation check 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v bx 0x55aa 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret bx 0xaa55 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret cx Extensions API support bitmap 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code / API version 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_extension_check ( struct int13_drive *drive __unused, 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ix86->regs.bx == 0x55aa ) { 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT 13 extensions installation check\n" ); 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.bx = 0xaa55; 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.cx = INT13_EXTENSION_LINEAR; 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return INT13_EXTENSION_VER_1_X; 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -INT13_STATUS_INVALID; 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Extended read / write 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ds:si Disk address packet 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v io Read / write method 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_extended_rw ( struct int13_drive *drive, 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86, 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ( * io ) ( struct block_device *blockdev, 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t block, 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long count, 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman userptr_t buffer ) ) { 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct block_device *blockdev = drive->blockdev; 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct int13_disk_address addr; 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t lba; 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long count; 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman userptr_t buffer; 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Read parameters from disk address structure */ 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, sizeof ( addr )); 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lba = addr.lba; 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman count = addr.count; 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset ); 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "LBA %#llx <-> %04x:%04x (count %ld)\n", (unsigned long long)lba, 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr.buffer.segment, addr.buffer.offset, count ); 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Read from / write to block device */ 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -INT13_STATUS_READ_ERROR; 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 42 - Extended read 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ds:si Disk address packet 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_extended_read ( struct int13_drive *drive, 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Extended read: " ); 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return int13_extended_rw ( drive, ix86, drive->blockdev->op->read ); 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 43 - Extended write 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ds:si Disk address packet 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_extended_write ( struct int13_drive *drive, 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Extended write: " ); 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return int13_extended_rw ( drive, ix86, drive->blockdev->op->write ); 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13, 48 - Get extended parameters 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ds:si Drive parameter table 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret status Status code 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int int13_get_extended_parameters ( struct int13_drive *drive, 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct i386_all_regs *ix86 ) { 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct int13_disk_parameters params = { 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .bufsize = sizeof ( params ), 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .flags = INT13_FL_DMA_TRANSPARENT, 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .cylinders = drive->cylinders, 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .heads = drive->heads, 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .sectors_per_track = drive->sectors_per_track, 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .sectors = drive->blockdev->blocks, 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .sector_size = drive->blockdev->blksize, 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman }; 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Get extended drive parameters to %04x:%04x\n", 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->segs.ds, ix86->regs.si ); 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman copy_to_real ( ix86->segs.ds, ix86->regs.si, ¶ms, 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sizeof ( params ) ); 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13 handler 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic __asmcall void int13 ( struct i386_all_regs *ix86 ) { 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int command = ix86->regs.ah; 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int bios_drive = ix86->regs.dl; 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct int13_drive *drive; 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check BIOS hasn't killed off our drive */ 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int13_check_num_drives(); 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( drive, &drives, list ) { 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( bios_drive != drive->drive ) { 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Remap any accesses to this drive's natural number */ 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( bios_drive == drive->natural_drive ) { 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT 13,%04x (%02x) remapped to " 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "(%02x)\n", ix86->regs.ax, 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bios_drive, drive->drive ); 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.dl = drive->drive; 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT 13,%04x (%02x): ", ix86->regs.ax, drive->drive ); 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch ( command ) { 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_RESET: 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_reset ( drive, ix86 ); 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_GET_LAST_STATUS: 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_get_last_status ( drive, ix86 ); 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_READ_SECTORS: 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_read_sectors ( drive, ix86 ); 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_WRITE_SECTORS: 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_write_sectors ( drive, ix86 ); 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_GET_PARAMETERS: 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_get_parameters ( drive, ix86 ); 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_GET_DISK_TYPE: 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_get_disk_type ( drive, ix86 ); 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_EXTENSION_CHECK: 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_extension_check ( drive, ix86 ); 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_EXTENDED_READ: 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_extended_read ( drive, ix86 ); 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_EXTENDED_WRITE: 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_extended_write ( drive, ix86 ); 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case INT13_GET_EXTENDED_PARAMETERS: 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = int13_get_extended_parameters ( drive, ix86 ); 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "*** Unrecognised INT 13 ***\n" ); 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = -INT13_STATUS_INVALID; 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Store status for INT 13,01 */ 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->last_status = status; 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Negative status indicates an error */ 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( status < 0 ) { 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = -status; 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT 13 returning failure status %x\n", status ); 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->flags &= ~CF; 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->regs.ah = status; 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set OF to indicate to wrapper not to chain this call */ 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ix86->flags |= OF; 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Hook INT 13 handler 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void hook_int13 ( void ) { 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Assembly wrapper to call int13(). int13() sets OF if we 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * should not chain to the previous handler. (The wrapper 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * clears CF and OF before calling int13()). 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __asm__ __volatile__ ( 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TEXT16_CODE ( "\nint13_wrapper:\n\t" 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Preserve %ax and %dx for future reference */ 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %%bp\n\t" 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movw %%sp, %%bp\n\t" 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %%ax\n\t" 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %%dx\n\t" 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear OF, set CF, call int13() */ 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "orb $0, %%al\n\t" 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "stc\n\t" 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushl %0\n\t" 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %%cs\n\t" 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "call prot_call\n\t" 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Chain if OF not set */ 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "jo 1f\n\t" 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushfw\n\t" 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "lcall *%%cs:int13_vector\n\t" 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "\n1:\n\t" 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Overwrite flags for iret */ 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushfw\n\t" 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "popw 6(%%bp)\n\t" 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fix up %dl: 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13,15 : do nothing 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 13,08 : load with number of drives 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * all others: restore original value 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "cmpb $0x15, -1(%%bp)\n\t" 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "je 2f\n\t" 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movb -4(%%bp), %%dl\n\t" 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "cmpb $0x08, -1(%%bp)\n\t" 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "jne 2f\n\t" 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %%ds\n\t" 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %1\n\t" 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "popw %%ds\n\t" 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movb %c2, %%dl\n\t" 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "popw %%ds\n\t" 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Return */ 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "\n2:\n\t" 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movw %%bp, %%sp\n\t" 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "popw %%bp\n\t" 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "iret\n\t" ) 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) ); 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &int13_vector ); 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Unhook INT 13 handler 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void unhook_int13 ( void ) { 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unhook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &int13_vector ); 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Guess INT 13 drive geometry 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Guesses the drive geometry by inspecting the partition table. 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void guess_int13_geometry ( struct int13_drive *drive ) { 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct master_boot_record mbr; 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct partition_table_entry *partition; 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int guessed_heads = 255; 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int guessed_sectors_per_track = 63; 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long blocks; 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long blocks_per_cyl; 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Don't even try when the blksize is invalid for C/H/S access */ 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( drive->blockdev->blksize != INT13_BLKSIZE ) 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Scan through partition table and modify guesses for heads 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and sectors_per_track if we find any used partitions. 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( drive->blockdev->op->read ( drive->blockdev, 0, 1, 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman virt_to_user ( &mbr ) ) == 0 ) { 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( i = 0 ; i < 4 ; i++ ) { 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman partition = &mbr.partitions[i]; 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! partition->type ) 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman guessed_heads = 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( PART_HEAD ( partition->chs_end ) + 1 ); 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman guessed_sectors_per_track = 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PART_SECTOR ( partition->chs_end ); 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Guessing C/H/S xx/%d/%d based on partition " 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "%d\n", guessed_heads, 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman guessed_sectors_per_track, ( i + 1 ) ); 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Could not read partition table to guess geometry\n" ); 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Apply guesses if no geometry already specified */ 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! drive->heads ) 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->heads = guessed_heads; 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! drive->sectors_per_track ) 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->sectors_per_track = guessed_sectors_per_track; 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! drive->cylinders ) { 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Avoid attempting a 64-bit divide on a 32-bit system */ 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blocks = ( ( drive->blockdev->blocks <= ULONG_MAX ) ? 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->blockdev->blocks : ULONG_MAX ); 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blocks_per_cyl = ( drive->heads * drive->sectors_per_track ); 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( blocks_per_cyl != 0 ); 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->cylinders = ( blocks / blocks_per_cyl ); 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( drive->cylinders > 1024 ) 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->cylinders = 1024; 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Register INT 13 emulated drive 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Registers the drive with the INT 13 emulation subsystem, and hooks 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the INT 13 interrupt vector (if not already hooked). 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The underlying block device must be valid. A drive number and 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * geometry will be assigned if left blank. 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid register_int13_drive ( struct int13_drive *drive ) { 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t num_drives; 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Give drive a default geometry if none specified */ 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman guess_int13_geometry ( drive ); 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Assign natural drive number */ 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->natural_drive = ( num_drives | 0x80 ); 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Assign drive number */ 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( drive->drive & 0xff ) == 0xff ) { 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Drive number == -1 => use natural drive number */ 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->drive = drive->natural_drive; 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Use specified drive number (+0x80 if necessary) */ 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->drive |= 0x80; 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S " 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "geometry %d/%d/%d\n", drive->drive, drive->natural_drive, 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive->cylinders, drive->heads, drive->sectors_per_track ); 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hook INT 13 vector if not already hooked */ 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( list_empty ( &drives ) ) 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hook_int13(); 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Add to list of emulated drives */ 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_add ( &drive->list, &drives ); 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update BIOS drive count */ 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int13_set_num_drives(); 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Unregister INT 13 emulated drive 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Emulated drive 63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Unregisters the drive from the INT 13 emulation subsystem. If this 63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is the last emulated drive, the INT 13 vector is unhooked (if 63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * possible). 63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid unregister_int13_drive ( struct int13_drive *drive ) { 63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Remove from list of emulated drives */ 63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_del ( &drive->list ); 64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Should adjust BIOS drive count, but it's difficult to do so 64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * reliably. 64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Unregistered INT13 drive %02x\n", drive->drive ); 64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Unhook INT 13 vector if no more drives */ 64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( list_empty ( &drives ) ) 64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unhook_int13(); 65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Attempt to boot from an INT 13 drive 65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v drive Drive number 65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This boots from the specified INT 13 drive by loading the Master 65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Boot Record to 0000:7c00 and jumping to it. INT 18 is hooked to 66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * capture an attempt by the MBR to boot the next device. (This is 66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the closest thing to a return path from an MBR). 66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note that this function can never return success, by definition. 66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint int13_boot ( unsigned int drive ) { 66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct memory_map memmap; 66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status, signature; 66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int discard_c, discard_d; 66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Booting from INT 13 drive %02x\n", drive ); 67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Use INT 13 to read the boot sector */ 67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t" 67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw $0\n\t" 67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "popw %%es\n\t" 67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "stc\n\t" 67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "sti\n\t" 67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "int $0x13\n\t" 68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "sti\n\t" /* BIOS bugs */ 68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "jc 1f\n\t" 68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorl %%eax, %%eax\n\t" 68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "\n1:\n\t" 68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movzwl %%es:0x7dfe, %%ebx\n\t" 68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "popw %%es\n\t" ) 68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman : "=a" ( status ), "=b" ( signature ), 68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "=c" ( discard_c ), "=d" ( discard_d ) 68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman : "a" ( 0x0201 ), "b" ( 0x7c00 ), 68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "c" ( 1 ), "d" ( drive ) ); 69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( status ) 69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EIO; 69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check signature is correct */ 69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( signature != be16_to_cpu ( 0x55aa ) ) { 69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Invalid disk signature %#04x (should be 0x55aa)\n", 69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cpu_to_be16 ( signature ) ); 69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOEXEC; 69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Dump out memory map prior to boot, if memmap debugging is 70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * enabled. Not required for program flow, but we have so 70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * many problems that turn out to be memory-map related that 70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it's worth doing. 70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman get_memmap ( &memmap ); 70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Jump to boot sector */ 70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) { 70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "INT 13 drive %02x boot returned: %s\n", 71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive, strerror ( rc ) ); 71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ECANCELED; /* -EIMPOSSIBLE */ 71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 716