|  | @@ -1,18 +1,25 @@
 | 
		
	
		
			
			| 1 | 1 |  #include "realmode.h"
 | 
		
	
		
			
			|  | 2 | +#include "isa_ids.h"
 | 
		
	
		
			
			|  | 3 | +#include "bios_disks.h"
 | 
		
	
		
			
			| 2 | 4 |  
 | 
		
	
		
			
			| 3 | 5 |  #define CF ( 1 << 0 )
 | 
		
	
		
			
			|  | 6 | +#define BIOS_DISK_NONE 0
 | 
		
	
		
			
			| 4 | 7 |  
 | 
		
	
		
			
			| 5 |  | -struct disk_sector {
 | 
		
	
		
			
			| 6 |  | -	char data[512];
 | 
		
	
		
			
			| 7 |  | -};
 | 
		
	
		
			
			|  | 8 | +/*
 | 
		
	
		
			
			|  | 9 | + * Ensure that there is sufficient space in the shared dev_bus
 | 
		
	
		
			
			|  | 10 | + * structure for a struct bios_disk_device.
 | 
		
	
		
			
			|  | 11 | + *
 | 
		
	
		
			
			|  | 12 | + */
 | 
		
	
		
			
			|  | 13 | +DEV_BUS( struct bios_disk_device, bios_disk_dev );
 | 
		
	
		
			
			|  | 14 | +static char bios_disk_magic[0]; /* guaranteed unique symbol */
 | 
		
	
		
			
			| 8 | 15 |  
 | 
		
	
		
			
			| 9 | 16 |  /*
 | 
		
	
		
			
			| 10 | 17 |   * Reset the disk system using INT 13,0.  Forces both hard disks and
 | 
		
	
		
			
			| 11 | 18 |   * floppy disks to seek back to track 0.
 | 
		
	
		
			
			| 12 | 19 |   *
 | 
		
	
		
			
			| 13 | 20 |   */
 | 
		
	
		
			
			| 14 |  | -static void disk_init ( void ) {
 | 
		
	
		
			
			| 15 |  | -	REAL_EXEC ( rm_disk_init,
 | 
		
	
		
			
			|  | 21 | +void bios_disk_init ( void ) {
 | 
		
	
		
			
			|  | 22 | +	REAL_EXEC ( rm_bios_disk_init,
 | 
		
	
		
			
			| 16 | 23 |  		    "sti\n\t"
 | 
		
	
		
			
			| 17 | 24 |  		    "xorw %%ax,%%ax\n\t"
 | 
		
	
		
			
			| 18 | 25 |  		    "movb $0x80,%%dl\n\t"
 | 
		
	
	
		
			
			|  | @@ -28,16 +35,19 @@ static void disk_init ( void ) {
 | 
		
	
		
			
			| 28 | 35 |  /*
 | 
		
	
		
			
			| 29 | 36 |   * Read a single sector from a disk using INT 13,2.
 | 
		
	
		
			
			| 30 | 37 |   *
 | 
		
	
		
			
			| 31 |  | - * Returns the BIOS status code (%ah) - 0 indicates success
 | 
		
	
		
			
			|  | 38 | + * Returns the BIOS status code (%ah) - 0 indicates success.
 | 
		
	
		
			
			| 32 | 39 |   *
 | 
		
	
		
			
			| 33 | 40 |   */
 | 
		
	
		
			
			| 34 |  | -static unsigned int pcbios_disk_read ( int drive, int cylinder, int head,
 | 
		
	
		
			
			| 35 |  | -				       int sector, struct disk_sector *buf ) {
 | 
		
	
		
			
			|  | 41 | +unsigned int bios_disk_read_once ( struct bios_disk_device *bios_disk,
 | 
		
	
		
			
			|  | 42 | +				   unsigned int cylinder,
 | 
		
	
		
			
			|  | 43 | +				   unsigned int head,
 | 
		
	
		
			
			|  | 44 | +				   unsigned int sector,
 | 
		
	
		
			
			|  | 45 | +				   struct bios_disk_sector *buf ) {
 | 
		
	
		
			
			| 36 | 46 |  	uint16_t basemem_buf, status, flags;
 | 
		
	
		
			
			| 37 | 47 |  	int discard_c, discard_d;
 | 
		
	
		
			
			| 38 | 48 |  
 | 
		
	
		
			
			| 39 | 49 |  	basemem_buf = BASEMEM_PARAMETER_INIT ( *buf );
 | 
		
	
		
			
			| 40 |  | -	REAL_EXEC ( rm_pcbios_disk_read,
 | 
		
	
		
			
			|  | 50 | +	REAL_EXEC ( rm_bios_disk_read,
 | 
		
	
		
			
			| 41 | 51 |  		    "sti\n\t"
 | 
		
	
		
			
			| 42 | 52 |  		    "movw $0x0201, %%ax\n\t" /* Read a single sector */
 | 
		
	
		
			
			| 43 | 53 |  		    "int $0x13\n\t"
 | 
		
	
	
		
			
			|  | @@ -46,14 +56,113 @@ static unsigned int pcbios_disk_read ( int drive, int cylinder, int head,
 | 
		
	
		
			
			| 46 | 56 |  		    "cli\n\t",
 | 
		
	
		
			
			| 47 | 57 |  		    4,
 | 
		
	
		
			
			| 48 | 58 |  		    OUT_CONSTRAINTS ( "=a" ( status ), "=b" ( flags ),
 | 
		
	
		
			
			| 49 |  | -				      "=c" ( discard_c ), "=d" ( discard_d ) ),
 | 
		
	
		
			
			|  | 59 | +				      "=c" ( discard_c ),
 | 
		
	
		
			
			|  | 60 | +				      "=d" ( discard_d ) ),
 | 
		
	
		
			
			| 50 | 61 |  		    IN_CONSTRAINTS ( "c" ( ( ( cylinder & 0xff ) << 8 ) |
 | 
		
	
		
			
			| 51 | 62 |  					   ( ( cylinder >> 8 ) & 0x3 ) |
 | 
		
	
		
			
			| 52 | 63 |  					   sector ),
 | 
		
	
		
			
			| 53 |  | -				     "d" ( ( head << 8 ) | drive ),
 | 
		
	
		
			
			|  | 64 | +				     "d" ( ( head << 8 ) | bios_disk->drive ),
 | 
		
	
		
			
			| 54 | 65 |  				     "b" ( basemem_buf ) ),
 | 
		
	
		
			
			| 55 | 66 |  		    CLOBBER ( "ebp", "esi", "edi" ) );
 | 
		
	
		
			
			| 56 | 67 |  	BASEMEM_PARAMETER_DONE ( *buf );
 | 
		
	
		
			
			| 57 | 68 |  
 | 
		
	
		
			
			| 58 |  | -	return ( flags & CF ) ? ( status >> 8 ) : 0;
 | 
		
	
		
			
			|  | 69 | +	return ( flags & CF ) ? ( status >> 8 ) : 0; 
 | 
		
	
		
			
			|  | 70 | +}
 | 
		
	
		
			
			|  | 71 | +
 | 
		
	
		
			
			|  | 72 | +/*
 | 
		
	
		
			
			|  | 73 | + * Fill in parameters for a BIOS disk device based on drive number
 | 
		
	
		
			
			|  | 74 | + *
 | 
		
	
		
			
			|  | 75 | + */
 | 
		
	
		
			
			|  | 76 | +static int fill_bios_disk_device ( struct bios_disk_device *bios_disk ) {
 | 
		
	
		
			
			|  | 77 | +	uint16_t type, flags;
 | 
		
	
		
			
			|  | 78 | +       
 | 
		
	
		
			
			|  | 79 | +	REAL_EXEC ( rm_bios_disk_exists,
 | 
		
	
		
			
			|  | 80 | +		    "sti\n\t"
 | 
		
	
		
			
			|  | 81 | +		    "movb $0x15, %%ah\n\t"
 | 
		
	
		
			
			|  | 82 | +		    "int $0x13\n\t"
 | 
		
	
		
			
			|  | 83 | +		    "pushfw\n\t"
 | 
		
	
		
			
			|  | 84 | +		    "popw %%dx\n\t"
 | 
		
	
		
			
			|  | 85 | +		    "cli\n\t",
 | 
		
	
		
			
			|  | 86 | +		    2,
 | 
		
	
		
			
			|  | 87 | +		    OUT_CONSTRAINTS ( "=a" ( type ), "=d" ( flags ) ),
 | 
		
	
		
			
			|  | 88 | +		    IN_CONSTRAINTS ( "d" ( bios_disk->drive ) ),
 | 
		
	
		
			
			|  | 89 | +		    CLOBBER ( "ebx", "ecx", "esi", "edi", "ebp" ) );
 | 
		
	
		
			
			|  | 90 | +
 | 
		
	
		
			
			|  | 91 | +	if ( ( flags & CF ) ||
 | 
		
	
		
			
			|  | 92 | +	     ( ( type >> 8 ) == BIOS_DISK_NONE ) )
 | 
		
	
		
			
			|  | 93 | +		return 0;
 | 
		
	
		
			
			|  | 94 | +
 | 
		
	
		
			
			|  | 95 | +	DBG ( "BIOS disk found valid drive %hhx\n", bios_disk->drive );
 | 
		
	
		
			
			|  | 96 | +	return 1;
 | 
		
	
		
			
			|  | 97 | +}
 | 
		
	
		
			
			|  | 98 | +
 | 
		
	
		
			
			|  | 99 | +/*
 | 
		
	
		
			
			|  | 100 | + * Find a BIOS disk device matching the specified driver
 | 
		
	
		
			
			|  | 101 | + *
 | 
		
	
		
			
			|  | 102 | + */
 | 
		
	
		
			
			|  | 103 | +int find_bios_disk_device ( struct bios_disk_device *bios_disk,
 | 
		
	
		
			
			|  | 104 | +			    struct bios_disk_driver *driver ) {
 | 
		
	
		
			
			|  | 105 | +
 | 
		
	
		
			
			|  | 106 | +	/* Initialise struct bios_disk if it's the first time it's been used.
 | 
		
	
		
			
			|  | 107 | +	 */
 | 
		
	
		
			
			|  | 108 | +	if ( bios_disk->magic != bios_disk_magic ) {
 | 
		
	
		
			
			|  | 109 | +		memset ( bios_disk, 0, sizeof ( *bios_disk ) );
 | 
		
	
		
			
			|  | 110 | +		bios_disk->magic = bios_disk_magic;
 | 
		
	
		
			
			|  | 111 | +	}
 | 
		
	
		
			
			|  | 112 | +
 | 
		
	
		
			
			|  | 113 | +	/* Iterate through all possible BIOS drives, starting where we
 | 
		
	
		
			
			|  | 114 | +	 * left off
 | 
		
	
		
			
			|  | 115 | +	 */
 | 
		
	
		
			
			|  | 116 | +	DBG ( "BIOS disk searching for device matching driver %s\n",
 | 
		
	
		
			
			|  | 117 | +	      driver->name );
 | 
		
	
		
			
			|  | 118 | +	do {
 | 
		
	
		
			
			|  | 119 | +		/* If we've already used this device, skip it */
 | 
		
	
		
			
			|  | 120 | +		if ( bios_disk->already_tried ) {
 | 
		
	
		
			
			|  | 121 | +			bios_disk->already_tried = 0;
 | 
		
	
		
			
			|  | 122 | +			continue;
 | 
		
	
		
			
			|  | 123 | +		}
 | 
		
	
		
			
			|  | 124 | +
 | 
		
	
		
			
			|  | 125 | +		/* Fill in device parameters */
 | 
		
	
		
			
			|  | 126 | +		if ( ! fill_bios_disk_device ( bios_disk ) ) {
 | 
		
	
		
			
			|  | 127 | +			continue;
 | 
		
	
		
			
			|  | 128 | +		}
 | 
		
	
		
			
			|  | 129 | +
 | 
		
	
		
			
			|  | 130 | +		/* Compare against driver's valid ID range */
 | 
		
	
		
			
			|  | 131 | +		if ( ( bios_disk->drive >= driver->min_drive ) &&
 | 
		
	
		
			
			|  | 132 | +		     ( bios_disk->drive <= driver->max_drive ) ) {
 | 
		
	
		
			
			|  | 133 | +			driver->fill_drive_name ( bios_disk->drive,
 | 
		
	
		
			
			|  | 134 | +						  bios_disk->name );
 | 
		
	
		
			
			|  | 135 | +			DBG ( "BIOS_DISK found drive %hhx (\"%s\") "
 | 
		
	
		
			
			|  | 136 | +			      "matching driver %s\n",
 | 
		
	
		
			
			|  | 137 | +			      bios_disk->drive, bios_disk->name,
 | 
		
	
		
			
			|  | 138 | +			      driver->name );
 | 
		
	
		
			
			|  | 139 | +			bios_disk->already_tried = 1;
 | 
		
	
		
			
			|  | 140 | +			return 1;
 | 
		
	
		
			
			|  | 141 | +		}
 | 
		
	
		
			
			|  | 142 | +	} while ( ++bios_disk->drive );
 | 
		
	
		
			
			|  | 143 | +
 | 
		
	
		
			
			|  | 144 | +	/* No device found */
 | 
		
	
		
			
			|  | 145 | +	DBG ( "BIOS disk found no device matching driver %s\n", driver->name );
 | 
		
	
		
			
			|  | 146 | +	return 0;
 | 
		
	
		
			
			|  | 147 | +}
 | 
		
	
		
			
			|  | 148 | +
 | 
		
	
		
			
			|  | 149 | +/*
 | 
		
	
		
			
			|  | 150 | + * Find the next MCA device that can be used to boot using the
 | 
		
	
		
			
			|  | 151 | + * specified driver.
 | 
		
	
		
			
			|  | 152 | + *
 | 
		
	
		
			
			|  | 153 | + */
 | 
		
	
		
			
			|  | 154 | +int find_bios_disk_boot_device ( struct dev *dev,
 | 
		
	
		
			
			|  | 155 | +				 struct bios_disk_driver *driver ) {
 | 
		
	
		
			
			|  | 156 | +	struct bios_disk_device *bios_disk
 | 
		
	
		
			
			|  | 157 | +		= ( struct bios_disk_device * ) dev->bus;
 | 
		
	
		
			
			|  | 158 | +
 | 
		
	
		
			
			|  | 159 | +	if ( ! find_bios_disk_device ( bios_disk, driver ) )
 | 
		
	
		
			
			|  | 160 | +		return 0;
 | 
		
	
		
			
			|  | 161 | +
 | 
		
	
		
			
			|  | 162 | +	dev->name = bios_disk->name;
 | 
		
	
		
			
			|  | 163 | +	dev->devid.bus_type = ISA_BUS_TYPE;
 | 
		
	
		
			
			|  | 164 | +	dev->devid.vendor_id = ISA_VENDOR ( 'D', 'S', 'K' );
 | 
		
	
		
			
			|  | 165 | +	dev->devid.device_id = bios_disk->drive;
 | 
		
	
		
			
			|  | 166 | +
 | 
		
	
		
			
			|  | 167 | +	return 1;
 | 
		
	
		
			
			| 59 | 168 |  }
 |