Subject: Re: Support for PS/2 esdi disks in bootblocks
To: Rafal Boni <rafal@mediaone.net>
From: Jaromír <jdolecek@netbsd.org>
List: port-i386
Date: 05/07/2001 17:28:55
--ELM989249335-326-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII

Rafal Boni wrote:
> That's great, in that case we can DTRT and not force non-MCA ESDI disks
> to in effect be obsoleted.

Okay, I've implemented an easier way to do it - if the machine is a
PS/2, DTYPE_ESDI disks are treated as ed(4), otherwise they
fallback to wd(4). I've also changed gateA20() to check
the machine model and use the L40 initialize code if appropriate
(so the thing is runtime option, rather than compile time).
The size different between "old" and "new" biosboot[_com0].sym is like
280 bytes.

However, I recognize this way is not quite right. It's my understanding
that there are some MCA wd1000/wd2000 controller cards and hence
it IS probably possible to have a wd(4)-type disk in an PS/2 too.
I don't know if those are bootable, though.
Since it's impossible to say until I'd have such machine/card available,
I think it's probably okay to get away with the above check only.
It would be possible to write something which would check if
ed(4) is actually installed and it's geometry matches the bios disk,
but that looks like unnecessary bloat in this case.

Jaromir
-- 
Jaromir Dolecek <jdolecek@NetBSD.org>      http://www.ics.muni.cz/~dolecek/
NetBSD - just plain best OS! -=*=- Got spare MCA cards or docs? Hand me them!

--ELM989249335-326-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=ISO-8859-2
Content-Disposition: attachment; filename=biosboot.ps2.diff

Index: biosboot/Makefile
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/biosboot/Makefile,v
retrieving revision 1.35
diff -u -p -r1.35 Makefile
--- biosboot/Makefile	2001/05/02 13:43:11	1.35
+++ biosboot/Makefile	2001/05/07 15:25:04
@@ -15,7 +15,7 @@ SRCS= main.c devopen.c conf.c exec.c
 
 CLEANFILES+= ${BSSTART}
 
-CPPFLAGS+= -DCOMPAT_OLDBOOT -DCOMPAT_386BSD_MBRPART
+CPPFLAGS+= -DCOMPAT_OLDBOOT -DCOMPAT_386BSD_MBRPART -DSUPPORT_PS2
 
 .if (${BASE} == "biosboot")
 # Various serial line configurations
Index: biosboot/devopen.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/biosboot/devopen.c,v
retrieving revision 1.9
diff -u -p -r1.9 devopen.c
--- biosboot/devopen.c	1999/10/28 05:20:05	1.9
+++ biosboot/devopen.c	2001/05/07 15:25:04
@@ -46,6 +46,9 @@
 #ifdef _STANDALONE
 #include <bootinfo.h>
 #endif
+#ifdef SUPPORT_PS2
+#include <biosmca.h>
+#endif
 
 extern int parsebootfile __P((const char *, char**, char**, unsigned int*,
 			      unsigned int*, const char**));
