[syslinux] BIOS disk geometry and Linux 2.6

Patrick J. LoPresti patl at users.sourceforge.net
Fri Feb 27 12:29:42 PST 2004


Michael_E_Brown at Dell.com writes:

> Just do the int13 calls in setup.S and save the results in
> empty-zero-page.  Make the data available via sys/proc.

OK, below is my initial attempt at a patch.

It creates new nodes under /sys/firmware/edd/int13_devXX named
legacy_cylinders, legacy_heads, and legacy_sectors.  The values within
are the maximum cylinder number, maximum head number, and maximum
sector number as returned by the legacy INT13/AH=08h "get drive
parameters" call (http://www.ctyme.com/intr/rb-0621.htm).

In general, I tried to follow the coding style already present.  But I
make no claims about the quality of my code, especially the assembly
portion.

It works on my test systems, so I am good to go.  Thank you for the
help, Michael and Peter!

Note that these files hold the literal values returned by the BIOS.
If I understand correctly, you have to add 1 to "legacy_heads" before
the value is useful (i.e., before you set it as the bios_head value in
/proc/sys/.../settings).  We could do that arithmetic here, but I
think it is cleaner to worry about it in userspace.

Michael, you may want to ask Matt to push this change or something
like it through to the Linux folks.

 - Pat


diff -u -r linux-2.6.3-orig/arch/i386/boot/setup.S linux-2.6.3/arch/i386/boot/setup.S
--- linux-2.6.3-orig/arch/i386/boot/setup.S	2004-02-17 22:58:11.000000000 -0500
+++ linux-2.6.3/arch/i386/boot/setup.S	2004-02-27 14:58:46.000000000 -0500
@@ -650,6 +650,31 @@
 	int	$0x13				# make the call
 						# Don't check for fail return
 						# it doesn't matter.
+edd_get_legacy_chs:
+        xorw    %ax, %ax
+        movw    %ax, %ds:-8(%si)        
+        movw    %ax, %ds:-6(%si)
+        # Ralf Brown's Interrupt List says to set ES:DI to
+        # 0000h:0000h "to guard against BIOS bugs"
+        pushw   %es
+        movw    %ax, %es
+        movw    %ax, %di
+        pushw   %dx                             # legacy call clobbers %dl
+        movb    $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
+        int     $0x13                           # make the call
+        popw    %es
+        jc      edd_legacy_done                 # failed
+        movb    %cl, %al                        # Low 6 bits are max
+        andb    $0x3F, %al                      #   sector number
+    	movb	%al, %ds:-5(%si)                # Record max sect
+	movb    %dh, %ds:-6(%si)                # Record max head number
+        movb    %ch, %al                        # Low 8 bits of max cyl
+        shr     $6, %cl
+        movb    %cl, %ah                        # High 2 bits of max cyl
+        movw    %ax, %ds:-8(%si)
+        
+edd_legacy_done:
+        popw    %dx
 	movw	%si, %ax			# increment si
 	addw	$EDDPARMSIZE+EDDEXTSIZE, %ax
 	movw	%ax, %si

diff -u -r linux-2.6.3-orig/arch/i386/kernel/edd.c linux-2.6.3/arch/i386/kernel/edd.c
--- linux-2.6.3-orig/arch/i386/kernel/edd.c	2004-02-17 22:57:22.000000000 -0500
+++ linux-2.6.3/arch/i386/kernel/edd.c	2004-02-27 14:22:12.000000000 -0500
@@ -321,6 +321,45 @@
 }
 
 static ssize_t
+edd_show_legacy_cylinders(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->legacy_cylinders);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_legacy_heads(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->legacy_heads);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_legacy_sectors(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->legacy_sectors);
+	return (p - buf);
+}
+
+static ssize_t
 edd_show_default_cylinders(struct edd_device *edev, char *buf)
 {
 	struct edd_info *info = edd_dev_get_info(edev);
@@ -384,6 +423,33 @@
  */
 
 static int
+edd_has_legacy_cylinders(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->legacy_cylinders > 0;
+}
+
+static int
+edd_has_legacy_heads(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->legacy_heads > 0;
+}
+
+static int
+edd_has_legacy_sectors(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->legacy_sectors > 0;
+}
+
+static int
 edd_has_default_cylinders(struct edd_device *edev)
 {
 	struct edd_info *info = edd_dev_get_info(edev);
@@ -452,6 +518,12 @@
 static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, NULL);
 static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, NULL);
 static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, NULL);
+static EDD_DEVICE_ATTR(legacy_cylinders, 0444, edd_show_legacy_cylinders,
+		       edd_has_legacy_cylinders);
+static EDD_DEVICE_ATTR(legacy_heads, 0444, edd_show_legacy_heads,
+		       edd_has_legacy_heads);
+static EDD_DEVICE_ATTR(legacy_sectors, 0444, edd_show_legacy_sectors,
+		       edd_has_legacy_sectors);
 static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
 		       edd_has_default_cylinders);
 static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
@@ -478,6 +550,9 @@
 
 /* These attributes are conditional and only added for some devices. */
 static struct edd_attribute * edd_attrs[] = {
+	&edd_attr_legacy_cylinders,
+	&edd_attr_legacy_heads,
+	&edd_attr_legacy_sectors,
 	&edd_attr_default_cylinders,
 	&edd_attr_default_heads,
 	&edd_attr_default_sectors_per_track,

diff -u -r linux-2.6.3-orig/include/asm-i386/edd.h linux-2.6.3/include/asm-i386/edd.h
--- linux-2.6.3-orig/include/asm-i386/edd.h	2004-02-17 22:57:12.000000000 -0500
+++ linux-2.6.3/include/asm-i386/edd.h	2004-02-27 14:21:01.000000000 -0500
@@ -34,10 +34,11 @@
 				   in empty_zero_block - treat this as 1 byte  */
 #define EDDBUF	0x600		/* addr of edd_info structs in empty_zero_block */
 #define EDDMAXNR 6		/* number of edd_info structs starting at EDDBUF  */
-#define EDDEXTSIZE 4		/* change these if you muck with the structures */
+#define EDDEXTSIZE 8		/* change these if you muck with the structures */
 #define EDDPARMSIZE 74
 #define CHECKEXTENSIONSPRESENT 0x41
 #define GETDEVICEPARAMETERS 0x48
+#define LEGACYGETDEVICEPARAMETERS 0x08
 #define EDDMAGIC1 0x55AA
 #define EDDMAGIC2 0xAA55
 
@@ -162,6 +163,9 @@
 } __attribute__ ((packed));
 
 struct edd_info {
+        u16 legacy_cylinders;
+        u8 legacy_heads;
+        u8 legacy_sectors;
 	u8 device;
 	u8 version;
 	u16 interface_support;




More information about the Syslinux mailing list