Subject: Adding cd9660 support to the i386/amd64 BIOS bootloader
To: None <tech-install@netbsd.org>
From: Bang Jun-Young <junyoung@netbsd.org>
List: port-amd64
Date: 06/21/2005 23:39:09
--Boundary-00=_NaCuCN2P1fCtx/a
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hi,

The attached patch adds cd9660 file system support to the i386/amd64 BIOS
bootloader. It allows you to boot the kernel directly from CD without floppy
disk emulation.

It has been tested with a number of real/virtual machines including Bochs,
VMware, ASUS/Pentium, ASUS/Athlon, Gigabyte/Duron, Soltek/Athlon XP, an
amd64 machine, and a Fujitsu laptop. It just worked fine.

The only MI change is in sys/lib/libsa/cd9660.c:

-#define        cdb2devb(bno)   ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
+#define        cdb2devb(bno)   (bno)

On i386, DEV_BSIZE on CD-ROM drives should be the same as
ISO_DEFAULT_BLOCK_SIZE, otherwise CD-ROM can't boot.

Any comments? I'm going to commit the patch in 48 hours unless there are
objections.

Jun-Young

--Boundary-00=_NaCuCN2P1fCtx/a
Content-Type: text/x-diff;
  charset="us-ascii";
  name="cdboot-20050621.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="cdboot-20050621.diff"

? sys/arch/i386/stand/lib/getbasemem.c
Index: sys/arch/i386/stand/boot/Makefile.boot
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/boot/Makefile.boot,v
retrieving revision 1.21
diff -u -r1.21 Makefile.boot
--- sys/arch/i386/stand/boot/Makefile.boot	27 May 2005 21:40:09 -0000	1.21
+++ sys/arch/i386/stand/boot/Makefile.boot	21 Jun 2005 14:22:19 -0000
@@ -62,6 +62,7 @@
 CPPFLAGS+= -DCONSADDR=boot_params.bp_consaddr
 CPPFLAGS+= -DCONSOLE_KEYMAP=boot_params.bp_keymap
 
+CPPFLAGS+= -DSUPPORT_CD9660
 CPPFLAGS+= -DSUPPORT_USTARFS
 CPPFLAGS+= -DSUPPORT_DOSFS
 CPPFLAGS+= -DPASS_BIOSGEOM
@@ -139,7 +140,7 @@
 
 CLEANFILES+= ${PROG}.tmp ${PROG}.map vers.c
 
-vers.c: ${VERSIONFILE} ${SOURCES} ${.CURDIR}/../Makefile.boot
+vers.c: ${VERSIONFILE} ${SOURCES} ${LIBLIST} ${.CURDIR}/../Makefile.boot
 	${HOST_SH} ${S}conf/newvers_stand.sh ${VERSIONFILE} ${MACHINE} ${NEWVERSWHAT}
 
 # Anything that calls 'real_to_prot' must have a %pc < 0x10000.
Index: sys/arch/i386/stand/boot/boot2.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/boot/boot2.c,v
retrieving revision 1.10
diff -u -r1.10 boot2.c
--- sys/arch/i386/stand/boot/boot2.c	21 Jun 2005 14:20:35 -0000	1.10
+++ sys/arch/i386/stand/boot/boot2.c	21 Jun 2005 14:22:19 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot2.c,v 1.10 2005/06/21 14:20:35 junyoung Exp $	*/
+/*	$NetBSD: boot2.c,v 1.7 2005/06/15 19:07:36 junyoung Exp $	*/
 
 /*
  * Copyright (c) 2003
@@ -56,15 +56,16 @@
 #include <biosmca.h>
 #endif
 
-int errno;
-extern int boot_biosdev;
-extern int boot_biossector;	/* may be wrong... */
-
 extern struct x86_boot_params boot_params;
 
 extern	const char bootprog_name[], bootprog_rev[], bootprog_date[],
 	bootprog_maker[];
 
