1/****************************************************************************** 2 * edd.S 3 * 4 * BIOS Enhanced Disk Drive support 5 * 6 * Copyright (C) 2002, 2003, 2004 Dell, Inc. 7 * by Matt Domsch <Matt_Domsch@dell.com> October 2002 8 * conformant to T13 Committee www.t13.org 9 * projects 1572D, 1484D, 1386D, 1226DT 10 * disk signature read by Matt Domsch <Matt_Domsch@dell.com> 11 * and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004 12 * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net> 13 * March 2004 14 * Command line option parsing, Matt Domsch, November 2004 15 * 16 * Updated and ported for Xen by Keir Fraser <keir@xensource.com> June 2007 17 */ 18 19#include <asm/edd.h> 20 21 .code16 22 23/* Offset of disc signature in the MBR. */ 24#define EDD_MBR_SIG_OFFSET 0x1B8 25 26get_edd: 27 cmpb $2, bootsym(opt_edd) # edd=off ? 28 je edd_done 29 30# Do the BIOS Enhanced Disk Drive calls 31# This consists of two calls: 32# int 13h ah=41h "Check Extensions Present" 33# int 13h ah=48h "Get Device Parameters" 34# int 13h ah=08h "Legacy Get Device Parameters" 35# 36# A buffer of size EDD_INFO_MAX*(EDDEXTSIZE+EDDPARMSIZE) is reserved at 37# boot_edd_info, the first four bytes of which are used to store the device 38# number, interface support map and version results from fn41. The next four 39# bytes are used to store the legacy cylinders, heads, and sectors from fn08. 40# The following 74 bytes are used to store the results from fn48. 41# This code is sensitive to the size of the structs in edd.h 42edd_start: 43 /* ds:si points at fn48 results. Fn41 results go immediately before. */ 44 movw $bootsym(boot_edd_info)+EDDEXTSIZE, %si 45 movb $0x80, %dl # BIOS device 0x80 46 47edd_check_ext: 48 movb $0x41, %ah # 0x41 Check Extensions Present 49 movw $0x55AA, %bx # magic 50 int $0x13 # make the call 51 jc edd_done # no more BIOS devices 52 53 cmpw $0xAA55, %bx # is magic right? 54 jne edd_next # nope, next... 55 56 movb %dl, %ds:-8(%si) # store device number 57 movb %ah, %ds:-7(%si) # store version 58 movw %cx, %ds:-6(%si) # store extensions 59 incb bootsym(boot_edd_info_nr) # note that we stored something 60 61edd_get_device_params: 62 movw $EDDPARMSIZE, %ds:(%si) # put size 63 movw $0x0, %ds:2(%si) # work around buggy BIOSes 64 movb $0x48, %ah # 0x48 Get Device Parameters 65 int $0x13 # make the call 66 # Don't check for fail return 67 # it doesn't matter. 68edd_get_legacy_chs: 69 xorw %ax, %ax 70 movw %ax, %ds:-4(%si) 71 movw %ax, %ds:-2(%si) 72 # Ralf Brown's Interrupt List says to set ES:DI to 73 # 0000h:0000h "to guard against BIOS bugs" 74 pushw %es 75 movw %ax, %es 76 movw %ax, %di 77 pushw %dx # legacy call clobbers %dl 78 movb $0x08, %ah # 0x08 Legacy Get Device Params 79 int $0x13 # make the call 80 jc edd_legacy_done # failed 81 movb %cl, %al # Low 6 bits are max 82 andb $0x3F, %al # sector number 83 movb %al, %ds:-1(%si) # Record max sect 84 movb %dh, %ds:-2(%si) # Record max head number 85 movb %ch, %al # Low 8 bits of max cyl 86 shr $6, %cl 87 movb %cl, %ah # High 2 bits of max cyl 88 movw %ax, %ds:-4(%si) 89 90edd_legacy_done: 91 popw %dx 92 popw %es 93 movw %si, %ax # increment si 94 addw $EDDPARMSIZE+EDDEXTSIZE, %ax 95 movw %ax, %si 96 97edd_next: 98 incb %dl # increment to next device 99 jz edd_done 100 cmpb $EDD_INFO_MAX,bootsym(boot_edd_info_nr) 101 jb edd_check_ext 102 103edd_done: 104 cmpb $1, bootsym(opt_edd) # edd=skipmbr ? 105 je .Ledd_mbr_sig_skip 106 107# Read the first sector of each BIOS disk device and store the 4-byte signature 108.Ledd_mbr_sig_start: 109 pushw %es 110 movb $0x80, %dl # from device 80 111 movw $bootsym(boot_mbr_signature), %bx # store buffer ptr in bx 112.Ledd_mbr_sig_read: 113 pushw %bx 114 movw $bootsym(boot_edd_info), %bx 115 movzbw bootsym(boot_edd_info_nr), %cx 116 jcxz .Ledd_mbr_sig_default 117.Ledd_mbr_sig_find_info: 118 cmpb %dl, (%bx) 119 ja .Ledd_mbr_sig_default 120 je .Ledd_mbr_sig_get_size 121 add $EDDEXTSIZE+EDDPARMSIZE, %bx 122 loop .Ledd_mbr_sig_find_info 123.Ledd_mbr_sig_default: 124 movw $(512 >> 4), %bx 125 jmp .Ledd_mbr_sig_set_buf 126.Ledd_mbr_sig_get_size: 127 movw EDDEXTSIZE+0x18(%bx), %bx # sector size 128 shr $4, %bx # convert to paragraphs 129 jz .Ledd_mbr_sig_default 130.Ledd_mbr_sig_set_buf: 131 movw %ds, %ax 132 subw %bx, %ax # disk's data goes right ahead 133 movw %ax, %es # of trampoline 134 xorw %bx, %bx 135 movw %bx, %es:0x1fe(%bx) # clear BIOS magic just in case 136 pushw %dx # work around buggy BIOSes 137 stc # work around buggy BIOSes 138 movw $0x0201, %ax # read 1 sector 139 movb $0, %dh # at head 0 140 movw $1, %cx # cylinder 0, sector 0 141 int $0x13 142 sti # work around buggy BIOSes 143 popw %dx 144 movw %es:0x1fe(%bx), %si 145 movl %es:EDD_MBR_SIG_OFFSET(%bx), %ecx 146 popw %bx 147 jc .Ledd_mbr_sig_done # on failure, we're done. 148 testb %ah, %ah # some BIOSes do not set CF 149 jnz .Ledd_mbr_sig_done # on failure, we're done. 150 cmpw $0xaa55, %si 151 jne .Ledd_mbr_sig_next 152 movb %dl, (%bx) # store BIOS drive number 153 movl %ecx, 4(%bx) # store signature from MBR 154 incb bootsym(boot_mbr_signature_nr) # note that we stored something 155 addw $8, %bx # increment sig buffer ptr 156.Ledd_mbr_sig_next: 157 incb %dl # increment to next device 158 jz .Ledd_mbr_sig_done 159 cmpb $EDD_MBR_SIG_MAX, bootsym(boot_mbr_signature_nr) 160 jb .Ledd_mbr_sig_read 161.Ledd_mbr_sig_done: 162 popw %es 163.Ledd_mbr_sig_skip: 164 ret 165 166GLOBAL(boot_edd_info_nr) 167 .byte 0 168GLOBAL(boot_mbr_signature_nr) 169 .byte 0 170GLOBAL(boot_mbr_signature) 171 .fill EDD_MBR_SIG_MAX*8,1,0 172GLOBAL(boot_edd_info) 173 .fill EDD_INFO_MAX * (EDDEXTSIZE + EDDPARMSIZE), 1, 0 174