Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 03 Sep 2019 14:08:09 -0000
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r346474 - in stable/11/stand/i386: libi386 loader
Message-ID:  <201904210327.x3L3RCXa015476@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kevans
Date: Sun Apr 21 03:27:12 2019
New Revision: 346474
URL: https://svnweb.freebsd.org/changeset/base/346474

Log:
  MFC i386 stand cleanup: r337353-r337354, r337356, r337872, r337878, r337881,
  r337890-r337891, r338188
  
  r337353:
  loader: cstyle cleanup for biosdisk.c
  
  Also switch u_int to uint32_t. Also replace "write" by "dowrite".
  No functional changes intended.
  
  r337354:
  loader: 337353 did miss to rename 2 write instances
  
  2 write instances got somehow missed.
  
  r337356:
  loader: bd_open() should cleanup from disk_open() error
  
  Since bd_open() does early increment for reference counter and bcache
  allocation, it also should undo those in case of the error.
  
  Also remove unused variables rdev, g_err.
  
  r337872:
  libi386: remove BD_SUPPORT_FRAGS
  
  BD_SUPPORT_FRAGS is preprocessor knob to allow partial reads in bioscd/biosdisk
  level. However, we already have support for partial reads in bcache, and there
  is no need to have duplication via preprocessor controls.
  
  Note that bioscd/biosdisk interface is assumed to perform IO in 512B blocks,
  so the only translation we have to do is 512 <-> native block size.
  
  r337878:
  libi386: remove bd_read() and bd_write() wrappers
  
  Those wroappers are nice, but do not really add much value.
  
  r337881:
  libi386: use BD_RD and BR_WR constants
  
  Use BD_RD and BD_WR instead of 0 and 1.
  
  r337890:
  libi386: small style updates in biosdisk
  
  Use break instead of return in for loop, as done earlier. Insert and remove
  some blank lines. No functional changes intended.
  
  r337891:
  libi386: bd_io_workaround() is to be called for reads only
  
  bd_io() can perform either reads or writes, we only need bd_io_workaround()
  for reads.
  
  r338188:
  loader: bios loader should allow to chain load a file
  
  The current chain command does accept only device, allow also a file to be used,
  such as /boot/pmbr or /boot/mbr (or stored third party MBR/VBR block).
  
  Also fix file descriptor leak.

Modified:
  stable/11/stand/i386/libi386/bioscd.c
  stable/11/stand/i386/libi386/biosdisk.c
  stable/11/stand/i386/loader/chain.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/stand/i386/libi386/bioscd.c
==============================================================================
--- stable/11/stand/i386/libi386/bioscd.c	Sun Apr 21 03:22:57 2019	(r346473)
+++ stable/11/stand/i386/libi386/bioscd.c	Sun Apr 21 03:27:12 2019	(r346474)
@@ -258,15 +258,9 @@ bc_realstrategy(void *devdata, int rw, daddr_t dblk, s
 	struct i386_devdesc *dev;
 	int unit;
 	int blks;
-#ifdef BD_SUPPORT_FRAGS
-	char fragbuf[BIOSCD_SECSIZE];
-	size_t fragsize;
 
-	fragsize = size % BIOSCD_SECSIZE;
-#else
 	if (size % BIOSCD_SECSIZE)
 		return (EINVAL);
-#endif
 
 	if ((rw & F_MASK) != F_READ)
 		return(EROFS);
@@ -290,20 +284,6 @@ bc_realstrategy(void *devdata, int rw, daddr_t dblk, s
 			return (0);
 		}
 	}
-#ifdef BD_SUPPORT_FRAGS
-	DEBUG("frag read %d from %lld+%d to %p", 
-	    fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE));
-	if (fragsize && bc_read(unit, dblk + blks, 1, fragbuf) != 1) {
-		if (blks) {
-			if (rsize)
-				*rsize = blks * BIOSCD_SECSIZE;
-			return (0);
-		}
-		DEBUG("frag read error");
-		return(EIO);
-	}
-	bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize);
-#endif	
 	if (rsize)
 		*rsize = size;
 	return (0);

