[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

x86 /boot LBA diff to test



Hello all,

Below is a diff to add LBA functionality to /boot on the x86 machines.
This diff alone will not allow you to completely boot a kernel past the
8GB limit, but it is the first step in being able to do so.  I need a
lot of people to test this patch on -current machines, so that I know
if this is going to give trouble (it should not).  To date it has been
tested on over 15 machines, a few dozen more would be really nice, esp.
some esoteric ones.

To test, you will need to apply the patch, and build yourself a floppy
and/or cdrom (make release type thing).  Then you need to run 2 different
boot's in order to know if it is working fully.

1) Boot the kernel from floppy/cdrom (this will likely not use LBA things,
but will let me know that this is not broken).

2) Boot a kernel from harddisk.  So, boot the floppy/cdrom, and at the
"boot> " prompt type in something like: "boot hd0a:/bsd", in order to
boot the kernel from the harddisk.

If you look closely at the output of boot loader, you will find that it
tries to detect all available bios disks (fd0 hd0 hd1...).  As it prints
out the disks it has detected, it will append a "+" to the end of the
disk name (IE: hd0+), if that disk supports LBA.  If a disk supports LBA
access, the new boot will use it.

Last but not least, let me know if it worked or not.

NOTE: You need to be -current to even bother.  This code will not boot an
older kernel.  If you are not -current (at least ELF), please do not test
this, as it will just cloud the issue.

--Toby.

Index: libsa/biosdev.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/stand/libsa/biosdev.c,v
retrieving revision 1.55
diff -u -r1.55 biosdev.c
--- libsa/biosdev.c	17 Apr 2003 03:43:18 -0000	1.55
+++ libsa/biosdev.c	16 May 2003 04:51:37 -0000
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 1996 Michael Shalayeff
+ * Copyright (c) 2003 Tobias Weingartner
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,6 +47,9 @@
 static const char *biosdisk_err(u_int);
 static int biosdisk_errno(u_int);
 
+static int CHS_rw __P((int, int, int, int, int, int, void *));
+static int EDD_rw __P((int, int, u_int64_t, u_int32_t, void *));
+
 extern int debug;
 
 #if 0
@@ -58,9 +62,11 @@
 
 struct EDD_CB {
 	u_int8_t  edd_len;   /* size of packet */
-	u_int8_t  edd_res;   /* reserved */
-	u_int16_t edd_nblk;  /* # of blocks to transfer */
-	u_int32_t edd_buf;   /* address of buffer */
+	u_int8_t  edd_res1;  /* reserved */
+	u_int8_t  edd_nblk;  /* # of blocks to transfer */
+	u_int8_t  edd_res2;  /* reserved */
+	u_int16_t edd_off;   /* address of buffer (offset) */
+	u_int16_t edd_seg;   /* address of buffer (segment) */
 	u_int64_t edd_daddr; /* starting block */
 };
 
@@ -87,10 +93,10 @@
 	int dev;
 	bios_diskinfo_t *pdi;
 {
-	u_int rv;
+	u_int rv, secl, sech;
 
 	/* Just reset, don't check return code */
-	biosdreset(dev);
+	rv = biosdreset(dev);
 
 #ifdef BIOS_DEBUG
 	if (debug)
@@ -113,7 +119,7 @@
 	}
 #endif
 	if (rv & 0xff)
-		return(1);
+		return (1);
 
 	/* Fix up info */
 	pdi->bios_number = dev;
@@ -121,46 +127,46 @@
 	pdi->bios_cylinders &= 0x3ff;
 	pdi->bios_cylinders++;
 
