Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152705783
D17667.id49835.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D17667.id49835.diff
View Options
Index: head/stand/i386/libi386/biosdisk.c
===================================================================
--- head/stand/i386/libi386/biosdisk.c
+++ head/stand/i386/libi386/biosdisk.c
@@ -43,7 +43,6 @@
#include <stand.h>
#include <machine/bootinfo.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <bootstrap.h>
#include <btxv86.h>
@@ -81,8 +80,10 @@
#define BD_MODEINT13 0x0000
#define BD_MODEEDD1 0x0001
#define BD_MODEEDD3 0x0002
+#define BD_MODEEDD (BD_MODEEDD1 | BD_MODEEDD3)
#define BD_MODEMASK 0x0003
#define BD_FLOPPY 0x0004
+#define BD_NO_MEDIA 0x0008
int bd_type; /* BIOS 'drive type' (floppy only) */
uint16_t bd_sectorsize; /* Sector size */
uint64_t bd_sectors; /* Disk size */
@@ -188,60 +189,83 @@
}
/*
- * Try to detect a device supported by the legacy int13 BIOS
+ * Return EDD version or 0 if EDD is not supported on this drive.
*/
static int
-bd_int13probe(struct bdinfo *bd)
+bd_check_extensions(int unit)
{
- struct edd_params params;
- int ret = 1; /* assume success */
+ /* Determine if we can use EDD with this device. */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x4100;
+ v86.edx = unit;
+ v86.ebx = 0x55aa;
+ v86int();
+ if (V86_CY(v86.efl) || /* carry set */
+ (v86.ebx & 0xffff) != 0xaa55) /* signature */
+ return (0);
+
+ /* extended disk access functions (AH=42h-44h,47h,48h) supported */
+ if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
+ return (0);
+
+ return ((v86.eax >> 8) & 0xff);
+}
+
+static void
+bd_reset_disk(int unit)
+{
+ /* reset disk */
v86.ctl = V86_FLAGS;
v86.addr = 0x13;
+ v86.eax = 0;
+ v86.edx = unit;
+ v86int();
+}
+
+/*
+ * Read CHS info. Return 0 on success, error otherwise.
+ */
+static int
+bd_get_diskinfo_std(struct bdinfo *bd)
+{
+ bzero(&v86, sizeof(v86));
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
v86.eax = 0x800;
v86.edx = bd->bd_unit;
v86int();
- /* Don't error out if we get bad sector number, try EDD as well */
- if (V86_CY(v86.efl) || /* carry set */
- (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */
- return (0); /* skip device */
+ if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
+ return ((v86.eax & 0xff00) >> 8);
- if ((v86.ecx & 0x3f) == 0) /* absurd sector number */
- ret = 0; /* set error */
+ /* return custom error on absurd sector number */
+ if ((v86.ecx & 0x3f) == 0)
+ return (0x60);
- /* Convert max cyl # -> # of cylinders */
bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
/* Convert max head # -> # of heads */
bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1;
bd->bd_sec = v86.ecx & 0x3f;
- bd->bd_type = v86.ebx & 0xff;
- bd->bd_flags |= BD_MODEINT13;
+ bd->bd_type = v86.ebx;
+ bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
- /* Calculate sectors count from the geometry */
- bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec;
- bd->bd_sectorsize = BIOSDISK_SECSIZE;
- DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
- bd->bd_hds, bd->bd_sec);
+ return (0);
+}
- /* Determine if we can use EDD with this device. */
- v86.ctl = V86_FLAGS;
- v86.addr = 0x13;
- v86.eax = 0x4100;
- v86.edx = bd->bd_unit;
- v86.ebx = 0x55aa;
- v86int();
- if (V86_CY(v86.efl) || /* carry set */
- (v86.ebx & 0xffff) != 0xaa55 || /* signature */
- (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
- return (ret); /* return code from int13 AH=08 */
+/*
+ * Read EDD info. Return 0 on success, error otherwise.
+ */
+static int
+bd_get_diskinfo_ext(struct bdinfo *bd)
+{
+ struct edd_params params;
+ uint64_t total;
- /* EDD supported */
- bd->bd_flags |= BD_MODEEDD1;
- if ((v86.eax & 0xff00) >= 0x3000)
- bd->bd_flags |= BD_MODEEDD3;
/* Get disk params */
- params.len = sizeof(struct edd_params);
+ bzero(¶ms, sizeof(params));
+ params.len = sizeof(params);
v86.ctl = V86_FLAGS;
v86.addr = 0x13;
v86.eax = 0x4800;
@@ -249,37 +273,120 @@
v86.ds = VTOPSEG(¶ms);
v86.esi = VTOPOFF(¶ms);
v86int();
- if (!V86_CY(v86.efl)) {
- uint64_t total;
- /*
- * Sector size must be a multiple of 512 bytes.
- * An alternate test would be to check power of 2,
- * powerof2(params.sector_size).
- * 4K is largest read buffer we can use at this time.
- */
- if (params.sector_size >= 512 &&
- params.sector_size <= 4096 &&
- (params.sector_size % BIOSDISK_SECSIZE) == 0)
- bd->bd_sectorsize = params.sector_size;
+ if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
+ return ((v86.eax & 0xff00) >> 8);
- total = bd->bd_sectorsize * params.sectors;
- if (params.sectors != 0) {
- /* Only update if we did not overflow. */
- if (total > params.sectors)
- bd->bd_sectors = params.sectors;
- }
+ /*
+ * Sector size must be a multiple of 512 bytes.
+ * An alternate test would be to check power of 2,
+ * powerof2(params.sector_size).
+ * 4K is largest read buffer we can use at this time.
+ */
+ if (params.sector_size >= 512 &&
+ params.sector_size <= 4096 &&
+ (params.sector_size % BIOSDISK_SECSIZE) == 0)
+ bd->bd_sectorsize = params.sector_size;
+ bd->bd_cyl = params.cylinders;
+ bd->bd_hds = params.heads;
+ bd->bd_sec = params.sectors_per_track;
+
+ if (params.sectors != 0) {
+ total = params.sectors;
+ } else {
total = (uint64_t)params.cylinders *
params.heads * params.sectors_per_track;
- if (total > 0 && bd->bd_sectors > total)
- bd->bd_sectors = total;
+ }
+ bd->bd_sectors = total;
- ret = 1;
+ return (0);
+}
+
+/*
+ * Try to detect a device supported by the legacy int13 BIOS
+ */
+static int
+bd_int13probe(struct bdinfo *bd)
+{
+ int edd;
+ int ret;
+
+ bd->bd_flags &= ~BD_NO_MEDIA;
+
+ edd = bd_check_extensions(bd->bd_unit);
+ if (edd == 0)
+ bd->bd_flags |= BD_MODEINT13;
+ else if (edd < 0x30)
+ bd->bd_flags |= BD_MODEEDD1;
+ else
+ bd->bd_flags |= BD_MODEEDD3;
+
+ /* Default sector size */
+ bd->bd_sectorsize = BIOSDISK_SECSIZE;
+
+ /*
+ * Test if the floppy device is present, so we can avoid receiving
+ * bogus information from bd_get_diskinfo_std().
+ */
+ if (bd->bd_unit < 0x80) {
+ /* reset disk */
+ bd_reset_disk(bd->bd_unit);
+
+ /* Get disk type */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x1500;
+ v86.edx = bd->bd_unit;
+ v86int();
+ if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0)
+ return (0);
}
- DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u",
- bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize);
- return (ret);
+
+ ret = 1;
+ if (edd != 0)
+ ret = bd_get_diskinfo_ext(bd);
+ if (ret != 0 || bd->bd_sectors == 0)
+ ret = bd_get_diskinfo_std(bd);
+
+ if (ret != 0 && bd->bd_unit < 0x80) {
+ /* Set defaults for 1.44 floppy */
+ bd->bd_cyl = 80;
+ bd->bd_hds = 2;
+ bd->bd_sec = 18;
+ bd->bd_type = 4;
+ bd->bd_sectors = 2880;
+ /* Since we are there, there most likely is no media */
+ bd->bd_flags |= BD_NO_MEDIA;
+ ret = 0;
+ }
+
+ if (ret != 0) {
+ if (bd->bd_sectors != 0 && edd != 0) {
+ bd->bd_sec = 63;
+ bd->bd_hds = 255;
+ bd->bd_cyl =
+ (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) /
+ bd->bd_sec * bd->bd_hds;
+ } else {
+ printf("Can not get information about %s unit %#x\n",
+ biosdisk.dv_name, bd->bd_unit);
+ return (0);
+ }
+ }
+
+ if (bd->bd_sec == 0)
+ bd->bd_sec = 63;
+ if (bd->bd_hds == 0)
+ bd->bd_hds = 255;
+
+ if (bd->bd_sectors == 0)
+ bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
+
+ DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
+ bd->bd_hds, bd->bd_sec);
+
+ return (1);
}
/*
@@ -301,9 +408,11 @@
for (i = 0; i < nbdinfo; i++) {
snprintf(line, sizeof(line),
- " disk%d: BIOS drive %c (%ju X %u):\n", i,
+ " disk%d: BIOS drive %c (%s%ju X %u):\n", i,
(bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit):
('C' + bdinfo[i].bd_unit - 0x80),
+ (bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ?
+ "no media, " : "",
(uintmax_t)bdinfo[i].bd_sectors,
bdinfo[i].bd_sectorsize);
if ((ret = pager_output(line)) != 0)
@@ -351,6 +460,11 @@
if (dev->dd.d_unit < 0 || dev->dd.d_unit >= nbdinfo)
return (EIO);
+
+ if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) {
+ if (!bd_int13probe(&BD(dev)))
+ return (EIO);
+ }
BD(dev).bd_open++;
if (BD(dev).bd_bcache == NULL)
BD(dev).bd_bcache = bcache_allocate();
@@ -499,7 +613,7 @@
* partition.
*/
if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
- /* DIOCGMEDIASIZE returns bytes. */
+ /* DIOCGMEDIASIZE does return bytes. */
disk_blocks /= BD(dev).bd_sectorsize;
} else {
/* We should not get here. Just try to survive. */
@@ -685,29 +799,33 @@
if (dowrite == BD_RD && dblk >= 0x100000000)
bd_io_workaround(dev);
for (retry = 0; retry < 3; retry++) {
- /* if retrying, reset the drive */
- if (retry > 0) {
- v86.ctl = V86_FLAGS;
- v86.addr = 0x13;
- v86.eax = 0;
- v86.edx = BD(dev).bd_unit;
- v86int();
- }
-
- if (BD(dev).bd_flags & BD_MODEEDD1)
+ if (BD(dev).bd_flags & BD_MODEEDD)
result = bd_edd_io(dev, dblk, blks, dest, dowrite);
else
result = bd_chs_io(dev, dblk, blks, dest, dowrite);
- if (result == 0)
+ if (result == 0) {
+ if (BD(dev).bd_flags & BD_NO_MEDIA)
+ BD(dev).bd_flags &= ~BD_NO_MEDIA;
break;
+ }
+
+ bd_reset_disk(BD(dev).bd_unit);
+
+ /*
+ * Error codes:
+ * 20h controller failure
+ * 31h no media in drive (IBM/MS INT 13 extensions)
+ * 80h no media in drive, VMWare (Fusion)
+ * There is no reason to repeat the IO with errors above.
+ */
+ if (result == 0x20 || result == 0x31 || result == 0x80) {
+ BD(dev).bd_flags |= BD_NO_MEDIA;
+ break;
+ }
}
- /*
- * 0x20 - Controller failure. This is common error when the
- * media is not present.
- */
- if (result != 0 && result != 0x20) {
+ if (result != 0 && (BD(dev).bd_flags & BD_NO_MEDIA) == 0) {
if (dowrite == BD_WR) {
printf("%s%d: Write %d sector(s) from %p (0x%x) "
"to %lld: 0x%x\n", dev->dd.d_dev->dv_name,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 17, 3:05 PM (3 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31665974
Default Alt Text
D17667.id49835.diff (9 KB)
Attached To
Mode
D17667: loader: issue edd probe before legacy ah=08 and detect no media
Attached
Detach File
Event Timeline
Log In to Comment