@@ -54,7 +57,7 @@ static int dev2bios __P((char *, unsigne
 
 static struct {
 	char           *name;
-	int             biosdev;
+	u_int8_t       biosdev;
 }               biosdevtab[] = {
 	{
 		"fd", 0
@@ -68,8 +71,13 @@ static struct {
 	},
 	{
 		"sd", 0x80
+	},
+#ifdef SUPPORT_PS2
+	{
+		"ed", 0x80
 	}
-#endif
+#endif /* SUPPORT_PS2 */
+#endif /* COMPAT_OLDBOOT */
 };
 #define NUMBIOSDEVS (sizeof(biosdevtab) / sizeof(biosdevtab[0]))
 
@@ -98,22 +106,30 @@ bios2dev(biosdev, devname, unit)
 	char          **devname;
 	unsigned int   *unit;
 {
+	u_int8_t devidx;
+
 	if (biosdev & 0x80) {
 #if defined(COMPAT_OLDBOOT) && defined(_STANDALONE)
 		extern struct disklabel disklabel;
 
-		if(disklabel.d_magic == DISKMAGIC) {
-			if(disklabel.d_type == DTYPE_SCSI)
-				*devname = biosdevtab[3].name;
+		if (disklabel.d_magic == DISKMAGIC) {
+			if (disklabel.d_type == DTYPE_SCSI)
+				devidx = 3;
+#ifdef SUPPORT_PS2
+			else if (disklabel.d_type == DTYPE_ESDI
+				 && biosmca_ps2model)
+				devidx = 4;
+#endif
 			else
-				*devname = biosdevtab[2].name;
+				devidx = 2;
 		} else
 #endif
 			/* call it "hd", we don't know better */
-			*devname = biosdevtab[1].name;
+			devidx = 1;
 	} else
-		*devname = biosdevtab[0].name;
+		devidx = 0;
 
+	*devname = biosdevtab[devidx].name;
 	*unit = biosdev & 0x7f;
 
 	return (0);
Index: biosboot/main.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/biosboot/main.c,v
retrieving revision 1.24
diff -u -p -r1.24 main.c
--- biosboot/main.c	2000/09/24 18:28:21	1.24
+++ biosboot/main.c	2001/05/07 15:25:04
@@ -47,6 +47,10 @@
 #include <libi386.h>
 #include "devopen.h"
 
+#ifdef SUPPORT_PS2
+#include <biosmca.h>
+#endif
+
 int errno;
 extern int boot_biosdev;
 
@@ -232,6 +236,10 @@ main()
 	initio(SUPPORT_SERIAL);
 #else
 	initio(CONSDEV_PC);
+#endif
+
+#ifdef SUPPORT_PS2
+	biosmca();
 #endif
 	gateA20();
 
Index: biosboot/version
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/biosboot/version,v
retrieving revision 1.9
diff -u -p -r1.9 version
--- biosboot/version	2000/09/24 12:32:35	1.9
+++ biosboot/version	2001/05/07 15:25:04
@@ -15,3 +15,6 @@ is taken as the current.
 2.6:	Support ELF boot.
 2.7:	Support on-the-fly switching of console devices.
 2.8:	Support verbose/quiet boot.
+2.9:	Recognize ESDI disks and identify them as ed(4)
+	Recognize PS/2 L40 at runtime and use appropriate gate A20
+	initialization (rather than using a compile flag)
Index: lib/Makefile
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/lib/Makefile,v
retrieving revision 1.17
diff -u -p -r1.17 Makefile
--- lib/Makefile	2000/09/24 18:13:54	1.17
+++ lib/Makefile	2001/05/07 15:25:04
@@ -9,6 +9,7 @@ MKPROFILE=no
 I386_INCLUDE_DISK?= yes
 I386_INCLUDE_DOS?= no
 I386_INCLUDE_BUS?= no
+I386_INCLUDE_PS2?= yes
 
 CPPFLAGS= -I$S/lib/libsa ${I386CPPFLAGS} ${I386MISCCPPFLAGS}
 #CPPFLAGS+= -DDISK_DEBUG
@@ -32,6 +33,9 @@ SRCS+= diskbuf.c
 .endif
 .if (${I386_INCLUDE_BUS} == "yes")
 SRCS+= biospci.c bios_pci.S isapnp.c isadma.c
+.endif
+.if (${I386_INCLUDE_PS2} == "yes")
+SRCS+= biosmca.S
 .endif
 
 .include <bsd.lib.mk>
Index: lib/biosmca.S
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/lib/biosmca.S,v
retrieving revision 1.1
diff -u -p -r1.1 biosmca.S
--- lib/biosmca.S	2001/05/02 13:41:07	1.1
+++ lib/biosmca.S	2001/05/07 15:25:04
@@ -58,13 +58,18 @@ WITH THE USE OR PERFORMANCE OF THIS SOFT
 #define	addr32	.byte 0x67
 #define	data32	.byte 0x66
 
+	.data
+	.globl _C_LABEL(biosmca_ps2model)
+_C_LABEL(biosmca_ps2model):	.long 0
+
+	.text
 /*
 # BIOS call "INT 0x15 Function 0xc0" to read extended sys config info on PS/2
-#	Return:		
-#			%ah = 0x0 on success; err code on failure
-#			%es:%bx = segment:offset of ROM address of sys config
-# Called like
-#	biosmca(&model, &features)
+#	Return:		no return value
+#
+# This function initializes biosmca_ps2model with model number as
+# identified by BIOS, if the machine is a PS/2 box (i.e. has MCA bus
+# instead of ISA).
 */
 ENTRY(biosmca)
 	pushl	%ebp
@@ -74,41 +79,41 @@ ENTRY(biosmca)
 	push	%edx
 	push	%esi
 	push	%edi
+	push	%eax
 
 	call	_C_LABEL(prot_to_real)	# enter real mode
 
+	# zero %cx
+	data32
+	xorl	%cx, %cx
+
 	data32
-	movl    $0xa0, %ax	# set table length to 0
+	xorl	%ax, %ax
 	movb	$0xc0, %ah	# subfunction
 	int	$0x15
-	jc	err
+	jc	back
 
+	# check feature byte 1 if MCA bus present and replaces ISA
 	addr32
-	movl	%es, %cx
+	movb	%es:5(%ebx), %ax
+	andw	$0x02, %ax	# bit 1 set means MCA instead of ISA
+	cmpw	$0x02, %ax	# see also arch/i386/mca/mca_machdep.c
+	jne	back
+	
+	# save model and submodel bytes to %cx
 	addr32
-	movl	%bx, %dx
-	data32
-	movl	%ax, %bx
-	jmp	back
-
-err:
-	data32
-	movb	$0, %bx
+	movb	%es:2(%ebx), %ch	# model (1 byte)
+	addr32
+	movb	%es:3(%ebx), %cl	# submodel (1 byte)
 
 back:
 	data32
 	call	_C_LABEL(real_to_prot) # back to protected mode
 
-	xorl	%eax, %eax
-	movw	%bx, %ax	# return value in %ax
-
 	# save model
-	movl	28(%esp), %ebx
-	movl	%ecx, 0(%ebx)
-	# save bios rev & features
-	movl	32(%esp), %ebx
-	movl	%edx, 0(%ebx)
+	movl	%ecx, _C_LABEL(biosmca_ps2model)
 
+	pop	%eax
 	pop	%edi
 	pop	%esi
 	pop	%edx
Index: lib/exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/lib/exec.c,v
retrieving revision 1.15
diff -u -p -r1.15 exec.c
--- lib/exec.c	2000/02/22 07:45:04	1.15
+++ lib/exec.c	2001/05/07 15:25:04
@@ -58,6 +58,9 @@
 #include "loadfile.h"
 #include "libi386.h"
 #include "bootinfo.h"
+#ifdef SUPPORT_PS2
+#include "biosmca.h"
+#endif
 
 #ifdef COMPAT_OLDBOOT
 static int dev2major __P((char *, int *));
@@ -67,13 +70,23 @@ dev2major(devname, major)
 	char           *devname;
 	int            *major;
 {
-	static char    *devices[] = {"wd", "", "fd", "", "sd"};
-#define NUMDEVICES (sizeof(devices)/sizeof(char *))
+	static const struct {
+		const char *name;
+		int maj;
+	} devices[] = {
+		{ "wd", 0  },
+		{ "fd", 2  },
+		{ "sd", 4  },
+#ifdef SUPPORT_PS2
+		{ "ed", 20 },
+#endif
+	};
+#define NUMDEVICES (sizeof(devices)/sizeof(devices[0]))
 	int             i;
 
 	for (i = 0; i < NUMDEVICES; i++)
-		if (!strcmp(devname, devices[i])) {
-			*major = i;
+		if (!strcmp(devname, devices[i].name)) {
+			*major = devices[i].maj;
 			return (0);
 		}
 	return (-1);
@@ -166,10 +179,21 @@ exec_netbsd(file, loadaddr, boothowto)
 			/* generic BIOS disk, have to guess type */
 			struct open_file *f = &files[fd];	/* XXX */
 
-			if (biosdisk_gettype(f) == DTYPE_SCSI)
+			switch (biosdisk_gettype(f)) {
+			case DTYPE_SCSI:
 				devname = "sd";
-			else
+				break;
+#ifdef SUPPORT_PS2
+			case DTYPE_ESDI:
+				if (biosmca_ps2model) {
+					devname = "ed";
+					break;
+				}
+#endif
+			default:
 				devname = "wd";
+				break;
+			}
 
 			/*
 			 * The old boot block performed the following
Index: lib/gatea20.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/stand/lib/gatea20.c,v
retrieving revision 1.3
diff -u -p -r1.3 gatea20.c
--- lib/gatea20.c	2000/05/11 16:11:54	1.3
+++ lib/gatea20.c	2001/05/07 15:25:04
@@ -8,6 +8,7 @@
 #include <lib/libsa/stand.h>
 
 #include "libi386.h"
+#include "biosmca.h"
 
 #define K_RDWR 		0x60		/* keyboard data & cmds (read/write) */
 #define K_STATUS 	0x64		/* keyboard status */
@@ -27,15 +28,19 @@
 /*
  * Gate A20 for high memory
  */
-#ifndef IBM_L40
 static unsigned char	x_20 = KB_A20;
-#endif
 void gateA20()
 {
 	__asm("pushfl ; cli");
-#ifdef	IBM_L40
-	outb(0x92, 0x2);
-#else	/* !IBM_L40 */
+#ifdef	SUPPORT_PS2
+	/*
+	 * Check if the machine is PS/2 L40 via biosmca_model, which is
+	 * initialized before gateA20() is called.
+	 */
+	if (biosmca_ps2model == 0xf82)
+		outb(0x92, 0x2);
+	else {
+#endif
 	while (inb(K_STATUS) & K_IBUF_FUL);
 	while (inb(K_STATUS) & K_OBUF_FUL)
 		(void)inb(K_RDWR);
@@ -46,6 +51,8 @@ void gateA20()
 	outb(K_RDWR, x_20);
 	delay(100);
 	while (inb(K_STATUS) & K_IBUF_FUL);
-#endif	/* IBM_L40 */
+#ifdef SUPPORT_PS2
+	}
+#endif
 	__asm("popfl");
 }

--ELM989249335-326-0_--