-#if 0
+	/*
+	 * NOTE: This seems to hang on certain machines.  Use function #8
+	 * first, and verify with #21 IFF #8 succeeds first.
+	 * Do not try this for floppy 0 (to support CD-ROM boot).
+	 */
+	if (dev) {
+		__asm __volatile (DOINT(0x13) ";setc %b0"
+				: "=a" (rv), "=d" (secl), "=c" (sech)
+				: "0" (0x15FF), "1" (dev), "2" (0xFFFF)
+				: "cc");
+		if (!(rv & 0xff00))
+			return (1);
+		if (rv & 0xff)
+			return (1);
+	}
+
 	/* NOTE:
 	 * This currently hangs/reboots some machines
 	 * The IBM Thinkpad 750ED for one.
 	 *
 	 * Funny that an IBM/MS extension would not be
 	 * implemented by an IBM system...
+	 *
+	 * Future hangs (when reported) can be "fixed"
+	 * with getSYSCONFaddr() and an exceptions list.
 	 */
 	if (dev & 0x80) {
 		int bm;
 		/* EDD support check */
-		__asm __volatile("int $2;" DOINT(0x13) "; setc %b0"
+		__asm __volatile(DOINT(0x13) "; setc %b0"
 			 : "=a" (rv), "=c" (bm)
-			 : "0" (0x4100), "2" (0x55aa), "d" (dev) : "cc");
-		DUMP_REGS;
+			 : "0" (0x4100), "b" (0x55aa), "d" (dev) : "cc");
 		if (!(rv & 0xff) && (BIOS_regs.biosr_bx & 0xffff) == 0xaa55)
-			pdi->bios_edd = bm & 0xffff;
+			pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff) << 16);
 		else
 			pdi->bios_edd = -1;
 	} else
 		pdi->bios_edd = -1;
-#else
-	pdi->bios_edd = -1;
-#endif
 
-	/*
-	 * NOTE: This seems to hang on certain machines.  Use function #8
-	 * first, and verify with #21 IFF #8 succeeds first.
-	 * Do not try this for floppy 0 (to support CD-ROM boot).
-	 */
-	if (dev) {
-		__asm __volatile (DOINT(0x13) "; setc %b0"
-			: "=a" (rv) : "0" (0x1500), "d" (dev) : "%ecx", "cc");
-		if(!(rv & 0xff00))
-			return(1);
-		if(rv & 0xff)
-			return(1);
-	}
-
-	/* XXX - Sanity check */
+	/* Sanity check */
 	if (!pdi->bios_cylinders || !pdi->bios_heads || !pdi->bios_sectors)
 		return(1);
 
@@ -175,7 +181,7 @@
  * Read/Write a block from given place using the BIOS.
  */
 static __inline int
-biosd_rw(rw, dev, cyl, head, sect, nsect, buf)
+CHS_rw(rw, dev, cyl, head, sect, nsect, buf)
 	int rw, dev, cyl, head;
 	int sect, nsect;
 	void * buf;
@@ -201,7 +207,7 @@
 	return (rv & 0xff)? rv >> 8 : 0;
 }
 
-int
+static __inline int
 EDD_rw(rw, dev, daddr, nblk, buf)
 	int rw, dev;
 	u_int64_t daddr;
@@ -209,16 +215,28 @@
 	void *buf;
 {
 	int rv;
-	struct EDD_CB cb;
+	volatile static struct EDD_CB cb;
+
+	/* Zero out reserved stuff */
+	cb.edd_res1 = 0;
+	cb.edd_res2 = 0;
 
+	/* Fill in parameters */
 	cb.edd_len = sizeof(cb);
 	cb.edd_nblk = nblk;
-	cb.edd_buf = (u_int32_t)buf;
+	cb.edd_seg = ((u_int32_t)buf >> 4) & 0xffff;
+	cb.edd_off = (u_int32_t)buf & 0xf;
 	cb.edd_daddr = daddr;
 
+	/* if offset/segment are zero, punt */
+	if (!cb.edd_seg && !cb.edd_off)
+		return (1);
+
+	/* Call extended read/write (with disk packet) */
+	BIOS_regs.biosr_ds = (u_int32_t)&cb >> 4;
 	__asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
 			  : "0" ((rw == F_READ)? 0x4200: 0x4300),
-			    "d" (dev), "S" (&cb) : "%ecx", "cc");
+			    "d" (dev), "S" ((int) (&cb) & 0xf) : "%ecx", "cc");
 	return (rv & 0xff)? rv >> 8 : 0;
 }
 
@@ -226,21 +244,17 @@
  * Read given sector, handling retry/errors/etc.
  */
 int
