diff options
author | Toomas Soome <tsoome@me.com> | 2020-02-02 20:37:22 +0200 |
---|---|---|
committer | Toomas Soome <tsoome@me.com> | 2020-02-03 16:26:33 +0200 |
commit | 83bba2b4a81b05183e2f81f5601e23cba9972fad (patch) | |
tree | fb56f2dec44b60fe5ce480125153d77a59f3d1d3 | |
parent | 8a2b682e57a046b828f37bcde1776f131ef4629f (diff) | |
download | illumos-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.version | 2 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/biosdisk.c | 148 |
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(¶ms, 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(¶ms); - v86.esi = VTOPOFF(¶ms); + 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; |