Modified: stable/11/stand/i386/libi386/biosdisk.c
==============================================================================
--- stable/11/stand/i386/libi386/biosdisk.c	Sun Apr 21 03:22:57 2019	(r346473)
+++ stable/11/stand/i386/libi386/biosdisk.c	Sun Apr 21 03:27:12 2019	(r346474)
@@ -30,7 +30,7 @@ __FBSDID("$FreeBSD$");
 
 /*
  * BIOS disk device handling.
- * 
+ *
  * Ideas and algorithms from:
  *
  * - NetBSD libi386/biosdisk.c
@@ -50,20 +50,20 @@ __FBSDID("$FreeBSD$");
 #include "disk.h"
 #include "libi386.h"
 
-#define BIOS_NUMDRIVES		0x475
-#define BIOSDISK_SECSIZE	512
-#define BUFSIZE			(1 * BIOSDISK_SECSIZE)
+#define	BIOS_NUMDRIVES		0x475
+#define	BIOSDISK_SECSIZE	512
+#define	BUFSIZE			(1 * BIOSDISK_SECSIZE)
 
-#define DT_ATAPI		0x10		/* disk type for ATAPI floppies */
-#define WDMAJOR			0		/* major numbers for devices we frontend for */
-#define WFDMAJOR		1
-#define FDMAJOR			2
-#define DAMAJOR			4
+#define	DT_ATAPI	0x10	/* disk type for ATAPI floppies */
+#define	WDMAJOR		0	/* major numbers for devices we frontend for */
+#define	WFDMAJOR	1
+#define	FDMAJOR		2
+#define	DAMAJOR		4
 
 #ifdef DISK_DEBUG
-# define DEBUG(fmt, args...)	printf("%s: " fmt "\n" , __func__ , ## args)
+#define	DEBUG(fmt, args...)	printf("%s: " fmt "\n", __func__, ## args)
 #else
-# define DEBUG(fmt, args...)
+#define	DEBUG(fmt, args...)
 #endif
 
 /*
@@ -91,13 +91,12 @@ static struct bdinfo
 static int nbdinfo = 0;
 
 #define	BD(dev)		(bdinfo[(dev)->dd.d_unit])
+#define	BD_RD		0
+#define	BD_WR		1
 
 static void bd_io_workaround(struct disk_devdesc *dev);
 
-static int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks,
-    caddr_t dest);
-static int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks,
-    caddr_t dest);
+static int bd_io(struct disk_devdesc *, daddr_t, int, caddr_t, int);
 static int bd_int13probe(struct bdinfo *bd);
 
 static int bd_init(void);
@@ -164,7 +163,7 @@ bd_init(void)
 			 * Check the BIOS equipment list for number
 			 * of fixed disks.
 			 */
-			if(base == 0x80 &&
+			if (base == 0x80 &&
 			    (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES)))
 				break;
 #endif
@@ -184,7 +183,7 @@ bd_init(void)
 		}
 	}
 	bcache_add_dev(nbdinfo);
-	return(0);
+	return (0);
 }
 
 /*
@@ -207,7 +206,7 @@ bd_int13probe(struct bdinfo *bd)
 	    (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f))	/* unit # bad */
 		return (0);	/* skip device */
 
-	if ((v86.ecx & 0x3f) == 0) /* absurd sector number */
+	if ((v86.ecx & 0x3f) == 0)	/* absurd sector number */
 		ret = 0;	/* set error */
 
 	/* Convert max cyl # -> # of cylinders */
@@ -307,6 +306,7 @@ bd_print(int verbose)
 		    bdinfo[i].bd_sectorsize);
 		if ((ret = pager_output(line)) != 0)
 			break;
+
 		dev.dd.d_dev = &biosdisk;
 		dev.dd.d_unit = i;
 		dev.d_slice = -1;
@@ -318,7 +318,7 @@ bd_print(int verbose)
 			ret = disk_print(&dev, line, verbose);
 			disk_close(&dev);
 			if (ret != 0)
-			    return (ret);
+				break;
 		}
 	}
 	return (ret);