-biosd_io(rw, dev, cyl, head, sect, nsect, buf)
-	int rw, dev, cyl, head;
-	int sect, nsect;
-	void * buf;
+biosd_io(rw, bd, off, nsect, buf)
+	int rw;
+	bios_diskinfo_t *bd;
+	daddr_t off;
+	int nsect;
+	void* buf;
 {
+	int dev = bd->bios_number;
 	int j, error;
 	void *bb;
 
-#ifdef BIOS_DEBUG
-	if (debug)
-		printf("biosd_io(%s,%x,%u,%u,%u,%u,%p)\n",
-		       (rw==F_READ?"reading":"writing"), dev,
-			   cyl, head, sect, nsect, buf);
-#endif
-
 	/* use a bounce buffer to not cross 64k DMA boundary */
 	if ((((u_int32_t)buf) & ~0xffff) !=
 	    (((u_int32_t)buf + nsect * DEV_BSIZE) & ~0xffff)) {
@@ -253,13 +267,35 @@
 			bcopy (buf, bb, nsect * DEV_BSIZE);
 	} else
 		bb = buf;
-#ifdef BIOS_DEBUG
-	if (debug)
-		printf(" (%d,%d,%d,%d)@%p", cyl, head, sect, nsect, bb);
-#endif
+
 	/* Try to do operation up to 5 times */
-	for (error = 1, j = 5; j-- && error;)
-		switch (error = biosd_rw(rw, dev, cyl, head, sect, nsect, bb)) {
+	for (error = 1, j = 5; j-- && error;) {
+		/* CHS or LBA access? */
+		if (bd->bios_edd != -1) {
+			error = EDD_rw(rw, dev, off, nsect, bb);
+		} else {
+			int cyl, head, sect;
+			size_t i, n;
+			char *p = bb;
+
+			/* Handle track boundaries */
+			for (error = i = 0; error == 0 && i < nsect;
+ 					i += n, off += n, p += n * DEV_BSIZE) {
+
+				btochs(off, cyl, head, sect, bd->bios_heads, bd->bios_sectors);
+				if ((sect + (nsect - i)) >= bd->bios_sectors)
+					n = bd->bios_sectors - sect;
+				else
+					n = nsect - i;
+
+				error = CHS_rw(rw, dev, cyl, head, sect, n, p);
+
+				/* ECC corrected */
+				if (error == 0x11)
+					error = 0;
+			}
+		}
+		switch (error) {
 		case 0x00:	/* No errors */
 		case 0x11:	/* ECC corrected */
 			error = 0;
@@ -274,6 +310,7 @@
 			biosdreset(dev);
 			break;
 		}
+	}
 
 	if (bb != buf && rw == F_READ)
 		bcopy (bb, buf, nsect * DEV_BSIZE);
@@ -286,7 +323,7 @@
 	}
 #endif
 
-	return biosdisk_errno(error);
+	return (error);
 }
 
 /*
@@ -300,22 +337,17 @@
 	daddr_t off = LABELSECTOR;
 	char *buf;
 	struct dos_mbr mbr;
-	int cyl, head, sect;
 	int error, i;
 
-	/* XXX - Sanity check */
+	/* Sanity check */
 	if(bd->bios_heads == 0 || bd->bios_sectors == 0)
 		return("failed to read disklabel");
 
