edd.S 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * BIOS Enhanced Disk Drive support
  3. * Copyright (C) 2002, 2003, 2004 Dell, Inc.
  4. * by Matt Domsch <Matt_Domsch@dell.com> October 2002
  5. * conformant to T13 Committee www.t13.org
  6. * projects 1572D, 1484D, 1386D, 1226DT
  7. * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
  8. * and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
  9. * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net>
  10. * March 2004
  11. * Command line option parsing, Matt Domsch, November 2004
  12. */
  13. #include <linux/edd.h>
  14. #include <asm/setup.h>
  15. #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
  16. # It is assumed that %ds == INITSEG here
  17. movb $0, (EDD_MBR_SIG_NR_BUF)
  18. movb $0, (EDDNR)
  19. # Check the command line for options:
  20. # edd=of disables EDD completely (edd=off)
  21. # edd=sk skips the MBR test (edd=skipmbr)
  22. # edd=on re-enables EDD (edd=on)
  23. pushl %esi
  24. movw $edd_mbr_sig_start, %di # Default to edd=on
  25. movl %cs:(cmd_line_ptr), %esi
  26. andl %esi, %esi
  27. jz old_cl # Old boot protocol?
  28. # Convert to a real-mode pointer in fs:si
  29. movl %esi, %eax
  30. shrl $4, %eax
  31. movw %ax, %fs
  32. andw $0xf, %si
  33. jmp have_cl_pointer
  34. # Old-style boot protocol?
  35. old_cl:
  36. push %ds # aka INITSEG
  37. pop %fs
  38. cmpw $0xa33f, (0x20)
  39. jne done_cl # No command line at all?
  40. movw (0x22), %si # Pointer relative to INITSEG
  41. # fs:si has the pointer to the command line now
  42. have_cl_pointer:
  43. # Loop through kernel command line one byte at a time. Just in
  44. # case the loader is buggy and failed to null-terminate the command line
  45. # terminate if we get close enough to the end of the segment that we
  46. # cannot fit "edd=XX"...
  47. cl_atspace:
  48. cmpw $-5, %si # Watch for segment wraparound
  49. jae done_cl
  50. movl %fs:(%si), %eax
  51. andb %al, %al # End of line?
  52. jz done_cl
  53. cmpl $EDD_CL_EQUALS, %eax
  54. jz found_edd_equals
  55. cmpb $0x20, %al # <= space consider whitespace
  56. ja cl_skipword
  57. incw %si
  58. jmp cl_atspace
  59. cl_skipword:
  60. cmpw $-5, %si # Watch for segment wraparound
  61. jae done_cl
  62. movb %fs:(%si), %al # End of string?
  63. andb %al, %al
  64. jz done_cl
  65. cmpb $0x20, %al
  66. jbe cl_atspace
  67. incw %si
  68. jmp cl_skipword
  69. found_edd_equals:
  70. # only looking at first two characters after equals
  71. # late overrides early on the command line, so keep going after finding something
  72. movw %fs:4(%si), %ax
  73. cmpw $EDD_CL_OFF, %ax # edd=of
  74. je do_edd_off
  75. cmpw $EDD_CL_SKIP, %ax # edd=sk
  76. je do_edd_skipmbr
  77. cmpw $EDD_CL_ON, %ax # edd=on
  78. je do_edd_on
  79. jmp cl_skipword
  80. do_edd_skipmbr:
  81. movw $edd_start, %di
  82. jmp cl_skipword
  83. do_edd_off:
  84. movw $edd_done, %di
  85. jmp cl_skipword
  86. do_edd_on:
  87. movw $edd_mbr_sig_start, %di
  88. jmp cl_skipword
  89. done_cl:
  90. popl %esi
  91. jmpw *%di
  92. # Read the first sector of each BIOS disk device and store the 4-byte signature
  93. edd_mbr_sig_start:
  94. movb $0x80, %dl # from device 80
  95. movw $EDD_MBR_SIG_BUF, %bx # store buffer ptr in bx
  96. edd_mbr_sig_read:
  97. movl $0xFFFFFFFF, %eax
  98. movl %eax, (%bx) # assume failure
  99. pushw %bx
  100. movb $READ_SECTORS, %ah
  101. movb $1, %al # read 1 sector
  102. movb $0, %dh # at head 0
  103. movw $1, %cx # cylinder 0, sector 0
  104. pushw %es
  105. pushw %ds
  106. popw %es
  107. movw $EDDBUF, %bx # disk's data goes into EDDBUF
  108. pushw %dx # work around buggy BIOSes
  109. stc # work around buggy BIOSes
  110. int $0x13
  111. sti # work around buggy BIOSes
  112. popw %dx
  113. popw %es
  114. popw %bx
  115. jc edd_mbr_sig_done # on failure, we're done.
  116. cmpb $0, %ah # some BIOSes do not set CF
  117. jne edd_mbr_sig_done # on failure, we're done.
  118. movl (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
  119. movl %eax, (%bx) # store success
  120. incb (EDD_MBR_SIG_NR_BUF) # note that we stored something
  121. incb %dl # increment to next device
  122. addw $4, %bx # increment sig buffer ptr
  123. cmpb $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF) # Out of space?
  124. jb edd_mbr_sig_read # keep looping
  125. edd_mbr_sig_done:
  126. # Do the BIOS Enhanced Disk Drive calls
  127. # This consists of two calls:
  128. # int 13h ah=41h "Check Extensions Present"
  129. # int 13h ah=48h "Get Device Parameters"
  130. # int 13h ah=08h "Legacy Get Device Parameters"
  131. #
  132. # A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
  133. # in the boot_params at EDDBUF. The first four bytes of which are
  134. # used to store the device number, interface support map and version
  135. # results from fn41. The next four bytes are used to store the legacy
  136. # cylinders, heads, and sectors from fn08. The following 74 bytes are used to
  137. # store the results from fn48. Starting from device 80h, fn41, then fn48
  138. # are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
  139. # Then the pointer is incremented to store the data for the next call.
  140. # This repeats until either a device doesn't exist, or until EDDMAXNR
  141. # devices have been stored.
  142. # The one tricky part is that ds:si always points EDDEXTSIZE bytes into
  143. # the structure, and the fn41 and fn08 results are stored at offsets
  144. # from there. This removes the need to increment the pointer for
  145. # every store, and leaves it ready for the fn48 call.
  146. # A second one-byte buffer, EDDNR, in the boot_params stores
  147. # the number of BIOS devices which exist, up to EDDMAXNR.
  148. # In setup.c, copy_edd() stores both boot_params buffers away
  149. # for later use, as they would get overwritten otherwise.
  150. # This code is sensitive to the size of the structs in edd.h
  151. edd_start:
  152. # %ds points to the bootsector
  153. # result buffer for fn48
  154. movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results
  155. # kept just before that
  156. movb $0x80, %dl # BIOS device 0x80
  157. edd_check_ext:
  158. movb $CHECKEXTENSIONSPRESENT, %ah # Function 41
  159. movw $EDDMAGIC1, %bx # magic
  160. int $0x13 # make the call
  161. jc edd_done # no more BIOS devices
  162. cmpw $EDDMAGIC2, %bx # is magic right?
  163. jne edd_next # nope, next...
  164. movb %dl, %ds:-8(%si) # store device number
  165. movb %ah, %ds:-7(%si) # store version
  166. movw %cx, %ds:-6(%si) # store extensions
  167. incb (EDDNR) # note that we stored something
  168. edd_get_device_params:
  169. movw $EDDPARMSIZE, %ds:(%si) # put size
  170. movw $0x0, %ds:2(%si) # work around buggy BIOSes
  171. movb $GETDEVICEPARAMETERS, %ah # Function 48
  172. int $0x13 # make the call
  173. # Don't check for fail return
  174. # it doesn't matter.
  175. edd_get_legacy_chs:
  176. xorw %ax, %ax
  177. movw %ax, %ds:-4(%si)
  178. movw %ax, %ds:-2(%si)
  179. # Ralf Brown's Interrupt List says to set ES:DI to
  180. # 0000h:0000h "to guard against BIOS bugs"
  181. pushw %es
  182. movw %ax, %es
  183. movw %ax, %di
  184. pushw %dx # legacy call clobbers %dl
  185. movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
  186. int $0x13 # make the call
  187. jc edd_legacy_done # failed
  188. movb %cl, %al # Low 6 bits are max
  189. andb $0x3F, %al # sector number
  190. movb %al, %ds:-1(%si) # Record max sect
  191. movb %dh, %ds:-2(%si) # Record max head number
  192. movb %ch, %al # Low 8 bits of max cyl
  193. shr $6, %cl
  194. movb %cl, %ah # High 2 bits of max cyl
  195. movw %ax, %ds:-4(%si)
  196. edd_legacy_done:
  197. popw %dx
  198. popw %es
  199. movw %si, %ax # increment si
  200. addw $EDDPARMSIZE+EDDEXTSIZE, %ax
  201. movw %ax, %si
  202. edd_next:
  203. incb %dl # increment to next device
  204. cmpb $EDDMAXNR, (EDDNR) # Out of space?
  205. jb edd_check_ext # keep looping
  206. edd_done:
  207. #endif