@@ -337,11 +337,11 @@ bd_print(int verbose)
 static int
 bd_open(struct open_file *f, ...)
 {
-	struct disk_devdesc *dev, rdev;
+	struct disk_devdesc *dev;
 	struct disk_devdesc disk;
-	int err, g_err;
 	va_list ap;
 	uint64_t size;
+	int rc;
 
 	va_start(ap, f);
 	dev = va_arg(ap, struct disk_devdesc *);
@@ -365,6 +365,7 @@ bd_open(struct open_file *f, ...)
 	disk.d_slice = -1;
 	disk.d_partition = -1;
 	disk.d_offset = 0;
+
 	if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
 	    BD(dev).bd_sectorsize) == 0) {
 
@@ -376,10 +377,16 @@ bd_open(struct open_file *f, ...)
 		disk_close(&disk);
 	}
 
-	err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
+	rc = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
 	    BD(dev).bd_sectorsize);
-
-	return (err);
+	if (rc != 0) {
+		BD(dev).bd_open--;
+		if (BD(dev).bd_open == 0) {
+			bcache_free(BD(dev).bd_bcache);
+			BD(dev).bd_bcache = NULL;
+		}
+	}
+	return (rc);
 }
 
 static int
@@ -410,7 +417,7 @@ bd_ioctl(struct open_file *f, u_long cmd, void *data)
 
 	switch (cmd) {
 	case DIOCGSECTORSIZE:
-		*(u_int *)data = BD(dev).bd_sectorsize;
+		*(uint32_t *)data = BD(dev).bd_sectorsize;
 		break;
 	case DIOCGMEDIASIZE:
 		*(uint64_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize;
@@ -432,176 +439,161 @@ bd_strategy(void *devdata, int rw, daddr_t dblk, size_
 	bcd.dv_strategy = bd_realstrategy;
 	bcd.dv_devdata = devdata;
 	bcd.dv_cache = BD(dev).bd_bcache;
-	return (bcache_strategy(&bcd, rw, dblk + dev->d_offset,
-	    size, buf, rsize));
+	return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, size,
+	    buf, rsize));
 }
 
 static int
 bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
     char *buf, size_t *rsize)
 {
-    struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
-    uint64_t		disk_blocks;
-    int			blks, rc;
-#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */
-    char		fragbuf[BIOSDISK_SECSIZE];
-    size_t		fragsize;
+	struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
+	uint64_t		disk_blocks;
+	int			blks, rc;
 
-    fragsize = size % BIOSDISK_SECSIZE;
-#else
-    if (size % BD(dev).bd_sectorsize)
-	panic("bd_strategy: %d bytes I/O not multiple of block size", size);
-#endif
+	if (size % BD(dev).bd_sectorsize) {
+		panic("bd_strategy: %d bytes I/O not multiple of block size",
+		    size);
+	}
 
-    DEBUG("open_disk %p", dev);
+	DEBUG("open_disk %p", dev);
 
-    /*
-     * Check the value of the size argument. We do have quite small
-     * heap (64MB), but we do not know good upper limit, so we check against
-     * INT_MAX here. This will also protect us against possible overflows
-     * while translating block count to bytes.
-     */
-    if (size > INT_MAX) {
-	DEBUG("too large read: %zu bytes", size);
-	return (EIO);
-    }
+	/*
+	 * Check the value of the size argument. We do have quite small
+	 * heap (64MB), but we do not know good upper limit, so we check against
+	 * INT_MAX here. This will also protect us against possible overflows
+	 * while translating block count to bytes.
+	 */
+	if (size > INT_MAX) {
+		DEBUG("too large read: %zu bytes", size);
+		return (EIO);
+	}
 
-    blks = size / BD(dev).bd_sectorsize;
-    if (dblk > dblk + blks)
-	return (EIO);
+	blks = size / BD(dev).bd_sectorsize;
+	if (dblk > dblk + blks)
+		return (EIO);
 
-    if (rsize)
-	*rsize = 0;
+	if (rsize)
+		*rsize = 0;
 
-    /* Get disk blocks, this value is either for whole disk or for partition */
-    if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
-	/* DIOCGMEDIASIZE returns bytes. */
-        disk_blocks /= BD(dev).bd_sectorsize;
-    } else {
-	/* We should not get here. Just try to survive. */
-	disk_blocks = BD(dev).bd_sectors - dev->d_offset;
-    }
+	/*
+	 * Get disk blocks, this value is either for whole disk or for
+	 * partition.
+	 */
+	if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
+		/* DIOCGMEDIASIZE returns bytes. */
+		disk_blocks /= BD(dev).bd_sectorsize;
+	} else {
+		/* We should not get here. Just try to survive. */
+		disk_blocks = BD(dev).bd_sectors - dev->d_offset;
+	}
 
