From owner-svn-src-stable@freebsd.org Tue Feb 4 07:15:34 2020 Return-Path: Delivered-To: svn-src-stable@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 2866023E472; Tue, 4 Feb 2020 07:15:34 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 48BbZG0M20z4mPV; Tue, 4 Feb 2020 07:15:34 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 06E02DFEF; Tue, 4 Feb 2020 07:15:34 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 0147FXRd003927; Tue, 4 Feb 2020 07:15:33 GMT (envelope-from tsoome@FreeBSD.org) Received: (from tsoome@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 0147FXxt003926; Tue, 4 Feb 2020 07:15:33 GMT (envelope-from tsoome@FreeBSD.org) Message-Id: <202002040715.0147FXxt003926@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tsoome set sender to tsoome@FreeBSD.org using -f From: Toomas Soome Date: Tue, 4 Feb 2020 07:15:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r357495 - stable/12/stand/i386/libi386 X-SVN-Group: stable-12 X-SVN-Commit-Author: tsoome X-SVN-Commit-Paths: stable/12/stand/i386/libi386 X-SVN-Commit-Revision: 357495 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Feb 2020 07:15:34 -0000 Author: tsoome Date: Tue Feb 4 07:15:33 2020 New Revision: 357495 URL: https://svnweb.freebsd.org/changeset/base/357495 Log: MFC r357442: 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 Modified: stable/12/stand/i386/libi386/biosdisk.c Directory Properties: stable/12/ (props changed) Modified: stable/12/stand/i386/libi386/biosdisk.c ============================================================================== --- stable/12/stand/i386/libi386/biosdisk.c Tue Feb 4 05:27:45 2020 (r357494) +++ stable/12/stand/i386/libi386/biosdisk.c Tue Feb 4 07:15:33 2020 (r357495) @@ -82,6 +82,7 @@ struct specification_packet { uint16_t sp_sectorcount; uint16_t sp_cylsec; uint8_t sp_head; + uint8_t sp_dummy[16]; /* Avoid memory corruption */ }; /* @@ -356,54 +357,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 = 0x13; v86.eax = 0x4b01; - 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++; @@ -483,22 +522,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 = 0x13; v86.eax = 0x4800; 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)) @@ -510,20 +559,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; @@ -540,6 +589,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; @@ -588,10 +641,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; @@ -603,8 +652,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;