You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dskprefix.S 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. #include "compiler.h"
  2. /* NOTE: this boot sector contains instructions that need at least an 80186.
  3. * Yes, as86 has a bug somewhere in the valid instruction set checks.
  4. *
  5. * SYS_SIZE is the number of clicks (16 bytes) to be loaded.
  6. */
  7. .equ SYSSIZE, 8192 # 8192 * 16 bytes = 128kB maximum size of .ROM file
  8. /* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
  9. * modified by Drew Eckhardt
  10. * modified by Bruce Evans (bde)
  11. *
  12. * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
  13. *
  14. * It then loads the system at SYSSEG<<4, using BIOS interrupts.
  15. *
  16. * The loader has been made as simple as possible, and continuous read errors
  17. * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by
  18. * getting whole tracks at a time whenever possible.
  19. */
  20. .equ BOOTSEG, 0x07C0 /* original address of boot-sector */
  21. .equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
  22. .org 0
  23. .arch i386
  24. .text
  25. .section ".prefix", "ax", @progbits
  26. .code16
  27. jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
  28. go:
  29. movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
  30. /* of bootsect + room for stack + 12 for */
  31. /* saved disk parm block */
  32. movw $BOOTSEG, %ax
  33. movw %ax,%ds
  34. movw %ax,%es
  35. movw %ax,%ss /* put stack at BOOTSEG:0x4000-12. */
  36. movw %di,%sp
  37. /* Many BIOS's default disk parameter tables will not recognize multi-sector
  38. * reads beyond the maximum sector number specified in the default diskette
  39. * parameter tables - this may mean 7 sectors in some cases.
  40. *
  41. * Since single sector reads are slow and out of the question, we must take care
  42. * of this by creating new parameter tables (for the first disk) in RAM. We
  43. * will set the maximum sector count to 36 - the most we will encounter on an
  44. * ED 2.88. High doesn't hurt. Low does.
  45. *
  46. * Segments are as follows: ds=es=ss=cs - BOOTSEG
  47. */
  48. xorw %cx,%cx
  49. movw %cx,%es /* access segment 0 */
  50. movw $0x78, %bx /* 0:bx is parameter table address */
  51. pushw %ds /* save ds */
  52. /* 0:bx is parameter table address */
  53. ldsw %es:(%bx),%si /* loads ds and si */
  54. movw %ax,%es /* ax is BOOTSECT (loaded above) */
  55. movb $6, %cl /* copy 12 bytes */
  56. cld
  57. pushw %di /* keep a copy for later */
  58. rep
  59. movsw /* ds:si is source, es:di is dest */
  60. popw %di
  61. movb $36,%es:4(%di)
  62. movw %cx,%ds /* access segment 0 */
  63. xchgw %di,(%bx)
  64. movw %es,%si
  65. xchgw %si,2(%bx)
  66. popw %ds /* restore ds */
  67. movw %di, dpoff /* save old parameters */
  68. movw %si, dpseg /* to restore just before finishing */
  69. pushw %ds
  70. popw %es /* reload es */
  71. /* Note that es is already set up. Also cx is 0 from rep movsw above. */
  72. xorb %ah,%ah /* reset FDC */
  73. xorb %dl,%dl
  74. int $0x13
  75. /* Get disk drive parameters, specifically number of sectors/track.
  76. *
  77. * It seems that there is no BIOS call to get the number of sectors. Guess
  78. * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
  79. * 15 if sector 15 can be read. Otherwise guess 9.
  80. */
  81. movw $disksizes, %si /* table of sizes to try */
  82. probe_loop:
  83. lodsb
  84. cbtw /* extend to word */
  85. movw %ax, sectors
  86. cmpw $disksizes+4, %si
  87. jae got_sectors /* if all else fails, try 9 */
  88. xchgw %cx,%ax /* cx = track and sector */
  89. xorw %dx,%dx /* drive 0, head 0 */
  90. movw $0x0200, %bx /* address after boot sector */
  91. /* (512 bytes from origin, es = cs) */
  92. movw $0x0201, %ax /* service 2, 1 sector */
  93. int $0x13
  94. jc probe_loop /* try next value */
  95. got_sectors:
  96. movw $msg1end-msg1, %cx
  97. movw $msg1, %si
  98. call print_str
  99. /* ok, we've written the Loading... message, now we want to load the system */
  100. movw $SYSSEG, %ax
  101. movw %ax,%es /* segment of SYSSEG<<4 */
  102. pushw %es
  103. call read_it
  104. /* This turns off the floppy drive motor, so that we enter the kernel in a
  105. * known state, and don't have to worry about it later.
  106. */
  107. movw $0x3f2, %dx
  108. xorb %al,%al
  109. outb %al,%dx
  110. call print_nl
  111. pop %es /* = SYSSEG */
  112. /* Restore original disk parameters */
  113. movw $0x78, %bx
  114. movw dpoff, %di
  115. movw dpseg, %si
  116. xorw %ax,%ax
  117. movw %ax,%ds
  118. movw %di,(%bx)
  119. movw %si,2(%bx)
  120. /* Everything now loaded. %es = SYSSEG, so %es:0000 points to
  121. * start of loaded image.
  122. */
  123. start_runtime:
  124. #ifdef COMPRESS
  125. /* Decompress runtime image. %es:0000 points to decompressed
  126. * image on exit.
  127. */
  128. lcall $SYSSEG, $decompress16
  129. #endif
  130. /* Set up internal environment. Address of entry-point
  131. * function is returned in %es:di.
  132. */
  133. pushw %es /* setup16 says %ds:0000 must point to image */
  134. popw %ds
  135. movw $setup16, %di
  136. pushw %cs
  137. call ljmp_to_es_di
  138. /* Call initialisation routine. Relocation may be done. New
  139. * address of entry-point function is returned in %es:di.
  140. */
  141. pushl $arch_rm_initialise
  142. pushw %cs /* == lcall %es:di */
  143. call ljmp_to_es_di
  144. /* Call to arch_rm_main. Register INT19 as an exit path. This
  145. * call will never return.
  146. */
  147. movl $exit_via_int19, %eax
  148. pushl $arch_rm_main
  149. pushl %eax /* Dummy return address */
  150. /* Do the equivalent of ljmp *%es:di */
  151. ljmp_to_es_di:
  152. pushw %es
  153. pushw %di
  154. lret
  155. /* This routine loads the system at address SYSSEG<<4, making sure no 64kB
  156. * boundaries are crossed. We try to load it as fast as possible, loading whole
  157. * tracks whenever we can.
  158. *
  159. * in: es - starting address segment (normally SYSSEG)
  160. */
  161. read_it:
  162. movw $1,sread /* don't reload the prefix */
  163. movw %es,%ax
  164. testw $0x0fff, %ax
  165. die: jne die /* es must be at 64kB boundary */
  166. xorw %bx,%bx /* bx is starting address within segment */
  167. rp_read:
  168. movw %es,%ax
  169. movw %bx,%dx
  170. movb $4, %cl
  171. shrw %cl,%dx /* bx is always divisible by 16 */
  172. addw %dx,%ax
  173. cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */
  174. jb ok1_read
  175. ret
  176. ok1_read:
  177. movw sectors, %ax
  178. subw sread, %ax
  179. movw %ax,%cx
  180. shlw $9, %cx
  181. addw %bx,%cx
  182. jnc ok2_read
  183. je ok2_read
  184. xorw %ax,%ax
  185. subw %bx,%ax
  186. shrw $9, %ax
  187. ok2_read:
  188. call read_track
  189. movw %ax,%cx
  190. addw sread, %ax
  191. cmpw sectors, %ax
  192. jne ok3_read
  193. movw $1, %ax
  194. subw head, %ax
  195. jne ok4_read
  196. incw track
  197. ok4_read:
  198. movw %ax, head
  199. xorw %ax,%ax
  200. ok3_read:
  201. movw %ax, sread
  202. shlw $9, %cx
  203. addw %cx,%bx
  204. jnc rp_read
  205. movw %es,%ax
  206. addb $0x10, %ah
  207. movw %ax,%es
  208. xorw %bx,%bx
  209. jmp rp_read
  210. read_track:
  211. pusha
  212. pushw %ax
  213. pushw %bx
  214. pushw %bp /* just in case the BIOS is buggy */
  215. movw $0x0e2e, %ax /* 0x2e = . */
  216. movw $0x0007, %bx
  217. int $0x10
  218. popw %bp
  219. popw %bx
  220. popw %ax
  221. movw track, %dx
  222. movw sread, %cx
  223. incw %cx
  224. movb %dl,%ch
  225. movw head, %dx
  226. movb %dl,%dh
  227. andw $0x0100, %dx
  228. movb $2, %ah
  229. pushw %dx /* save for error dump */
  230. pushw %cx
  231. pushw %bx
  232. pushw %ax
  233. int $0x13
  234. jc bad_rt
  235. addw $8, %sp
  236. popa
  237. ret
  238. bad_rt: pushw %ax /* save error code */
  239. call print_all /* ah = error, al = read */
  240. xorb %ah,%ah
  241. xorb %dl,%dl
  242. int $0x13
  243. addw $10, %sp
  244. popa
  245. jmp read_track
  246. /* print_all is for debugging purposes. It will print out all of the registers.
  247. * The assumption is that this is called from a routine, with a stack frame like
  248. * dx
  249. * cx
  250. * bx
  251. * ax
  252. * error
  253. * ret <- sp
  254. */
  255. print_all:
  256. call print_nl /* nl for readability */
  257. movw $5, %cx /* error code + 4 registers */
  258. movw %sp,%bp
  259. print_loop:
  260. pushw %cx /* save count left */
  261. cmpb $5, %cl
  262. jae no_reg /* see if register name is needed */
  263. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  264. movw $0xe05+0x41-1, %ax
  265. subb %cl,%al
  266. int $0x10
  267. movb $0x58, %al /* 'X' */
  268. int $0x10
  269. movb $0x3A, %al /* ':' */
  270. int $0x10
  271. no_reg:
  272. addw $2, %bp /* next register */
  273. call print_hex /* print it */
  274. movb $0x20, %al /* print a space */
  275. int $0x10
  276. popw %cx
  277. loop print_loop
  278. call print_nl /* nl for readability */
  279. ret
  280. print_str:
  281. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  282. movb $0x0e, %ah /* write char, tty mode */
  283. prloop:
  284. lodsb
  285. int $0x10
  286. loop prloop
  287. ret
  288. print_nl:
  289. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  290. movw $0xe0d, %ax /* CR */
  291. int $0x10
  292. movb $0xa, %al /* LF */
  293. int $0x10
  294. ret
  295. /* print_hex prints the word pointed to by ss:bp in hexadecimal. */
  296. print_hex:
  297. movw (%bp),%dx /* load word into dx */
  298. movb $4, %cl
  299. movb $0x0e, %ah /* write char, tty mode */
  300. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  301. call print_digit
  302. call print_digit
  303. call print_digit
  304. /* fall through */
  305. print_digit:
  306. rol %cl,%dx /* rotate so that lowest 4 bits are used */
  307. movb $0x0f, %al /* mask for nybble */
  308. andb %dl,%al
  309. addb $0x90, %al /* convert al to ascii hex (four instructions) */
  310. daa
  311. adcb $0x40, %al
  312. daa
  313. int $0x10
  314. ret
  315. sread: .word 0 /* sectors read of current track */
  316. head: .word 0 /* current head */
  317. track: .word 0 /* current track */
  318. sectors:
  319. .word 0
  320. dpseg: .word 0
  321. dpoff: .word 0
  322. disksizes:
  323. .byte 36,18,15,9
  324. msg1:
  325. .ascii "Loading ROM image"
  326. msg1end:
  327. .org 510, 0
  328. .word 0xAA55