-    /* Validate source block address. */
-    if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks)
-	return (EIO);
+	/* Validate source block address. */
+	if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks)
+		return (EIO);
 
-    /*
-     * Truncate if we are crossing disk or partition end.
-     */
-    if (dblk + blks >= dev->d_offset + disk_blocks) {
-	blks = dev->d_offset + disk_blocks - dblk;
-	size = blks * BD(dev).bd_sectorsize;
-	DEBUG("short read %d", blks);
-    }
+	/*
+	 * Truncate if we are crossing disk or partition end.
+	 */
+	if (dblk + blks >= dev->d_offset + disk_blocks) {
+		blks = dev->d_offset + disk_blocks - dblk;
+		size = blks * BD(dev).bd_sectorsize;
+		DEBUG("short read %d", blks);
+	}
 
-    switch (rw & F_MASK) {
-    case F_READ:
-	DEBUG("read %d from %lld to %p", blks, dblk, buf);
+	switch (rw & F_MASK) {
+	case F_READ:
+		DEBUG("read %d from %lld to %p", blks, dblk, buf);
 
-	if (blks && (rc = bd_read(dev, dblk, blks, buf))) {
-	    /* Filter out floppy controller errors */
-	    if (BD(dev).bd_flags != BD_FLOPPY || rc != 0x20) {
-		printf("read %d from %lld to %p, error: 0x%x\n", blks, dblk,
-		    buf, rc);
-	    }
-	    return (EIO);
-	}
-#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */
-	DEBUG("bd_strategy: frag read %d from %d+%d to %p",
-	    fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE));
-	if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) {
-	    DEBUG("frag read error");
-	    return(EIO);
-	}
-	bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize);
-#endif
-	break;
-    case F_WRITE :
-	DEBUG("write %d from %lld to %p", blks, dblk, buf);
+		if (blks && (rc = bd_io(dev, dblk, blks, buf, BD_RD))) {
+			/* Filter out floppy controller errors */
+			if (BD(dev).bd_flags != BD_FLOPPY || rc != 0x20) {
+				printf("read %d from %lld to %p, error: 0x%x\n",
+				    blks, dblk, buf, rc);
+			}
+			return (EIO);
+		}
+		break;
+	case F_WRITE :
+		DEBUG("write %d from %lld to %p", blks, dblk, buf);
 
-	if (blks && bd_write(dev, dblk, blks, buf)) {
-	    DEBUG("write error");
-	    return (EIO);
+		if (blks && bd_io(dev, dblk, blks, buf, BD_WR)) {
+			DEBUG("write error");
+			return (EIO);
+		}
+		break;
+	default:
+		/* DO NOTHING */
+		return (EROFS);
 	}
-#ifdef BD_SUPPORT_FRAGS
-	if(fragsize) {
-	    DEBUG("Attempted to write a frag");
-	    return (EIO);
-	}
-#endif
-	break;
-    default:
-	/* DO NOTHING */
-	return (EROFS);
-    }
 
-    if (rsize)
-	*rsize = size;
-    return (0);
+	if (rsize)
+		*rsize = size;
+	return (0);
 }
 
 static int
 bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
