bootsect.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
  3.  *
  4.  * modified by Drew Eckhardt
  5.  * modified by Bruce Evans (bde)
  6.  * modified by Chris Noe (May 1999) (as86 -> gas)
  7.  *
  8.  * 360k/720k disk support: Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
  9.  *
  10.  * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
  11.  * addresses must be multiplied by 16 to obtain their respective linear
  12.  * addresses. To avoid confusion, linear addresses are written using leading
  13.  * hex while segment addresses are written as segment:offset.
  14.  *
  15.  * bde - should not jump blindly, there may be systems with only 512K low
  16.  * memory.  Use int 0x12 to get the top of memory, etc.
  17.  *
  18.  * It then loads 'setup' directly after itself (0x90200), and the system
  19.  * at 0x10000, using BIOS interrupts. 
  20.  *
  21.  * NOTE! currently system is at most (8*65536-4096) bytes long. This should 
  22.  * be no problem, even in the future. I want to keep it simple. This 508 kB
  23.  * kernel size should be enough, especially as this doesn't contain the
  24.  * buffer cache as in minix (and especially now that the kernel is 
  25.  * compressed :-)
  26.  *
  27.  * The loader has been made as simple as possible, and continuous
  28.  * read errors will result in a unbreakable loop. Reboot by hand. It
  29.  * loads pretty fast by getting whole tracks at a time whenever possible.
  30.  */
  31. #include <asm/boot.h>
  32. SETUPSECTS = 4 /* default nr of setup-sectors */
  33. BOOTSEG = 0x07C0 /* original address of boot-sector */
  34. INITSEG = DEF_INITSEG /* we move boot here - out of the way */
  35. SETUPSEG = DEF_SETUPSEG /* setup starts here */
  36. SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
  37. SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
  38. /* to be loaded */
  39. ROOT_DEV = 0  /* ROOT_DEV is now written by "build" */
  40. SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
  41. #ifndef SVGA_MODE
  42. #define SVGA_MODE ASK_VGA
  43. #endif
  44. #ifndef RAMDISK
  45. #define RAMDISK 0
  46. #endif
  47. #ifndef ROOT_RDONLY
  48. #define ROOT_RDONLY 1
  49. #endif
  50. .code16
  51. .text
  52. .global _start
  53. _start:
  54. # First things first. Move ourself from 0x7C00 -> 0x90000 and jump there.
  55. movw $BOOTSEG, %ax
  56. movw %ax, %ds # %ds = BOOTSEG
  57. movw $INITSEG, %ax
  58. movw %ax, %es # %ax = %es = INITSEG
  59. movw $256, %cx
  60. subw %si, %si
  61. subw %di, %di
  62. cld
  63. rep
  64. movsw
  65. ljmp $INITSEG, $go
  66. # bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
  67. # wouldn't have to worry about this if we checked the top of memory.  Also
  68. # my BIOS can be configured to put the wini drive tables in high memory
  69. # instead of in the vector table.  The old stack might have clobbered the
  70. # drive table.
  71. go: movw $0x4000-12, %di # 0x4000 is an arbitrary value >=
  72. # length of bootsect + length of
  73. # setup + room for stack;
  74. # 12 is disk parm size.
  75. movw %ax, %ds # %ax and %es already contain INITSEG
  76. movw %ax, %ss
  77. movw %di, %sp # put stack at INITSEG:0x4000-12.
  78. # Many BIOS's default disk parameter tables will not recognize
  79. # multi-sector reads beyond the maximum sector number specified
  80. # in the default diskette parameter tables - this may mean 7
  81. # sectors in some cases.
  82. #
  83. # Since single sector reads are slow and out of the question,
  84. # we must take care of this by creating new parameter tables
  85. # (for the first disk) in RAM.  We will set the maximum sector
  86. # count to 36 - the most we will encounter on an ED 2.88.  
  87. #
  88. # High doesn't hurt.  Low does.
  89. #
  90. # Segments are as follows: %cs = %ds = %es = %ss = INITSEG, %fs = 0,
  91. # and %gs is unused.
  92. movw %cx, %fs # %fs = 0
  93. movw $0x78, %bx # %fs:%bx is parameter table address
  94. pushw %ds
  95. ldsw %fs:(%bx), %si # %ds:%si is source
  96. movb $6, %cl # copy 12 bytes
  97. pushw %di # %di = 0x4000-12.
  98. rep # don't worry about cld
  99. movsw # already done above
  100. popw %di
  101. popw %ds
  102. movb $36, 0x4(%di) # patch sector count
  103. movw %di, %fs:(%bx)
  104. movw %es, %fs:2(%bx)
  105. # Get disk drive parameters, specifically number of sectors/track.
  106. # It seems that there is no BIOS call to get the number of sectors.
  107. # Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
  108. # can be read, 15 if sector 15 can be read.  Otherwise guess 9.
  109. # Note that %cx = 0 from rep movsw above.
  110. movw $disksizes, %si # table of sizes to try
  111. probe_loop:
  112. lodsb
  113. cbtw # extend to word
  114. movw %ax, sectors
  115. cmpw $disksizes+4, %si
  116. jae got_sectors # If all else fails, try 9
  117. xchgw %cx, %ax # %cx = track and sector
  118. xorw %dx, %dx # drive 0, head 0
  119. movw $0x0200, %bx # address = 512, in INITSEG (%es = %cs)
  120. movw $0x0201, %ax # service 2, 1 sector
  121. int $0x13
  122. jc probe_loop # try next value
  123. got_sectors:
  124. movb $0x03, %ah # read cursor pos
  125. xorb %bh, %bh
  126. int $0x10
  127. movw $9, %cx
  128. movb $0x07, %bl # page 0, attribute 7 (normal)
  129. # %bh is set above; int10 doesn't
  130. # modify it
  131. movw $msg1, %bp
  132. movw $0x1301, %ax # write string, move cursor
  133. int $0x10 # tell the user we're loading..
  134. # Load the setup-sectors directly after the moved bootblock (at 0x90200).
  135. # We should know the drive geometry to do it, as setup may exceed first
  136. # cylinder (for 9-sector 360K and 720K floppies).
  137. movw $0x0001, %ax # set sread (sector-to-read) to 1 as
  138. movw $sread, %si # the boot sector has already been read
  139. movw %ax, (%si)
  140. xorw %ax, %ax # reset FDC
  141. xorb %dl, %dl
  142. int $0x13
  143. movw $0x0200, %bx # address = 512, in INITSEG
  144. next_step:
  145. movb setup_sects, %al
  146. movw sectors, %cx
  147. subw (%si), %cx # (%si) = sread
  148. cmpb %cl, %al
  149. jbe no_cyl_crossing
  150. movw sectors, %ax
  151. subw (%si), %ax # (%si) = sread
  152. no_cyl_crossing:
  153. call read_track
  154. pushw %ax # save it
  155. call set_next # set %bx properly; it uses %ax,%cx,%dx
  156. popw %ax # restore
  157. subb %al, setup_sects # rest - for next step
  158. jnz next_step
  159. pushw $SYSSEG
  160. popw %es # %es = SYSSEG
  161. call read_it
  162. call kill_motor
  163. call print_nl
  164. # After that we check which root-device to use. If the device is
  165. # defined (!= 0), nothing is done and the given device is used.
  166. # Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
  167. # depending on the number of sectors we pretend to know we have.
  168. # Segments are as follows: %cs = %ds = %ss = INITSEG,
  169. # %es = SYSSEG, %fs = 0, %gs is unused.
  170. movw root_dev, %ax
  171. orw %ax, %ax
  172. jne root_defined
  173. movw sectors, %bx
  174. movw $0x0208, %ax # /dev/ps0 - 1.2Mb
  175. cmpw $15, %bx
  176. je root_defined
  177. movb $0x1c, %al # /dev/PS0 - 1.44Mb
  178. cmpw $18, %bx
  179. je root_defined
  180. movb $0x20, %al # /dev/fd0H2880 - 2.88Mb
  181. cmpw $36, %bx
  182. je root_defined
  183. movb $0, %al # /dev/fd0 - autodetect
  184. root_defined:
  185. movw %ax, root_dev
  186. # After that (everything loaded), we jump to the setup-routine
  187. # loaded directly after the bootblock:
  188. ljmp $SETUPSEG, $0
  189. # These variables are addressed via %si register as it gives shorter code.
  190. sread: .word 0 # sectors read of current track
  191. head: .word 0 # current head
  192. track: .word 0 # current track
  193. # This routine loads the system at address SYSSEG, making sure
  194. # no 64kB boundaries are crossed. We try to load it as fast as
  195. # possible, loading whole tracks whenever we can.
  196. read_it:
  197. movw %es, %ax # %es = SYSSEG when called
  198. testw $0x0fff, %ax
  199. die: jne die # %es must be at 64kB boundary
  200. xorw %bx, %bx # %bx is starting address within segment
  201. rp_read:
  202. #ifdef __BIG_KERNEL__ # look in setup.S for bootsect_kludge
  203. bootsect_kludge = 0x220 # 0x200 + 0x20 which is the size of the
  204. lcall bootsect_kludge # bootsector + bootsect_kludge offset
  205. #else
  206. movw %es, %ax
  207. subw $SYSSEG, %ax
  208. movw %bx, %cx
  209. shr $4, %cx
  210. add %cx, %ax # check offset
  211. #endif
  212. cmpw syssize, %ax # have we loaded everything yet?
  213. jbe ok1_read
  214. ret
  215. ok1_read:
  216. movw sectors, %ax
  217. subw (%si), %ax # (%si) = sread
  218. movw %ax, %cx
  219. shlw $9, %cx
  220. addw %bx, %cx
  221. jnc ok2_read
  222. je ok2_read
  223. xorw %ax, %ax
  224. subw %bx, %ax
  225. shrw $9, %ax
  226. ok2_read:
  227. call read_track
  228. call set_next
  229. jmp rp_read
  230. read_track:
  231. pusha
  232. pusha
  233. movw $0xe2e, %ax  # loading... message 2e = .
  234. movw $7, %bx
  235.   int $0x10
  236. popa
  237. # Accessing head, track, sread via %si gives shorter code.
  238. movw 4(%si), %dx # 4(%si) = track
  239. movw (%si), %cx # (%si)  = sread
  240. incw %cx
  241. movb %dl, %ch
  242. movw 2(%si), %dx # 2(%si) = head
  243. movb %dl, %dh
  244. andw $0x0100, %dx
  245. movb $2, %ah
  246. pushw %dx # save for error dump
  247. pushw %cx
  248. pushw %bx
  249. pushw %ax
  250. int $0x13
  251. jc bad_rt
  252. addw $8, %sp
  253. popa
  254. ret
  255. set_next:
  256. movw %ax, %cx
  257. addw (%si), %ax # (%si) = sread
  258. cmp sectors, %ax
  259. jne ok3_set
  260. movw $0x0001, %ax
  261. xorw %ax, 2(%si) # change head
  262. jne ok4_set
  263. incw 4(%si) # next track
  264. ok4_set:
  265. xorw %ax, %ax
  266. ok3_set:
  267. movw %ax, (%si) # set sread
  268. shlw $9, %cx
  269. addw %cx, %bx
  270. jnc set_next_fin
  271. movw %es, %ax
  272. addb $0x10, %ah
  273. movw %ax, %es
  274. xorw %bx, %bx
  275. set_next_fin:
  276. ret
  277. bad_rt:
  278. pushw %ax # save error code
  279. call print_all # %ah = error, %al = read
  280. xorb %ah, %ah
  281. xorb %dl, %dl
  282. int $0x13
  283. addw $10, %sp
  284. popa
  285. jmp read_track
  286. # print_all is for debugging purposes.  
  287. #
  288. # it will print out all of the registers.  The assumption is that this is
  289. # called from a routine, with a stack frame like
  290. #
  291. # %dx 
  292. # %cx
  293. # %bx
  294. # %ax
  295. # (error)
  296. # ret <- %sp
  297.  
  298. print_all:
  299. movw $5, %cx # error code + 4 registers
  300. movw %sp, %bp
  301. print_loop:
  302. pushw %cx # save count remaining
  303. call print_nl # <-- for readability
  304. cmpb $5, %cl
  305. jae no_reg # see if register name is needed
  306. movw $0xe05 + 'A' - 1, %ax
  307. subb %cl, %al
  308. int $0x10
  309. movb $'X', %al
  310. int $0x10
  311. movb $':', %al
  312. int $0x10
  313. no_reg:
  314. addw $2, %bp # next register
  315. call print_hex # print it
  316. popw %cx
  317. loop print_loop
  318. ret
  319. print_nl:
  320. movw $0xe0d, %ax # CR
  321. int $0x10
  322. movb $0xa, %al # LF
  323. int  $0x10
  324. ret
  325. # print_hex is for debugging purposes, and prints the word
  326. # pointed to by %ss:%bp in hexadecimal.
  327. print_hex:
  328. movw $4, %cx # 4 hex digits
  329. movw (%bp), %dx # load word into %dx
  330. print_digit:
  331. rolw $4, %dx # rotate to use low 4 bits
  332. movw $0xe0f, %ax # %ah = request
  333. andb %dl, %al # %al = mask for nybble
  334. addb $0x90, %al # convert %al to ascii hex
  335. daa # in only four instructions!
  336. adc $0x40, %al
  337. daa
  338. int $0x10
  339. loop print_digit
  340. ret
  341. # This procedure turns off the floppy drive motor, so
  342. # that we enter the kernel in a known state, and
  343. # don't have to worry about it later.
  344. # NOTE: Doesn't save %ax or %dx; do it yourself if you need to.
  345. kill_motor:
  346. movw $0x3f2, %dx
  347. xorb %al, %al
  348. outb %al, %dx
  349. ret
  350. sectors: .word 0
  351. disksizes: .byte 36, 18, 15, 9
  352. msg1: .byte 13, 10
  353. .ascii "Loading"
  354. # XXX: This is a fairly snug fit.
  355. .org 497
  356. setup_sects: .byte SETUPSECTS
  357. root_flags: .word ROOT_RDONLY
  358. syssize: .word SYSSIZE
  359. swap_dev: .word SWAP_DEV
  360. ram_size: .word RAMDISK
  361. vid_mode: .word SVGA_MODE
  362. root_dev: .word ROOT_DEV
  363. boot_flag: .word 0xAA55