x86/boot: re-arrange how/when we do disk I/O

We place the trampoline no lower than at 256k, so we have ample space
to read the MBRs of BIOS disks into an aligned buffer right below the
trampoline (not doing so has been found to be a problem on a buggy BIOS
coming with a Skull Canyon NUC). To facilitate that move MBR reading
past EDD info retrieval.

Also add a wrap check to the EDD info retrieval loop, to match that in
the MBR reading one.

Reported-by: Paul Durrant <Paul.Durrant@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Paul Durrant <Paul.Durrant@citrix.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Jan Beulich committed 2017-06-13 10:41:10 +02:00
1 parent 7f679c4fed
commit 5ec164fd61
1 file changed
+62 -41
+62 -41
View File
@@ -26,46 +26,6 @@
get_edd:
cmpb $2, bootsym(opt_edd) # edd=off ?
je edd_done
cmpb $1, bootsym(opt_edd) # edd=skipmbr ?
je edd_start
# Read the first sector of each BIOS disk device and store the 4-byte signature
edd_mbr_sig_start:
movb $0x80, %dl # from device 80
movw $bootsym(boot_mbr_signature),%bx # store buffer ptr in bx
edd_mbr_sig_read:
pushw %bx
movb $0x02, %ah # 0x02 Read Sectors
movb $1, %al # read 1 sector
movb $0, %dh # at head 0
movw $1, %cx # cylinder 0, sector 0
pushw %es
pushw %ds
popw %es
movw $bootsym(boot_edd_info), %bx # disk's data goes into info
pushw %dx # work around buggy BIOSes
stc # work around buggy BIOSes
int $0x13
sti # work around buggy BIOSes
popw %dx
popw %es
popw %bx
jc edd_mbr_sig_done # on failure, we're done.
cmpb $0, %ah # some BIOSes do not set CF
jne edd_mbr_sig_done # on failure, we're done.
cmpw $0xaa55, bootsym(boot_edd_info)+0x1fe
jne .Ledd_mbr_sig_next
movl bootsym(boot_edd_info)+EDD_MBR_SIG_OFFSET,%eax
movb %dl, (%bx) # store BIOS drive number
movl %eax, 4(%bx) # store signature from MBR
incb bootsym(boot_mbr_signature_nr) # note that we stored something
addw $8, %bx # increment sig buffer ptr
.Ledd_mbr_sig_next:
incb %dl # increment to next device
jz edd_mbr_sig_done
cmpb $EDD_MBR_SIG_MAX,bootsym(boot_mbr_signature_nr)
jb edd_mbr_sig_read
edd_mbr_sig_done:
# Do the BIOS Enhanced Disk Drive calls
# This consists of two calls:
@@ -136,10 +96,71 @@ edd_legacy_done:
edd_next:
incb %dl # increment to next device
jz edd_done
cmpb $EDD_INFO_MAX,bootsym(boot_edd_info_nr)
jb edd_check_ext
edd_done:
cmpb $1, bootsym(opt_edd) # edd=skipmbr ?
je .Ledd_mbr_sig_skip
# Read the first sector of each BIOS disk device and store the 4-byte signature
.Ledd_mbr_sig_start:
pushw %es
movb $0x80, %dl # from device 80
movw $bootsym(boot_mbr_signature), %bx # store buffer ptr in bx
.Ledd_mbr_sig_read:
pushw %bx
movw $bootsym(boot_edd_info), %bx
movzbw bootsym(boot_edd_info_nr), %cx
jcxz .Ledd_mbr_sig_default
.Ledd_mbr_sig_find_info:
cmpb %dl, (%bx)
ja .Ledd_mbr_sig_default
je .Ledd_mbr_sig_get_size
add $EDDEXTSIZE+EDDPARMSIZE, %bx
loop .Ledd_mbr_sig_find_info
.Ledd_mbr_sig_default:
movw $(512 >> 4), %bx
jmp .Ledd_mbr_sig_set_buf
.Ledd_mbr_sig_get_size:
movw EDDEXTSIZE+0x18(%bx), %bx # sector size
shr $4, %bx # convert to paragraphs
jz .Ledd_mbr_sig_default
.Ledd_mbr_sig_set_buf:
movw %ds, %ax
subw %bx, %ax # disk's data goes right ahead
movw %ax, %es # of trampoline
xorw %bx, %bx
movw %bx, %es:0x1fe(%bx) # clear BIOS magic just in case
pushw %dx # work around buggy BIOSes
stc # work around buggy BIOSes
movw $0x0201, %ax # read 1 sector
movb $0, %dh # at head 0
movw $1, %cx # cylinder 0, sector 0
int $0x13
sti # work around buggy BIOSes
popw %dx
movw %es:0x1fe(%bx), %si
movl %es:EDD_MBR_SIG_OFFSET(%bx), %ecx
popw %bx
jc .Ledd_mbr_sig_done # on failure, we're done.
testb %ah, %ah # some BIOSes do not set CF
jnz .Ledd_mbr_sig_done # on failure, we're done.
cmpw $0xaa55, %si
jne .Ledd_mbr_sig_next
movb %dl, (%bx) # store BIOS drive number
movl %ecx, 4(%bx) # store signature from MBR
incb bootsym(boot_mbr_signature_nr) # note that we stored something
addw $8, %bx # increment sig buffer ptr
.Ledd_mbr_sig_next:
incb %dl # increment to next device
jz .Ledd_mbr_sig_done
cmpb $EDD_MBR_SIG_MAX, bootsym(boot_mbr_signature_nr)
jb .Ledd_mbr_sig_read
.Ledd_mbr_sig_done:
popw %es
.Ledd_mbr_sig_skip:
ret
GLOBAL(boot_edd_info_nr)
@@ -149,4 +170,4 @@ GLOBAL(boot_mbr_signature_nr)
GLOBAL(boot_mbr_signature)
.fill EDD_MBR_SIG_MAX*8,1,0
GLOBAL(boot_edd_info)
.fill 512,1,0 # big enough for a disc sector
.fill EDD_INFO_MAX * (EDDEXTSIZE + EDDPARMSIZE), 1, 0
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.