+int errno;
+
+int boot_biosdev;
+u_int boot_biossector;
+
 static const char * const names[][2] = {
 	{ "netbsd", "netbsd.gz" },
 	{ "onetbsd", "onetbsd.gz" },
@@ -83,7 +84,7 @@
 char *sprint_bootsel(const char *);
 void bootit(const char *, int, int);
 void print_banner(void);
-void boot2(u_int, u_int);
+void boot2(int, u_int);
 
 void	command_help(char *);
 void	command_ls(char *);
@@ -105,11 +106,12 @@
 
 int
 parsebootfile(const char *fname, char **fsname, char **devname,
-	      u_int *unit, u_int *partition, const char **file)
+	      int *unit, int *partition, const char **file)
 {
 	const char *col;
 
-	*fsname = "ufs";
+	if (fsname != NULL)
+		*fsname = "ufs";
 	*devname = default_devname;
 	*unit = default_unit;
 	*partition = default_partition;
@@ -121,7 +123,7 @@
 	if ((col = strchr(fname, ':')) != NULL) {	/* device given */
 		static char savedevname[MAXDEVNAME+1];
 		int devlen;
-		u_int u = 0, p = 0;
+		int u = 0, p = 0;
 		int i = 0;
 
 		devlen = col - fname;
@@ -172,12 +174,12 @@
 char *
 sprint_bootsel(const char *filename)
 {
-	char *fsname, *devname;
+	char *devname;
 	int unit, partition;
 	const char *file;
 	static char buf[80];
 
-	if (parsebootfile(filename, &fsname, &devname, &unit,
+	if (parsebootfile(filename, NULL, &devname, &unit,
 			  &partition, &file) == 0) {
 		sprintf(buf, "%s%d%c:%s", devname, unit, 'a' + partition, file);
 		return buf;
@@ -213,8 +215,14 @@
 	printf(">> Memory: %d/%d k\n", getbasemem(), getextmem());
 }
 
+/*
+ * Called from the initial entry point boot_start in biosboot.S
+ *
+ * biosdev: BIOS drive number the system booted from
+ * biossector: Sector number of the NetBSD partition
+ */
 void
-boot2(u_int boot_biosdev, u_int boot_biossector)
+boot2(int biosdev, u_int biossector)
 {
 	int currname;
 	char c;
@@ -231,9 +239,13 @@
 
 	print_banner();
 
+	/* need to remember these */
+	boot_biosdev = biosdev;
+	boot_biossector = biossector;
+
 	/* try to set default device to what BIOS tells us */
-	bios2dev(boot_biosdev, &default_devname, &default_unit,
-		 boot_biossector, &default_partition);
+	bios2dev(biosdev, biossector, &default_devname, &default_unit,
+		 &default_partition);
 
 	/* if the user types "boot" without filename */
 	default_filename = DEFFILENAME;
@@ -315,7 +327,7 @@
 command_dev(char *arg)
 {
 	static char savedevname[MAXDEVNAME + 1];
-	char *fsname, *devname;
+	char *devname;
 	const char *file; /* dummy */
 
 	if (*arg == '\0') {
@@ -325,7 +337,7 @@
 	}
 
 	if (strchr(arg, ':') != NULL ||
-	    parsebootfile(arg, &fsname, &devname, &default_unit,
+	    parsebootfile(arg, NULL, &devname, &default_unit,
 			  &default_partition, &file)) {
 		command_help(NULL);
 		return;
Index: sys/arch/i386/stand/boot/conf.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/boot/conf.c,v
retrieving revision 1.2
diff -u -r1.2 conf.c
--- sys/arch/i386/stand/boot/conf.c	24 Mar 2004 16:54:18 -0000	1.2
+++ sys/arch/i386/stand/boot/conf.c	21 Jun 2005 14:22:19 -0000
@@ -39,6 +39,9 @@
 #ifdef SUPPORT_DOSFS
 #include <lib/libsa/dosfs.h>
 #endif
+#ifdef SUPPORT_CD9660
+#include <lib/libsa/cd9660.h>
+#endif
 
 #include <biosdisk.h>
 
@@ -48,6 +51,9 @@
 int ndevs = sizeof(devsw) / sizeof(struct devsw);
 
 struct fs_ops file_system[] = {
+#ifdef SUPPORT_CD9660
+	FS_OPS(cd9660),
+#endif
 #ifdef SUPPORT_USTARFS
 	FS_OPS(ustarfs),
 #endif
Index: sys/arch/i386/stand/boot/devopen.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/boot/devopen.c,v
retrieving revision 1.3
diff -u -r1.3 devopen.c
--- sys/arch/i386/stand/boot/devopen.c	15 Jun 2005 19:01:19 -0000	1.3
+++ sys/arch/i386/stand/boot/devopen.c	21 Jun 2005 14:22:19 -0000
@@ -1,5 +1,41 @@
 /*	$NetBSD: devopen.c,v 1.3 2005/06/15 19:01:19 junyoung Exp $	 */
 
+/*-
+ * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bang Jun-Young.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /*
  * Copyright (c) 1996, 1997
  *	Matthias Drochner.  All rights reserved.
@@ -41,33 +77,46 @@
 #include <biosmca.h>
 #endif
 
-static int dev2bios(char *, u_int, int *);
+static int dev2bios(char *, int, int *);
 
 static int
-dev2bios(char *devname, u_int unit, int *biosdev)
+dev2bios(char *devname, int unit, int *biosdev)
 {
+
 	if (strcmp(devname, "hd") == 0)
 		*biosdev = 0x80 + unit;
 	else if (strcmp(devname, "fd") == 0)
 		*biosdev = 0x00 + unit;
+	else if (strcmp(devname, "cd") == 0)
+		*biosdev = boot_biosdev;
 	else
 		return ENXIO;
 
 	return 0;
 }
 
-int
-bios2dev(int biosdev, char **devname, u_int *unit, u_int sector, u_int *ptnp)
+void
+bios2dev(int biosdev, u_int sector, char **devname, int *unit, int *partition)
 {
-	if (biosdev & 0x80)
-		*devname = "hd";
-	else
-		*devname = "fd";
 
+	/* set default */
 	*unit = biosdev & 0x7f;
-	*ptnp = biosdiskfindptn(biosdev, sector);
 
-	return 0;
+	if (biosdev & 0x80) {
+		/*
+		 * There seems to be no standard way of numbering BIOS
+		 * CD-ROM drives. The following method is a little tricky
+		 * but works nicely.
+		 */
+		if (biosdev >= 0x80 + get_harddrives()) {
+			*devname = "cd";
+			*unit = 0;		/* override default */
+		} else
+			*devname = "hd";
+	} else
+		*devname = "fd";
+
+	*partition = biosdiskfindptn(biosdev, sector);
 }
 
 #ifdef _STANDALONE
@@ -81,7 +130,7 @@
 devopen(struct open_file *f, const char *fname, char **file)
 {
 	char *fsname, *devname;
-	u_int unit, partition;
+	int unit, partition;
 	int biosdev;
 	int error;
 
Index: sys/arch/i386/stand/boot/devopen.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/boot/devopen.h,v
retrieving revision 1.1
diff -u -r1.1 devopen.h
--- sys/arch/i386/stand/boot/devopen.h	16 Apr 2003 22:36:14 -0000	1.1
+++ sys/arch/i386/stand/boot/devopen.h	21 Jun 2005 14:22:19 -0000
@@ -1,3 +1,5 @@
-/* $NetBSD: devopen.h,v 1.1 2003/04/16 22:36:14 dsl Exp $ */
+/*	$NetBSD: devopen.h,v 1.1 2003/04/16 22:36:14 dsl Exp $	*/
 
-int bios2dev(int, char **, u_int *, u_int, u_int *);
+extern int boot_biosdev;
+
+void bios2dev(int, u_int, char **, int *, int *);
Index: sys/arch/i386/stand/boot/version
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/boot/version,v
retrieving revision 1.3
diff -u -r1.3 version
--- sys/arch/i386/stand/boot/version	23 Oct 2004 17:20:04 -0000	1.3
+++ sys/arch/i386/stand/boot/version	21 Jun 2005 14:22:19 -0000
@@ -35,3 +35,4 @@
 	Leave space in bootxx for FAT32 BPB and MBR partition table.
 	Keep MBR's existing BPB and partition table when installing bootxx.
 3.2:	Add support for passing boot wedge information to the kernel.
+3.3:	Add support for cd9660 file system.
Index: sys/arch/i386/stand/lib/Makefile
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/Makefile,v
retrieving revision 1.22
diff -u -r1.22 Makefile
--- sys/arch/i386/stand/lib/Makefile	16 Apr 2003 22:30:40 -0000	1.22
+++ sys/arch/i386/stand/lib/Makefile	21 Jun 2005 14:22:19 -0000
@@ -18,7 +18,7 @@
 
 SRCS= pcio.c conio.S comio.S comio_direct.c biosvideomode.S
 SRCS+= getsecs.c biosgetrtc.S biosdelay.S biosreboot.S gatea20.c
-SRCS+= biosmem.S getextmemx.c biosmemx.S printmemlist.c
+SRCS+= biosmem.S getbasemem.c getextmemx.c biosmemx.S printmemlist.c
 SRCS+= pread.c menuutils.c parseutils.c
 SRCS+= bootinfo.c bootinfo_biosgeom.c bootinfo_memmap.c
 SRCS+= startprog.S panic.c
Index: sys/arch/i386/stand/lib/biosdisk.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/biosdisk.c,v
retrieving revision 1.22
diff -u -r1.22 biosdisk.c
--- sys/arch/i386/stand/lib/biosdisk.c	13 Jun 2005 11:23:28 -0000	1.22
+++ sys/arch/i386/stand/lib/biosdisk.c	21 Jun 2005 14:22:19 -0000
@@ -78,7 +78,7 @@
 #include "bootinfo.h"
 #endif
 
-#define BUFSIZE (1 * BIOSDISK_SECSIZE)
+#define BUFSIZE	2048	/* must be large enough for a CD sector */
 
 struct biosdisk {
 	struct biosdisk_ll ll;
@@ -93,8 +93,6 @@
 
 #define	RF_PROTECTED_SECTORS	64	/* XXX refer to <.../rf_optnames.h> */
 
-int boot_biossector;	/* disk sector partition might have started in */
-
 int
 biosdiskstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
 		 void *buf, size_t *rsize)
@@ -109,22 +107,22 @@
 
 	dblk += d->boff;
 
-	blks = size / BIOSDISK_SECSIZE;
+	blks = size / d->ll.secsize;
 	if (blks && readsects(&d->ll, dblk, blks, buf, 0)) {
 		if (rsize)
 			*rsize = 0;
 		return EIO;
 	}
 
-	/* do we really need this? */
-	frag = size % BIOSDISK_SECSIZE;
+	/* needed for CD */
+	frag = size % d->ll.secsize;
 	if (frag) {
 		if (readsects(&d->ll, dblk + blks, 1, d->buf, 0)) {
 			if (rsize)
-				*rsize = blks * BIOSDISK_SECSIZE;
+				*rsize = blks * d->ll.secsize;
 			return EIO;
 		}
-		memcpy(buf + blks * BIOSDISK_SECSIZE, d->buf, frag);
+		memcpy(buf + blks * d->ll.secsize, d->buf, frag);
 	}
 
 	if (rsize)
@@ -133,21 +131,21 @@
 }
 
 static struct biosdisk *
-alloc_biosdisk(int dev)
+alloc_biosdisk(int biosdev)
 {
 	struct biosdisk *d;
 
-	d = alloc(sizeof *d);
+	d = alloc(sizeof(*d));
 	if (d == NULL)
 		return NULL;
-	memset(d, 0, sizeof *d);
+	memset(d, 0, sizeof(*d));
 
-	d->ll.dev = dev;
+	d->ll.dev = biosdev;
 	if (set_geometry(&d->ll, NULL)) {
 #ifdef DISK_DEBUG
 		printf("no geometry information\n");
 #endif
-		free(d, sizeof *d);
+		free(d, sizeof(*d));
 		return NULL;
 	}
 	return d;
@@ -192,13 +190,13 @@
 	int sector_386bsd = -1;
 #endif
 
-	memset(&dflt_lbl, 0, sizeof dflt_lbl);
+	memset(&dflt_lbl, 0, sizeof(dflt_lbl));
 	dflt_lbl.d_npartitions = 8;
 
 	d->boff = 0;
 
-	if (!(d->ll.dev & 0x80)) /* floppy */
-		/* No label on floppy */
+	if (d->ll.type != BIOSDISK_TYPE_HD)
+		/* No label on floppy or CD */
 		return -1;
 
 	/*
@@ -216,7 +214,8 @@
 #endif
 			return EIO;
 		}
-		memcpy(&mbr, ((struct mbr_sector *)d->buf)->mbr_parts, sizeof mbr);
+		memcpy(&mbr, ((struct mbr_sector *)d->buf)->mbr_parts,
+		       sizeof(mbr));
 		/* Look for NetBSD partition ID */
 		for (i = 0; i < MBR_PART_COUNT; i++) {
 			typ = mbr[i].mbrp_type;
@@ -279,7 +278,7 @@
 	 */
 	/* XXX fill it to make checksum match kernel one */
 	dflt_lbl.d_checksum = dkcksum(&dflt_lbl);
-	memcpy(d->buf, &dflt_lbl, sizeof dflt_lbl);
+	memcpy(d->buf, &dflt_lbl, sizeof(dflt_lbl));
 	return -1;
 }
 #endif /* NO_DISKLABEL */
@@ -288,14 +287,14 @@
  * partition.
  */
 
-u_int
+int
 biosdiskfindptn(int biosdev, u_int sector)
 {
 #ifdef NO_DISKLABEL
 	return 0;
 #else
 	struct biosdisk *d;
-	u_int partition = 0;
+	int partition = 0;
 	struct disklabel *lp;
 
 	/* Look for netbsd partition that is the dos boot one */
@@ -313,17 +312,18 @@
 		}
 	}
 
-	free(d, sizeof *d);
+	free(d, sizeof(*d));
 	return partition;
 #endif /* NO_DISKLABEL */
 }
 
 int
 biosdiskopen(struct open_file *f, ...)
-/* file, biosdev, partition */
+/* struct open_file *f, int biosdev, int partition */
 {
 	va_list ap;
 	struct biosdisk *d;
+	int biosdev;
 	int partition;
 #ifndef NO_DISKLABEL
 	struct disklabel *lp;
@@ -331,8 +331,9 @@
 	int error = 0;
 
 	va_start(ap, f);
-	d = alloc_biosdisk(va_arg(ap, int));
-	if (!d) {
+	biosdev = va_arg(ap, int);
+	d = alloc_biosdisk(biosdev);
+	if (d == NULL) {
 		error = ENXIO;
 		goto out;
 	}
@@ -360,7 +361,7 @@
 
 	lp = (struct disklabel *) (d->buf + LABELOFFSET);
 	if (partition >= lp->d_npartitions ||
-	   lp->d_partitions[partition].p_fstype == FS_UNUSED) {
+	    lp->d_partitions[partition].p_fstype == FS_UNUSED) {
 #ifdef DISK_DEBUG
 		printf("illegal partition\n");
 #endif
@@ -414,7 +415,8 @@
 {
 	struct biosdisk *d = f->f_devdata;
 
-	if (!(d->ll.dev & 0x80))/* let the floppy drive go off */
+	/* let the floppy drive go off */
+	if (d->ll.type == BIOSDISK_TYPE_FD)
 		delay(3000000);	/* 2s is enough on all PCs I found */
 
 	free(d, sizeof(struct biosdisk));
Index: sys/arch/i386/stand/lib/biosdisk.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/biosdisk.h,v
retrieving revision 1.4
diff -u -r1.4 biosdisk.h
--- sys/arch/i386/stand/lib/biosdisk.h	24 Mar 2004 16:46:27 -0000	1.4
+++ sys/arch/i386/stand/lib/biosdisk.h	21 Jun 2005 14:22:19 -0000
@@ -29,5 +29,5 @@
 int biosdiskopen(struct open_file *, ...);
 int biosdiskclose(struct open_file *);
 int biosdiskioctl(struct open_file *, u_long, void *);
-u_int biosdiskfindptn(int, u_int);
+int biosdiskfindptn(int, u_int);
 
Index: sys/arch/i386/stand/lib/biosdisk_ll.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/biosdisk_ll.c,v
retrieving revision 1.20
diff -u -r1.20 biosdisk_ll.c
--- sys/arch/i386/stand/lib/biosdisk_ll.c	13 Jun 2005 11:27:40 -0000	1.20
+++ sys/arch/i386/stand/lib/biosdisk_ll.c	21 Jun 2005 14:22:19 -0000
@@ -1,5 +1,41 @@
 /*	$NetBSD: biosdisk_ll.c,v 1.20 2005/06/13 11:27:40 junyoung Exp $	 */
 
+/*-
+ * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bang Jun-Young.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /*
  * Copyright (c) 1996
  * 	Matthias Drochner.  All rights reserved.
@@ -50,8 +86,8 @@
 
 /*
  * we get from get_diskinfo():
- * xxxx  %ch  %cl  %dh (registers after int13/8), ie
- * xxxx cccc Csss hhhh
+ *   unused      %ch      %cl      %dh (registers after int13/8), ie
+ * xxxxxxxx cccccccc CCssssss hhhhhhhh
  */
 #define	SPT(di)		(((di)>>8)&0x3f)
 #define	HEADS(di)	(((di)&0xff)+1)
@@ -65,7 +101,6 @@
 set_geometry(struct biosdisk_ll *d, struct biosdisk_ext13info *ed)
 {
 	int diskinfo;
-	char buf[512];
 
 	diskinfo = get_diskinfo(d->dev);
 	d->sec = SPT(diskinfo);
@@ -73,11 +108,31 @@
 	d->cyl = CYL(diskinfo);
 	d->chs_sectors = d->sec * d->head * d->cyl;
 
+	if (d->dev >= 0x80 + get_harddrives()) {
+		d->secsize = 2048;
+		d->type = BIOSDISK_TYPE_CD;
+	} else {
+		d->secsize = 512;
+		if (d->dev & 0x80)
+			d->type = BIOSDISK_TYPE_HD;
+		else
+			d->type = BIOSDISK_TYPE_FD;
+	}
+
+	/*
+	 * Some broken BIOSes such as one found on Soltek SL-75DRV2 report
+	 * that they don't support int13 extension for CD-ROM drives while
+	 * they actually do. As a workaround, if the boot device is a CD we
+	 * assume that the extension is available. Note that only very old
+	 * BIOSes don't support the extended mode, and they don't work with
+	 * ATAPI CD-ROM drives, either. So there's no problem.
+	 */
 	d->flags = 0;
-	if ((d->dev & 0x80) && int13_extension(d->dev)) {
+	if (d->type == BIOSDISK_TYPE_CD ||
+	    (d->type == BIOSDISK_TYPE_HD && int13_extension(d->dev))) {
 		d->flags |= BIOSDISK_EXT13;
 		if (ed != NULL) {
-			ed->size = sizeof *ed;
+			ed->size = sizeof(*ed);
 			int13_getextinfo(d->dev, ed);
 		}
 	}
@@ -86,18 +141,16 @@
 	 * If the drive is 2.88MB floppy drive, check that we can actually
 	 * read sector >= 18. If not, assume 1.44MB floppy disk.
 	 */
-	if (d->dev == 0 && SPT(diskinfo) == 36) {
+	if (d->type == BIOSDISK_TYPE_FD && SPT(diskinfo) == 36) {
+		char buf[512];
+
 		if (biosread(d->dev, 0, 0, 18, 1, buf)) {
 			d->sec = 18;
 			d->chs_sectors /= 2;
 		}
 	}
 
-	/*
-	 * get_diskinfo assumes floppy if BIOS call fails. Check at least
-	 * "valid" geometry.
-	 */
-	return (!d->sec || !d->head);
+	return 0;
 }
 
 /*
@@ -105,7 +158,6 @@
  * floppies, the bootstrap has to be loaded on a 64K boundary to ensure that
  * this buffer doesn't cross a 64K DMA boundary.
  */
-#define RA_SECTORS      (DISKBUFSIZE / BIOSDISK_SECSIZE)
 static int      ra_dev;
 static int      ra_end;
 static int      ra_first;
@@ -126,23 +178,25 @@
 	(((d)->dev & 0x80) != 0)
 #else
 #define	NEED_INT13EXT(d, dblk, num)				\
-	(((d)->dev & 0x80) != 0 && ((dblk) + (num)) >= (d)->chs_sectors)
+	(((d)->type == BIOSDISK_TYPE_CD) ||                     \
+	 ((d)->type == BIOSDISK_TYPE_HD &&			\
+	  ((dblk) + (num)) >= (d)->chs_sectors))
 #endif
 
 static int
 do_read(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf)
 {
-	int		cyl, head, sec, nsec, spc, dblk32;
-	struct {
-		int8_t	size;
-		int8_t	resvd;
-		int16_t	cnt;
-		int16_t	off;
-		int16_t	seg;
-		int64_t	sec;
-	}		ext;
 
 	if (NEED_INT13EXT(d, dblk, num)) {
+		struct {
+			int8_t size;
+			int8_t resvd;
+			int16_t cnt;
+			int16_t off;
+			int16_t seg;
+			int64_t sec;
+		} ext;
+
 		if (!(d->flags & BIOSDISK_EXT13))
 			return -1;
 		ext.size = sizeof(ext);
@@ -160,6 +214,8 @@
 
 		return ext.cnt;
 	} else {
+		int cyl, head, sec, nsec, spc, dblk32;
+
 		dblk32 = (int)dblk;
 		spc = d->head * d->sec;
 		cyl = dblk32 / spc;
@@ -179,11 +235,10 @@
 	}
 }
 
-/* NB if 'cold' is set below not all of the program is loaded, so
- * musn't use data segment, bss, call library functions or do
- * read-ahead.
+/*
+ * NB if 'cold' is set below not all of the program is loaded, so
+ * mustn't use data segment, bss, call library functions or do read-ahead.
  */
-
 int
 readsects(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf, int cold)
 {
@@ -209,7 +264,7 @@
 			} else {
 				/* fill read-ahead buffer */
 				trbuf = alloc_diskbuf(0); /* no data yet */
-				maxsecs = RA_SECTORS;
+				maxsecs = DISKBUFSIZE / d->secsize;
 			}
 
 			while ((nsec = do_read(d, dblk, maxsecs, trbuf)) < 0) {
@@ -238,13 +293,31 @@
 			if (nsec > num)
 				nsec = num;
 			memcpy(buf,
-			       diskbufp + (dblk - ra_first) * BIOSDISK_SECSIZE,
-			       nsec * BIOSDISK_SECSIZE);
+			       diskbufp + (dblk - ra_first) * d->secsize,
+			       nsec * d->secsize);
 		}
-		buf += nsec * BIOSDISK_SECSIZE;
+		buf += nsec * d->secsize;
 		num -= nsec;
 		dblk += nsec;
 	}
 
 	return 0;
 }
+
+/*
+ * Return the number of hard disk drives.
+ */
+int
+get_harddrives(void)
+{
+	/*
+	 * Some BIOSes are buggy so that they return incorrect number
+	 * of hard drives with int13/ah=8. We read a byte at 0040:0075
+	 * instead, which is known to be always correct.
+	 */
+	int n = 0;
+
+	pvbcopy((void *)0x475, &n, 1);
+
+	return n;
+}
Index: sys/arch/i386/stand/lib/biosdisk_ll.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/biosdisk_ll.h,v
retrieving revision 1.10
diff -u -r1.10 biosdisk_ll.h
--- sys/arch/i386/stand/lib/biosdisk_ll.h	13 Jun 2005 11:34:11 -0000	1.10
+++ sys/arch/i386/stand/lib/biosdisk_ll.h	21 Jun 2005 14:22:19 -0000
@@ -46,12 +46,18 @@
  */
 struct biosdisk_ll {
 	int             dev;		/* BIOS device number */
+	int		type;		/* device type; see below */
 	int             sec, head, cyl;	/* geometry */
 	int		flags;		/* see below */
 	int		chs_sectors;	/* # of sectors addressable by CHS */
+	int		secsize;	/* bytes per sector */
 };
 #define	BIOSDISK_EXT13	1		/* BIOS supports int13 extension */
 
+#define BIOSDISK_TYPE_FD	0
+#define BIOSDISK_TYPE_HD	1
+#define BIOSDISK_TYPE_CD	2
+
 /*
  * Version 1.x drive parameters from int13 extensions
  * - should be supported by every BIOS that supports the extensions.
@@ -114,7 +120,5 @@
 #define EXT13_LOCKABLE		0x0020	/* device is lockable */
 #define EXT13_MAXGEOM		0x0040	/* geometry set to max; no media */
 
-#define BIOSDISK_SECSIZE 512
-
 int set_geometry(struct biosdisk_ll *, struct biosdisk_ext13info *);
 int readsects(struct biosdisk_ll *, daddr_t, int, char *, int);
Index: sys/arch/i386/stand/lib/biosmem.S
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/biosmem.S,v
retrieving revision 1.6
diff -u -r1.6 biosmem.S
--- sys/arch/i386/stand/lib/biosmem.S	1 Feb 2003 14:48:18 -0000	1.6
+++ sys/arch/i386/stand/lib/biosmem.S	21 Jun 2005 14:22:19 -0000
@@ -31,42 +31,12 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-	
 
-#include <machine/asm.h>
 
-#define	data32	.byte 0x66
+#include <machine/asm.h>
 
 	.text
 
-/* get mem below 1M, in kByte */
-
-ENTRY(getbasemem)
-	pushl	%ebp
-	movl	%esp,%ebp
-	pushl	%ebx
-	push	%esi
-	push	%edi
-
-	call	_C_LABEL(prot_to_real)
-	.code16
-
-	int	$0x12
-	# zero-extend 16-bit result to 32 bits.
-	movl	$0, %ebx
-	mov	%ax,%bx
-
-	calll	_C_LABEL(real_to_prot)
-	.code32
-
-	movl	%ebx, %eax
-
-	pop	%edi
-	pop	%esi
-	popl	%ebx
-	popl	%ebp
-	ret
-
 /* get mem above 1M, in kByte */
 
 ENTRY(getextmem1)
Index: sys/arch/i386/stand/lib/bootinfo_biosgeom.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/bootinfo_biosgeom.c,v
retrieving revision 1.13
diff -u -r1.13 bootinfo_biosgeom.c
--- sys/arch/i386/stand/lib/bootinfo_biosgeom.c	24 Mar 2004 16:46:28 -0000	1.13
+++ sys/arch/i386/stand/lib/bootinfo_biosgeom.c	21 Jun 2005 14:22:19 -0000
@@ -37,6 +37,8 @@
 #include "biosdisk_ll.h"
 #include "bootinfo.h"
 
+#define BIOSDISK_SECSIZE	512	/* XXX */
+
 #ifdef BIOSDISK_EXT13INFO_V3
 static struct {
 	char	*name;
@@ -56,27 +58,28 @@
 		    {NULL, BI_GEOM_IFACE_OTHER} };
 #endif
 
-void bi_getbiosgeom()
+void
+bi_getbiosgeom(void)
 {
 	struct btinfo_biosgeom *bibg;
 	int i, j, nvalid;
-	unsigned char nhd;
+	int nhd;
 	unsigned int cksum;
 	struct biosdisk_ll d;
 	struct biosdisk_ext13info ed;
 	char buf[BIOSDISK_SECSIZE];
 
-	pvbcopy((void *)(0x400 + 0x75), &nhd, 1);
+	nhd = get_harddrives();
 #ifdef GEOM_DEBUG
-	printf("nhd %d\n", (int)nhd);
+	printf("nhd %d\n", nhd);
 #endif
 
 	bibg = alloc(sizeof(struct btinfo_biosgeom)
 		     + (nhd - 1) * sizeof(struct bi_biosgeom_entry));
-	if (!bibg)
+	if (bibg == NULL)
 		return;
 
-	for (i = nvalid = 0; i < MAX_BIOSDISKS && nvalid < (int)nhd; i++) {
+	for (i = nvalid = 0; i < MAX_BIOSDISKS && nvalid < nhd; i++) {
 
 		d.dev = 0x80 + i;
 
@@ -97,10 +100,10 @@
 
 #ifdef GEOM_DEBUG
 		printf("#%d: %x: C %d H %d S %d\n", nvalid,
-		    d.dev, d.cyl, d.head, d.sec);
+		       d.dev, d.cyl, d.head, d.sec);
 		printf("   sz %d fl %x cyl %d head %d sec %d totsec %lld sbytes %d\n",
-			ed.size, ed.flags, ed.cyl, ed.head, ed.sec,
-			ed.totsec, ed.sbytes);
+		       ed.size, ed.flags, ed.cyl, ed.head, ed.sec,
+		       ed.totsec, ed.sbytes);
 #endif
 
 		if (d.flags & BIOSDISK_EXT13) {
@@ -110,8 +113,8 @@
 #ifdef BIOSDISK_EXT13INFO_V3
 #ifdef GEOM_DEBUG
 		printf("   edd_cfg %x, sig %x, len %x, bus %s type %s\n",
-			ed.edd_cfg, ed.devpath_sig, ed.devpath_len,
-			ed.host_bus, ed.iface_type);
+		       ed.edd_cfg, ed.devpath_sig, ed.devpath_len,
+		       ed.host_bus, ed.iface_type);
 #endif
 
 		/* The v3.0 stuff will help identify the disks */
@@ -120,7 +123,7 @@
 			char *cp;
 
 			for (cp = (void *)&ed.devpath_sig, cksum = 0;
-			    cp <= (char *)&ed.checksum; cp++) {
+			     cp <= (char *)&ed.checksum; cp++) {
 				cksum += *cp;
 			}
 			if ((cksum & 0xff) != 0)
@@ -133,12 +136,12 @@
 				if (cp == NULL)
 					break;
 				if (strncmp(cp, ed.host_bus,
-				    sizeof ed.host_bus) == 0)
+					    sizeof(ed.host_bus)) == 0)
 					break;
 			}
 #ifdef GEOM_DEBUG
 			printf("bus %s (%x)\n", cp ? cp : "null",
-					bus_names[j].flag);
+			       bus_names[j].flag);
 #endif
 			bibg->disk[nvalid].flags |= bus_names[j].flag;
 			for (j = 0; ; j++) {
@@ -146,7 +149,7 @@
 				if (cp == NULL)
 					break;
 				if (strncmp(cp, ed.iface_type,
-				    sizeof ed.iface_type) == 0)
+					    sizeof(ed.iface_type)) == 0)
 					break;
 			}
 			bibg->disk[nvalid].flags |= iface_names[j].flag;
@@ -157,10 +160,10 @@
 					ed.device_path.dp_64[0];
 #ifdef GEOM_DEBUG
 			printf("device %s (%x) interface %x path %llx\n",
-					cp ? cp : "null",
-					iface_names[j].flag,
-					ed.interface_path.ip_32[0],
-					ed.device_path.dp_64[0]);
+			       cp ? cp : "null",
+			       iface_names[j].flag,
+			       ed.interface_path.ip_32[0],
+			       ed.device_path.dp_64[0]);
 #endif
 		}
 #endif
@@ -169,7 +172,7 @@
 			cksum += buf[j];
 		bibg->disk[nvalid].cksum = cksum;
 		memcpy(bibg->disk[nvalid].dosparts, &buf[MBR_PART_OFFSET],
-		    sizeof(bibg->disk[nvalid].dosparts));
+		       sizeof(bibg->disk[nvalid].dosparts));
 		nvalid++;
 	}
 
Index: sys/arch/i386/stand/lib/exec.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/exec.c,v
retrieving revision 1.20
diff -u -r1.20 exec.c
--- sys/arch/i386/stand/lib/exec.c	10 Nov 2003 08:51:52 -0000	1.20
+++ sys/arch/i386/stand/lib/exec.c	21 Jun 2005 14:22:19 -0000
@@ -92,11 +92,8 @@
 
 extern struct btinfo_console btinfo_console;
 
-int 
-exec_netbsd(file, loadaddr, boothowto)
-	const char     *file;
-	physaddr_t      loadaddr;
-	int             boothowto;
+int
+exec_netbsd(const char *file, physaddr_t loadaddr, int boothowto)
 {
 	u_long          boot_argv[BOOT_NARGS];
 	int		fd;
@@ -134,7 +131,7 @@
 		 */
 		if (xmsmem > extmem)
 			extmem = xmsmem;
-		/* 
+		/*
 		 * Get the size of the kernel
 		 */
 		marks[MARK_START] = loadaddr;
@@ -147,7 +144,7 @@
 
 		loadaddr = xmsalloc(kernsize);
 		if (!loadaddr)
-			return(ENOMEM);
+			return ENOMEM;
 	}
 #endif
 	marks[MARK_START] = loadaddr;
@@ -206,11 +203,11 @@
 	BI_ADD(&btinfo_symtab, BTINFO_SYMTAB, sizeof(struct btinfo_symtab));
 
 	startprog(marks[MARK_ENTRY], BOOT_NARGS, boot_argv,
-		x86_trunc_page(basemem*1024));
+		  x86_trunc_page(basemem*1024));
 	panic("exec returned");
 
 out:
 	BI_FREE();
 	bootinfo = 0;
-	return (-1);
+	return -1;
 }