-    int write)
+    int dowrite)
 {
-    static struct edd_packet packet;
+	static struct edd_packet packet;
 
-    packet.len = sizeof(struct edd_packet);
-    packet.count = blks;
-    packet.off = VTOPOFF(dest);
-    packet.seg = VTOPSEG(dest);
-    packet.lba = dblk;
-    v86.ctl = V86_FLAGS;
-    v86.addr = 0x13;
-    if (write)
+	packet.len = sizeof(struct edd_packet);
+	packet.count = blks;
+	packet.off = VTOPOFF(dest);
+	packet.seg = VTOPSEG(dest);
+	packet.lba = dblk;
+	v86.ctl = V86_FLAGS;
+	v86.addr = 0x13;
 	/* Should we Write with verify ?? 0x4302 ? */
-	v86.eax = 0x4300;
-    else
-	v86.eax = 0x4200;
-    v86.edx = BD(dev).bd_unit;
-    v86.ds = VTOPSEG(&packet);
-    v86.esi = VTOPOFF(&packet);
-    v86int();
-    if (V86_CY(v86.efl))
-	return (v86.eax >> 8);
-    return (0);
+	if (dowrite == BD_WR)
+		v86.eax = 0x4300;
+	else
+		v86.eax = 0x4200;
+	v86.edx = BD(dev).bd_unit;
+	v86.ds = VTOPSEG(&packet);
+	v86.esi = VTOPOFF(&packet);
+	v86int();
+	if (V86_CY(v86.efl))
+		return (v86.eax >> 8);
+	return (0);
 }
 
 static int
 bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
-    int write)
+    int dowrite)
 {
-    u_int	x, bpc, cyl, hd, sec;
+	uint32_t x, bpc, cyl, hd, sec;
 
-    bpc = BD(dev).bd_sec * BD(dev).bd_hds;	/* blocks per cylinder */
-    x = dblk;
-    cyl = x / bpc;			/* block # / blocks per cylinder */
-    x %= bpc;				/* block offset into cylinder */
-    hd = x / BD(dev).bd_sec;		/* offset / blocks per track */
-    sec = x % BD(dev).bd_sec;		/* offset into track */
+	bpc = BD(dev).bd_sec * BD(dev).bd_hds;	/* blocks per cylinder */
+	x = dblk;
+	cyl = x / bpc;			/* block # / blocks per cylinder */
+	x %= bpc;				/* block offset into cylinder */
+	hd = x / BD(dev).bd_sec;		/* offset / blocks per track */
+	sec = x % BD(dev).bd_sec;		/* offset into track */
 
-    /* correct sector number for 1-based BIOS numbering */
-    sec++;
+	/* correct sector number for 1-based BIOS numbering */
+	sec++;
 
-    if (cyl > 1023)
-	/* CHS doesn't support cylinders > 1023. */
-	return (1);
+	if (cyl > 1023) {
+		/* CHS doesn't support cylinders > 1023. */
+		return (1);
+	}
 
-    v86.ctl = V86_FLAGS;
-    v86.addr = 0x13;
-    if (write)
-	v86.eax = 0x300 | blks;
-    else
-	v86.eax = 0x200 | blks;
-    v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
-    v86.edx = (hd << 8) | BD(dev).bd_unit;
-    v86.es = VTOPSEG(dest);
-    v86.ebx = VTOPOFF(dest);
-    v86int();
-    if (V86_CY(v86.efl))
-	return (v86.eax >> 8);
-    return (0);
+	v86.ctl = V86_FLAGS;
+	v86.addr = 0x13;
+	if (dowrite == BD_WR)
+		v86.eax = 0x300 | blks;
+	else
+		v86.eax = 0x200 | blks;
+	v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
+	v86.edx = (hd << 8) | BD(dev).bd_unit;
+	v86.es = VTOPSEG(dest);
+	v86.ebx = VTOPOFF(dest);
+	v86int();
+	if (V86_CY(v86.efl))
+		return (v86.eax >> 8);
+	return (0);
 }
 
 static void
@@ -609,130 +601,117 @@ bd_io_workaround(struct disk_devdesc *dev)
 {
 	uint8_t buf[8 * 1024];
 
-	bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, 0);
+	bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, BD_RD);
 }
 
 
 static int
-bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write)
+bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
+    int dowrite)
 {
-    u_int	x, sec, result, resid, retry, maxfer;
-    caddr_t	p, xp, bbuf;
+	u_int	x, sec, result, resid, retry, maxfer;
+	caddr_t	p, xp, bbuf;
     
-    /* Just in case some idiot actually tries to read/write -1 blocks... */
-    if (blks < 0)
-	return (-1);
+	/* Just in case some idiot actually tries to read/write -1 blocks... */
+	if (blks < 0)
+		return (-1);
 
-    resid = blks;
-    p = dest;
+	resid = blks;
+	p = dest;
 
-    /*
-     * Workaround for a problem with some HP ProLiant BIOS failing to work out
-     * the boot disk after installation. hrs and kuriyama discovered this
-     * problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and discovered
-     * that an int13h call seems to cause a buffer overrun in the bios. The
-     * problem is alleviated by doing an extra read before the buggy read. It
-     * is not immediately known whether other models are similarly affected.
-     */
-    if (dblk >= 0x100000000)
-	bd_io_workaround(dev);
-
-    /* Decide whether we have to bounce */
-    if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 &&
-	(VTOP(dest) >> 16) != (VTOP(dest +
-	blks * BD(dev).bd_sectorsize) >> 16))) {
-
-	/* 
-	 * There is a 64k physical boundary somewhere in the
-	 * destination buffer, or the destination buffer is above
-	 * first 1MB of physical memory so we have to arrange a
-	 * suitable bounce buffer.  Allocate a buffer twice as large
-	 * as we need to.  Use the bottom half unless there is a break
-	 * there, in which case we use the top half.
-	 */
-	x = V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize;
-	x = min(x, (unsigned)blks);
-	bbuf = PTOV(V86_IO_BUFFER);
-	maxfer = x;		/* limit transfers to bounce region size */
-    } else {
-	bbuf = NULL;
-	maxfer = 0;
-    }
-    
-    while (resid > 0) {
 	/*
-	 * Play it safe and don't cross track boundaries.
-	 * (XXX this is probably unnecessary)
+	 * Workaround for a problem with some HP ProLiant BIOS failing to work
+	 * out the boot disk after installation. hrs and kuriyama discovered
+	 * this problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and
+	 * discovered that an int13h call seems to cause a buffer overrun in
+	 * the bios. The problem is alleviated by doing an extra read before
+	 * the buggy read. It is not immediately known whether other models
+	 * are similarly affected.
 	 */
-	sec = dblk % BD(dev).bd_sec;	/* offset into track */
-	x = min(BD(dev).bd_sec - sec, resid);
-	if (maxfer > 0)
-	    x = min(x, maxfer);		/* fit bounce buffer */
+	if (dowrite == BD_RD && dblk >= 0x100000000)
+		bd_io_workaround(dev);
 
-	/* where do we transfer to? */
-	xp = bbuf == NULL ? p : bbuf;
+	/* Decide whether we have to bounce */
+	if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 &&
+	    (VTOP(dest) >> 16) !=
+	    (VTOP(dest + blks * BD(dev).bd_sectorsize) >> 16))) {
 
-	/*
-	 * Put your Data In, Put your Data out,
-	 * Put your Data In, and shake it all about 
-	 */
-	if (write && bbuf != NULL)
-	    bcopy(p, bbuf, x * BD(dev).bd_sectorsize);
-
-	/*
-	 * Loop retrying the operation a couple of times.  The BIOS
-	 * may also retry.
-	 */
-	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)
-		result = bd_edd_io(dev, dblk, x, xp, write);
-	    else
-		result = bd_chs_io(dev, dblk, x, xp, write);
-	    if (result == 0)
-		break;
+		/* 
+		 * There is a 64k physical boundary somewhere in the
+		 * destination buffer, or the destination buffer is above
+		 * first 1MB of physical memory so we have to arrange a
+		 * suitable bounce buffer.  Allocate a buffer twice as large
+		 * as we need to.  Use the bottom half unless there is a break
+		 * there, in which case we use the top half.
+		 */
+		x = V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize;
+		x = min(x, (unsigned)blks);
+		bbuf = PTOV(V86_IO_BUFFER);
+		maxfer = x;	/* limit transfers to bounce region size */
+	} else {
+		bbuf = NULL;
+		maxfer = 0;
 	}
