loader: bc_add can not use any other probes than ah=0x4b
CD boot is broken for some systems since bioscd and biosdisk merge. The issue is that we can not use anything else than int 13 ah=0x4b to query cd information. The patch does restore the same probe as was originally used in bioscd.c. Additionally extra buffer padding is used to avoid memory corruption caused by some systems. PR: 234031 Reported by: ultramage and others MFC after: 1 day
This commit is contained in:
parent
d9e9979c02
commit
b0af1e20e6
@ -98,6 +98,7 @@ struct specification_packet {
|
||||
uint16_t sp_sectorcount;
|
||||
uint16_t sp_cylsec;
|
||||
uint8_t sp_head;
|
||||
uint8_t sp_dummy[16]; /* Avoid memory corruption */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -372,53 +373,91 @@ cd_init(void)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Information from bootable CD-ROM.
|
||||
*/
|
||||
static int
|
||||
bd_get_diskinfo_cd(struct bdinfo *bd)
|
||||
{
|
||||
struct specification_packet bc_sp;
|
||||
int ret = -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 = bd->bd_unit;
|
||||
v86.ds = VTOPSEG(&bc_sp);
|
||||
v86.esi = VTOPOFF(&bc_sp);
|
||||
v86int();
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is the boot_drive, default to non-emulation bootable CD-ROM.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
struct specification_packet bc_sp;
|
||||
int nbcinfo = 0;
|
||||
|
||||
if (!STAILQ_EMPTY(&cdinfo))
|
||||
return (-1);
|
||||
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = DISK_BIOS;
|
||||
v86.eax = CMD_CD_GET_STATUS;
|
||||
v86.edx = biosdev;
|
||||
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);
|
||||
|
||||
bd->bd_flags = BD_CDROM;
|
||||
bd->bd_unit = biosdev;
|
||||
bd->bd_sectorsize = 2048;
|
||||
|
||||
/*
|
||||
* Ignore result from bd_int13probe(), we will use local
|
||||
* workaround below.
|
||||
*/
|
||||
(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 (bd_get_diskinfo_cd(bd) < 0) {
|
||||
free(bd);
|
||||
return (-1);
|
||||
}
|
||||
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 */
|
||||
if (bd->bd_sectors == 0)
|
||||
bd->bd_sectors = 4173824;
|
||||
|
||||
STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link);
|
||||
printf("BIOS CD is cd%d\n", nbcinfo);
|
||||
@ -499,22 +538,32 @@ 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))
|
||||
@ -526,20 +575,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;
|
||||
|
||||
@ -556,6 +605,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;
|
||||
@ -604,10 +657,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;
|
||||
@ -619,8 +668,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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user