summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2020-02-02 20:37:22 +0200
committerToomas Soome <tsoome@me.com>2020-02-03 16:26:33 +0200
commit83bba2b4a81b05183e2f81f5601e23cba9972fad (patch)
treefb56f2dec44b60fe5ce480125153d77a59f3d1d3
parent8a2b682e57a046b828f37bcde1776f131ef4629f (diff)
downloadillumos-joyent-83bba2b4a81b05183e2f81f5601e23cba9972fad.tar.gz
12272 loader: bc_add can not use any other probes than ah=0x4b
Reviewed by: Alexander Eremin <a.eremin@nexenta.com> Reviewed by: Matthias Scheler <mscheler@tintri.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/boot/Makefile.version2
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/biosdisk.c148
2 files changed, 98 insertions, 52 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version
index f11337041e..b4fb4691f4 100644
--- a/usr/src/boot/Makefile.version
+++ b/usr/src/boot/Makefile.version
@@ -33,4 +33,4 @@ LOADER_VERSION = 1.1
# Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
# The version is processed from left to right, the version number can only
# be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2020.01.17.1
+BOOT_VERSION = $(LOADER_VERSION)-2020.02.02.1
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
index 3d1ab645d5..343b8b0df9 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
+++ b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
@@ -97,7 +97,8 @@ struct specification_packet {
uint16_t sp_sectorcount;
uint16_t sp_cylsec;
uint8_t sp_head;
-};
+ uint8_t sp_dummy[16]; /* Avoid memory corruption */
+} __packed;
/*
* List of BIOS devices, translation from disk unit number to
@@ -367,54 +368,92 @@ cd_init(void)
return (0);
}
-int
-bc_add(int biosdev)
+/*
+ * Information from bootable CD-ROM.
+ */
+static int
+bd_get_diskinfo_cd(struct bdinfo *bd)
{
- bdinfo_t *bd;
struct specification_packet bc_sp;
- int nbcinfo = 0;
+ int ret = -1;
- if (!STAILQ_EMPTY(&cdinfo))
- return (-1);
+ (void) memset(&bc_sp, 0, sizeof (bc_sp));
+ /* Set sp_size as per specification. */
+ bc_sp.sp_size = sizeof (bc_sp) - sizeof (bc_sp.sp_dummy);
v86.ctl = V86_FLAGS;
v86.addr = DISK_BIOS;
v86.eax = CMD_CD_GET_STATUS;
- v86.edx = biosdev;
+ v86.edx = bd->bd_unit;
v86.ds = VTOPSEG(&bc_sp);
v86.esi = VTOPOFF(&bc_sp);
v86int();
- if ((v86.eax & 0xff00) != 0)
- return (-1);
- if ((bd = calloc(1, sizeof (*bd))) == NULL)
- return (-1);
+ if ((v86.eax & 0xff00) == 0 &&
+ bc_sp.sp_drive == bd->bd_unit) {
+ bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) +
+ ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1;
+ bd->bd_sec = bc_sp.sp_cylsec & 0x3f;
+ bd->bd_hds = bc_sp.sp_head + 1;
+ bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
- bd->bd_flags = BD_CDROM;
- bd->bd_unit = biosdev;
- bd->bd_sectorsize = 2048;
+ if (bc_sp.sp_bootmedia & 0x0F) {
+ /* Floppy or hard-disk emulation */
+ bd->bd_sectorsize = BIOSDISK_SECSIZE;
+ return (-1);
+ } else {
+ bd->bd_sectorsize = 2048;
+ bd->bd_flags = BD_MODEEDD | BD_CDROM;
+ ret = 0;
+ }
+ }
/*
- * Ignore result from bd_int13probe(), we will use local
- * workaround below.
+ * If this is the boot_drive, default to non-emulation bootable CD-ROM.
*/
- (void) bd_int13probe(bd);
-
- if (bd->bd_cyl == 0) {
- bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) +
- ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1;
+ if (ret != 0 && bd->bd_unit >= 0x88) {
+ bd->bd_cyl = 0;
+ bd->bd_hds = 1;
+ bd->bd_sec = 15;
+ bd->bd_sectorsize = 2048;
+ bd->bd_flags = BD_MODEEDD | BD_CDROM;
+ bd->bd_sectors = 0;
+ ret = 0;
}
- if (bd->bd_hds == 0)
- bd->bd_hds = bc_sp.sp_head + 1;
- if (bd->bd_sec == 0)
- bd->bd_sec = bc_sp.sp_cylsec & 0x3f;
- if (bd->bd_sectors == 0)
- bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
- /* Still no size? use 7.961GB */
+ /*
+ * Note we can not use bd_get_diskinfo_ext() nor bd_get_diskinfo_std()
+ * here - some systems do get hung with those.
+ */
+ /*
+ * Still no size? use 7.961GB. The size does not really matter
+ * as long as it is reasonably large to make our reads to pass
+ * the sector count check.
+ */
if (bd->bd_sectors == 0)
bd->bd_sectors = 4173824;
+ return (ret);
+}
+
+int
+bc_add(int biosdev)
+{
+ bdinfo_t *bd;
+ int nbcinfo = 0;
+
+ if (!STAILQ_EMPTY(&cdinfo))
+ return (-1);
+
+ if ((bd = calloc(1, sizeof (*bd))) == NULL)
+ return (-1);
+
+ bd->bd_unit = biosdev;
+ if (bd_get_diskinfo_cd(bd) < 0) {
+ free(bd);
+ return (-1);
+ }
+
STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link);
printf("BIOS CD is cd%d\n", nbcinfo);
nbcinfo++;
@@ -494,22 +533,31 @@ bd_get_diskinfo_std(struct bdinfo *bd)
/*
* Read EDD info. Return 0 on success, error otherwise.
+ *
+ * Avoid stack corruption on some systems by adding extra bytes to
+ * params block.
*/
static int
bd_get_diskinfo_ext(struct bdinfo *bd)
{
- struct edd_params params;
+ struct disk_params {
+ struct edd_params head;
+ struct edd_device_path_v3 device_path;
+ uint8_t dummy[16];
+ } __packed dparams;
+ struct edd_params *params;
uint64_t total;
+ params = &dparams.head;
/* Get disk params */
- bzero(&params, sizeof (params));
- params.len = sizeof (params);
+ bzero(&dparams, sizeof (dparams));
+ params->len = sizeof (struct edd_params_v3);
v86.ctl = V86_FLAGS;
v86.addr = DISK_BIOS;
v86.eax = CMD_EXT_PARAM;
v86.edx = bd->bd_unit;
- v86.ds = VTOPSEG(&params);
- v86.esi = VTOPOFF(&params);
+ v86.ds = VTOPSEG(&dparams);
+ v86.esi = VTOPOFF(&dparams);
v86int();
if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
@@ -521,20 +569,20 @@ bd_get_diskinfo_ext(struct bdinfo *bd)
* powerof2(params.sector_size).
* 16K is largest read buffer we can use at this time.
*/
- if (params.sector_size >= 512 &&
- params.sector_size <= 16384 &&
- (params.sector_size % BIOSDISK_SECSIZE) == 0)
- bd->bd_sectorsize = params.sector_size;
+ if (params->sector_size >= 512 &&
+ params->sector_size <= 16384 &&
+ (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;
+ bd->bd_cyl = params->cylinders;
+ bd->bd_hds = params->heads;
+ bd->bd_sec = params->sectors_per_track;
- if (params.sectors != 0) {
- total = params.sectors;
+ if (params->sectors != 0) {
+ total = params->sectors;
} else {
- total = (uint64_t)params.cylinders *
- params.heads * params.sectors_per_track;
+ total = (uint64_t)params->cylinders *
+ params->heads * params->sectors_per_track;
}
bd->bd_sectors = total;
@@ -551,6 +599,10 @@ bd_int13probe(bdinfo_t *bd)
bd->bd_flags &= ~BD_NO_MEDIA;
+ if ((bd->bd_flags & BD_CDROM) != 0) {
+ return (bd_get_diskinfo_cd(bd) == 0);
+ }
+
edd = bd_check_extensions(bd->bd_unit);
if (edd == 0)
bd->bd_flags |= BD_MODEINT13;
@@ -599,10 +651,6 @@ bd_int13probe(bdinfo_t *bd)
}
if (ret != 0) {
- /* CD is special case, bc_add() has its own fallback. */
- if ((bd->bd_flags & BD_CDROM) != 0)
- return (true);
-
if (bd->bd_sectors != 0 && edd != 0) {
bd->bd_sec = 63;
bd->bd_hds = 255;
@@ -614,8 +662,6 @@ bd_int13probe(bdinfo_t *bd)
if ((bd->bd_flags & BD_FLOPPY) != 0)
dv_name = biosfd.dv_name;
- else if ((bd->bd_flags & BD_CDROM) != 0)
- dv_name = bioscd.dv_name;
else
dv_name = bioshd.dv_name;