+    
+	while (resid > 0) {
+		/*
+		 * Play it safe and don't cross track boundaries.
+		 * (XXX this is probably unnecessary)
+		 */
+		sec = dblk % BD(dev).bd_sec;	/* offset into track */
+		x = min(BD(dev).bd_sec - sec, resid);
+		if (maxfer > 0)
+			x = min(x, maxfer);		/* fit bounce buffer */
 
-	if (write)
-	    DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x,
-		p, VTOP(p), dblk, result ? "failed" : "ok");
-	else
-	    DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x,
-		dblk, p, VTOP(p), result ? "failed" : "ok");
-	if (result) {
-	    return (result);
-	}
-	if (!write && bbuf != NULL)
-	    bcopy(bbuf, p, x * BD(dev).bd_sectorsize);
-	p += (x * BD(dev).bd_sectorsize);
-	dblk += x;
-	resid -= x;
-    }
+		/* where do we transfer to? */
+		xp = bbuf == NULL ? p : bbuf;
 
-/*    hexdump(dest, (blks * BD(dev).bd_sectorsize)); */
-    return(0);
-}
+		/*
+		 * Put your Data In, Put your Data out,
+		 * Put your Data In, and shake it all about 
+		 */
+		if (dowrite == BD_WR && bbuf != NULL)
+			bcopy(p, bbuf, x * BD(dev).bd_sectorsize);
 
-static int
-bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
-{
+		/*
+		 * Loop retrying the operation a couple of times.  The BIOS
+		 * may also retry.
+		 */
+		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();
+			}
 
-	return (bd_io(dev, dblk, blks, dest, 0));
-}
+			if (BD(dev).bd_flags & BD_MODEEDD1)
+				result = bd_edd_io(dev, dblk, x, xp, dowrite);
+			else
+				result = bd_chs_io(dev, dblk, x, xp, dowrite);
+			if (result == 0)
+				break;
+		}
 
-static int
-bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
-{
+		if (dowrite == BD_WR)
+			DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x,
+			    p, VTOP(p), dblk, result ? "failed" : "ok");
+		else
+			DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x,
+			    dblk, p, VTOP(p), result ? "failed" : "ok");
+		if (result) {
+			return (result);
+		}
+		if (dowrite == BD_RD && bbuf != NULL)
+			bcopy(bbuf, p, x * BD(dev).bd_sectorsize);
+		p += (x * BD(dev).bd_sectorsize);
+		dblk += x;
+		resid -= x;
+	}
 
-	return (bd_io(dev, dblk, blks, dest, 1));
+	return (0);
 }
 
 /*
@@ -753,15 +732,15 @@ uint32_t
 bd_getbigeom(int bunit)
 {
 
-    v86.ctl = V86_FLAGS;
-    v86.addr = 0x13;
-    v86.eax = 0x800;
-    v86.edx = 0x80 + bunit;
-    v86int();
-    if (V86_CY(v86.efl))
-	return 0x4f010f;
-    return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
-	   (v86.edx & 0xff00) | (v86.ecx & 0x3f);
+	v86.ctl = V86_FLAGS;
+	v86.addr = 0x13;
+	v86.eax = 0x800;
+	v86.edx = 0x80 + bunit;
+	v86int();
+	if (V86_CY(v86.efl))
+		return (0x4f010f);
+	return (((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
+	    (v86.edx & 0xff00) | (v86.ecx & 0x3f));
 }
 
 /*
@@ -773,49 +752,49 @@ bd_getbigeom(int bunit)
 int
 bd_getdev(struct i386_devdesc *d)
 {
-    struct disk_devdesc		*dev;
-    int				biosdev;
-    int 			major;
-    int				rootdev;
-    char			*nip, *cp;
-    int				i, unit;
+	struct disk_devdesc *dev;
+	int	biosdev;
+	int	major;
+	int	rootdev;
+	char	*nip, *cp;
+	int	i, unit;
 
-    dev = (struct disk_devdesc *)d;
-    biosdev = bd_unit2bios(dev->dd.d_unit);
-    DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev);
-    if (biosdev == -1)				/* not a BIOS device */
-	return(-1);
-    if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
-	BD(dev).bd_sectorsize) != 0)		/* oops, not a viable device */
-	    return (-1);
-    else
-	disk_close(dev);
+	dev = (struct disk_devdesc *)d;
+	biosdev = bd_unit2bios(dev->dd.d_unit);
+	DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev);
+	if (biosdev == -1)			/* not a BIOS device */
+		return (-1);
+	if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
+	    BD(dev).bd_sectorsize) != 0)	/* oops, not a viable device */
+		return (-1);
+	else
+		disk_close(dev);
 