-	/* MBR is a hard thing */
+	/* MBR is a harddisk thing */
 	if (bd->bios_number & 0x80) {
 		/* Read MBR */
-		btochs(DOSBBSECTOR, cyl, head, sect,
-		       bd->bios_heads, bd->bios_sectors);
-
-		error = biosd_io(F_READ, bd->bios_number,
-				 cyl, head, sect, 1, &mbr);
-		if(error)
+		error = biosd_io(F_READ, bd, DOSBBSECTOR, 1, &mbr);
+		if (error)
 			return(biosdisk_err(error));
 
 		/* check mbr signature */
@@ -345,8 +377,7 @@
 		printf("loading disklabel @ %u\n", off);
 #endif
 	/* read disklabel */
-	btochs(off, cyl, head, sect, bd->bios_heads, bd->bios_sectors);
-	error = biosd_io(F_READ, bd->bios_number, cyl, head, sect, 1, buf);
+	error = biosd_io(F_READ, bd, off, 1, buf);
 
 	if(error)
 		return("failed to read disklabel");
@@ -555,38 +586,18 @@
 	void *buf;
 	size_t *rsize;
 {
-	u_int8_t error = 0;
 	struct diskinfo *dip = (struct diskinfo *)devdata;
-	register size_t i, nsect, n, spt, tpc;
-	int dev;
+	bios_diskinfo_t *bd = &dip->bios_info;
+	u_int8_t error = 0;
+	size_t nsect;
 
 	nsect = (size + DEV_BSIZE-1) / DEV_BSIZE;
 	if (rsize != NULL)
 		blk += dip->disklabel.
 			d_partitions[B_PARTITION(dip->bsddev)].p_offset;
 
-	/* handle floppies w/ different from drive geometry */
-	if (!(dip->bios_info.bios_number & 0x80) &&
-	    dip->disklabel.d_nsectors != 0)
-		spt = dip->disklabel.d_nsectors;
-	else
-		spt = dip->bios_info.bios_sectors;
-
-	tpc = dip->bios_info.bios_heads;
-	dev = dip->bios_info.bios_number;
-
-	for (i = 0; error == 0 && i < nsect;
-	     i += n, blk += n, buf += n * DEV_BSIZE) {
-		register int	cyl, hd, sect;
-
-		btochs(blk, cyl, hd, sect, tpc, spt);
-		if ((sect + (nsect - i)) >= spt)
-			n = spt - sect;
-		else
-			n = nsect - i;
-		
-		error = biosd_io(rw, dev, cyl, hd, sect, n, buf);
-	}
+	/* Read all, sub-functions handle track boundaries */
+	error = biosd_io(rw, bd, blk, nsect, buf);
 
 #ifdef BIOS_DEBUG
 	if (debug) {
@@ -597,7 +608,7 @@
 #endif
 
 	if (rsize != NULL)
-		*rsize = i * DEV_BSIZE;
+		*rsize = nsect * DEV_BSIZE;
 
 	return biosdisk_errno(error);
 }
Index: libsa/biosdev.h
===================================================================
RCS file: /cvs/src/sys/arch/i386/stand/libsa/biosdev.h,v
retrieving revision 1.27
diff -u -r1.27 biosdev.h
--- libsa/biosdev.h	14 Mar 2002 03:15:54 -0000	1.27
+++ libsa/biosdev.h	16 May 2003 04:51:37 -0000
@@ -42,7 +42,7 @@
 int biosclose(struct open_file *);
 int biosioctl(struct open_file *, u_long, void *);
 int bios_getdiskinfo(int, bios_diskinfo_t *);
-int biosd_io(int, int, int, int, int, int, void *);
+int biosd_io(int, bios_diskinfo_t *, daddr_t, int, void *);
 const char * bios_getdisklabel(bios_diskinfo_t *, struct disklabel *);
 
 /* diskprobe.c */
Index: libsa/cmd_i386.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/stand/libsa/cmd_i386.c,v
retrieving revision 1.24
diff -u -r1.24 cmd_i386.c
--- libsa/cmd_i386.c	14 Mar 2002 03:15:54 -0000	1.24
+++ libsa/cmd_i386.c	16 May 2003 04:51:37 -0000
@@ -87,6 +87,7 @@
 {
 #ifndef _TEST
 	int dev, part, st;
+	bios_diskinfo_t *bd = NULL;
 	char buf[DEV_BSIZE], *dest = (void *)BOOTBIOS_ADDR;
 
 	if(cmd.argc != 2) {
@@ -118,7 +119,8 @@
 		printf("[%x]\n", dev);
 
 	/* Read boot sector from device */
-	st = biosd_io(F_READ, dev, 0, 0, 0, 1, buf);
+	bd = bios_dklookup(dev);
+	st = biosd_io(F_READ, bd, 0, 1, buf);
 	if(st) goto bad;
 
 	/* Frob boot flag in buffer from HD */
Index: libsa/diskprobe.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/stand/libsa/diskprobe.c,v
retrieving revision 1.18
diff -u -r1.18 diskprobe.c
--- libsa/diskprobe.c	14 Mar 2002 01:26:34 -0000	1.18
+++ libsa/diskprobe.c	16 May 2003 04:51:37 -0000
@@ -267,9 +267,7 @@
 {
 	struct diskinfo *dip, *dip2;
 	int st, reprobe = 0;
-	int hpc, spt, dev;
 	char *buf;
-	int cyl, head, sect;
 
 	buf = alloca(DEV_BSIZE);
 	for(dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)){
@@ -279,13 +277,8 @@
 		if (!(bdi->bios_number & 0x80) || bdi->flags & BDI_INVALID)
 			continue;
 
-		dev = bdi->bios_number;
-		hpc = bdi->bios_heads;
-		spt = bdi->bios_sectors;
-
 		/* Adler32 checksum */
-		btochs(blk, cyl, head, sect, hpc, spt);
-		st = biosd_io(F_READ, dev, cyl, head, sect, 1, buf);
+		st = biosd_io(F_READ, bdi, blk, 1, buf);
 		if (st) {
 			bdi->flags |= BDI_INVALID;
 			continue;