Index: sys/arch/i386/stand/lib/libi386.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/libi386.h,v
retrieving revision 1.19
diff -u -r1.19 libi386.h
--- sys/arch/i386/stand/lib/libi386.h	13 Jun 2005 11:37:41 -0000	1.19
+++ sys/arch/i386/stand/lib/libi386.h	21 Jun 2005 14:22:19 -0000
@@ -68,8 +68,8 @@
 char awaitkey(int, int);
 
 /* this is in "user code"! */
-int parsebootfile(const char *, char **, char **, unsigned int *,
-		  unsigned int *, const char **);
+int parsebootfile(const char *, char **, char **, int *, int *,
+		  const char **);
 
 #ifdef XMS
 physaddr_t ppbcopy(physaddr_t, physaddr_t, int);
@@ -119,6 +119,8 @@
 int int13_extension(int);
 struct biosdisk_ext13info;
 void int13_getextinfo(int, struct biosdisk_ext13info *);
+int get_harddrives(void);
+
 int pcibios_cfgread(unsigned int, int, int *);
 int pcibios_cfgwrite(unsigned int, int, int);
 int pcibios_finddev(int, int, int, unsigned int *);
Index: sys/lib/libsa/cd9660.c
===================================================================
RCS file: /cvsroot/src/sys/lib/libsa/cd9660.c,v
retrieving revision 1.18
diff -u -r1.18 cd9660.c
--- sys/lib/libsa/cd9660.c	13 Jun 2005 12:06:36 -0000	1.18
+++ sys/lib/libsa/cd9660.c	21 Jun 2005 14:22:21 -0000
@@ -71,7 +71,7 @@
 #define	PTFIXSZ		8
 #define	PTSIZE(pp)	roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
 
-#define	cdb2devb(bno)	((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
+#define	cdb2devb(bno)	(bno)
 
 static int	pnmatch(const char *, struct ptable_ent *);
 static int	dirmatch(const char *, struct iso_directory_record *);
--- /dev/null	2005-06-21 23:10:27.000000000 +0900
+++ sys/arch/i386/stand/lib/getbasemem.c	2005-06-20 14:14:27.000000000 +0900
@@ -0,0 +1,28 @@
+/*	$NetBSD$	*/
+
+/*
+ * Written by Bang Jun-Young, 2005.
+ *
+ * This file is placed in public domain.
+ */
+
+#include <lib/libsa/stand.h>
+
+#include "libi386.h"
+
+/*
+ * Return the size of the base memory in kB.
+ */
+int
+getbasemem(void)
+{
+	int memsize = 0;
+
+	/*
+	 * Instead of using int12 which is reported to be buggy on some
+	 * BIOSes, read a 16-bit word located in the BIOS data area.
+	 */
+	pvbcopy((void *)0x413, &memsize, 2);
+
+	return memsize;
+}

--Boundary-00=_NaCuCN2P1fCtx/a--