-    if (biosdev < 0x80) {
-	/* floppy (or emulated floppy) or ATAPI device */
-	if (bdinfo[dev->dd.d_unit].bd_type == DT_ATAPI) {
-	    /* is an ATAPI disk */
-	    major = WFDMAJOR;
+	if (biosdev < 0x80) {
+		/* floppy (or emulated floppy) or ATAPI device */
+		if (bdinfo[dev->dd.d_unit].bd_type == DT_ATAPI) {
+			/* is an ATAPI disk */
+			major = WFDMAJOR;
+		} else {
+			/* is a floppy disk */
+			major = FDMAJOR;
+		}
 	} else {
-	    /* is a floppy disk */
-	    major = FDMAJOR;
+		/* assume an IDE disk */
+		major = WDMAJOR;
 	}
-    } else {
-	    /* assume an IDE disk */
-	    major = WDMAJOR;
-    }
-    /* default root disk unit number */
-    unit = biosdev & 0x7f;
+	/* default root disk unit number */
+	unit = biosdev & 0x7f;
 
-    /* XXX a better kludge to set the root disk unit number */
-    if ((nip = getenv("root_disk_unit")) != NULL) {
-	i = strtol(nip, &cp, 0);
-	/* check for parse error */
-	if ((cp != nip) && (*cp == 0))
-	    unit = i;
-    }
+	/* XXX a better kludge to set the root disk unit number */
+	if ((nip = getenv("root_disk_unit")) != NULL) {
+		i = strtol(nip, &cp, 0);
+		/* check for parse error */
+		if ((cp != nip) && (*cp == 0))
+			unit = i;
+	}
 
-    rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition);
-    DEBUG("dev is 0x%x\n", rootdev);
-    return(rootdev);
+	rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition);
+	DEBUG("dev is 0x%x\n", rootdev);
+	return (rootdev);
 }

Modified: stable/11/stand/i386/loader/chain.c
==============================================================================
--- stable/11/stand/i386/loader/chain.c	Sun Apr 21 03:22:57 2019	(r346473)
+++ stable/11/stand/i386/loader/chain.c	Sun Apr 21 03:27:12 2019	(r346474)
@@ -92,24 +92,26 @@ command_chain(int argc, char *argv[])
 	i386_getdev((void **)(&rootdev), argv[1], NULL);
 	if (rootdev == NULL) {
 		command_errmsg = "can't determine root device";
+		close(fd);
 		return (CMD_ERROR);
 	}
 
-	if (archsw.arch_readin(fd, mem, SECTOR_SIZE) != SECTOR_SIZE) {
+	if (archsw.arch_readin(fd, mem, size) != size) {
 		command_errmsg = "failed to read disk";
 		close(fd);
 		return (CMD_ERROR);
 	}
 	close(fd);
 
-	if (*((uint16_t *)PTOV(mem + DOSMAGICOFFSET)) != DOSMAGIC) {
+	if (argv[1][len-1] == ':' &&
+	    *((uint16_t *)PTOV(mem + DOSMAGICOFFSET)) != DOSMAGIC) {
 		command_errmsg = "wrong magic";
 		return (CMD_ERROR);
 	}
 
 	relocater_data[0].src = mem;
 	relocater_data[0].dest = 0x7C00;
-	relocater_data[0].size = SECTOR_SIZE;
+	relocater_data[0].size = size;
 
 	relocator_edx = bd_unit2bios(rootdev->dd.d_unit);
 	relocator_esi = relocater_size;





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904210327.x3L3RCXa015476>