[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Missing LBA-awareness for 3rd and higher (hd2,..=0x82,..) boot disks
>>> Fred de Jong 12-Jun-04 12:14 >>>
>
> I'm experiencing a boot problem with
> BOOT 2.06 in the OpenBSD/i386 3.5 GENERIC RELEASE.
>
> Could I be alone in experiencing this ?
Possibly. I don't have any hardware with this number of hard disks...
care to donate some :-)
> 3.5 GENERIC BOOT 2.06 RELEASE of May 1st, 2004 does not
> support LBA-awareness on a 3rd or higher (hd2,... = 0x82,...)
> BIOS-drive when /boot itself was not loaded from that drive.
> So we cannot boot OBSD on such drives in MBR-partitions
> that are located beyond the 8 GB CHS limit. Any boot> command
> like boot hd2a:/bsd to load a kernel from such partitions on such
> drives fails when /boot was loaded from another device (another
> harddisk, a floppy, or a CD-ROM).
>
> I wrote some minor patches for /boot to fix it. Left all the legacy
> untouched:
Either use "cvs diff -u" or "diff -u" (see cvs(1) and diff(1)) to
generate output we can actually use.
> Any comments ?
See below.
> ORG:
> bios_getdiskinfo()::
> if (dev & 0x80 && (dev == 0x80 || dev == 0x81 || dev ==
> bios_bootdev)) {
> NEW:
> bios_getdiskinfo()::
> if (dev & 0x80) {
> REASON:
> This is the crucial patch to support a 3rd or next BIOS disk to
> install on or boot from a 3rd or higher LBA drive. Now supports
I can see why this won't work on 3rd of above LBA drive. I am looking
at this for inclusion.
> ORG:
> biosdreset()::
> return ((rv & 0xff)? rv >> 8 : 0);
> NEW:
> biosdreset()::
> return ((rv & 0xff00)? (rv & 0xff00) >> 8 : 0);
> REASON:
> BIOS Int13 Disk Reset (AH=0) returns result status in the AH, not
> in the AL 8-bit register.
This is why unified (-u) diffs (which show context) help. Sometimes
people will increase the context from the default 3 lines to assist
with understanding. If you had done this you would have:
--- biosdev.c 9 Mar 2004 19:12:12 -0000 1.68
+++ biosdev.c 12 Jun 2004 14:42:06 -0000
@@ -73,15 +73,15 @@
biosdreset(int dev)
{
int rv;
__asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
: "0" (0), "d" (dev) : "%ecx", "cc");
- return ((rv & 0xff)? rv >> 8 : 0);
+ return ((rv & 0xff00)? (rv & 0xff00) >> 8 : 0);
}
where we can see that %al is set to 1 (by "setc %b0") if the carry flag
is set by the BIOS call/interrupt. Given this, the return expression
is correct.
> ORG:
> bios_getdiskinfo()::
> if (rv & 0xff)
> return 1;
> NEW:
> bios_getdiskinfo()::
> if (rv & 0xff00)
> return 1;
Similarly here. %al (which is stored in %eax) is set to 1 if the
carry flag is set. So the original is correct.
> ORG:
> bios_getdiskinfo()::
> if (!(rv & 0xff) && (BIOS_regs.biosr_bx & 0xffff) == 0xaa55)
> pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff) << 16);
> NEW:
> bios_getdiskinfo()::
> if ((BIOS_regs.biosr_bx & 0xffff) == 0xaa55)
> pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff00) << 8);
> REASON:
> BIOS Int13 EDA/EDD Extension Installation Check (AH=41h) returns
> EDA/EDD version in AH (21h = v2.1); Also: biosboot.S too only checks
> for biosr_bx == 0xaa55 to get the resulting status of this function
> call;
Not true. Again, the lower byte of %eax (rv) is set to 1 if carry was
set. And biosboot.S also checks this:
jc no_lba /* Did the command work? Jump if not */
cmpw $0xAA55, %bx /* Check that bl, bh exchanged */
jne no_lba /* If not, don't have EDD extensions */
> ORG:
> CHS_rw()::
> return ((rv & 0xff)? rv >> 8 : 0);
> NEW:
> CHS_rw()::
> return ((rv & 0xff00)? (rv & 0xff00) >> 8 : 0);
Wrong. Same reason.
> ORG:
> EDD_rw()::
> return ((rv & 0xff)? rv >> 8 : 0);
> NEW:
> EDD_rw()::
> return ((rv & 0xff00)? (rv & 0xff00) >> 8 : 0);
Ditto.
Okay, thanks for the report. I will investigate the first change
request further.
But, for the archives: some of the in-line assembler in the boot blocks
is hard to understand. It often takes me a second or third look to be
sure of what is going on, and I've been reading and writing x86 assembler
for 17 years :-)
Thanks
Tom