Source code of Windows XP (NT5)
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.

432 lines
15 KiB

  1. page ,132
  2. ;
  3. ; Microsoft Confidential
  4. ; Copyright (C) Microsoft Corporation 1983-1997
  5. ; All Rights Reserved.
  6. ;
  7. ;
  8. ; This is the standard boot record that will be shipped on all hard disks.
  9. ; It contains:
  10. ;
  11. ; 1. Code to load (and give control to) the active boot record for 1 of 4
  12. ; possible operating systems.
  13. ;
  14. ; 2. A partition table at the end of the boot record, followed by the
  15. ; required signature.
  16. ;
  17. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  18. VOLBOOT_ORG EQU 7c00h
  19. SIZE_SECTOR EQU 512
  20. ;
  21. ; Partition table entry structure and other related stuff
  22. ;
  23. Part_Active EQU 0
  24. Part_StartHead EQU 1
  25. Part_StartSector EQU 2
  26. Part_StartCylinder EQU 3
  27. Part_Type EQU 4
  28. Part_EndHead EQU 5
  29. Part_EndSector EQU 6
  30. Part_EndCylinder EQU 7
  31. Part_AbsoluteSector EQU 8
  32. Part_AbsoluteSectorH EQU 10
  33. Part_SectorCount EQU 12
  34. Part_SectorCountH EQU 14
  35. SIZE_PART_TAB_ENT EQU 16
  36. NUM_PART_TAB_ENTS EQU 4
  37. PART_TAB_OFF EQU (SIZE_SECTOR - 2 - (SIZE_PART_TAB_ENT * NUM_PART_TAB_ENTS))
  38. MBR_NT_OFFSET EQU (PART_TAB_OFF - 6)
  39. MBR_MSG_TABLE_OFFSET EQU (PART_TAB_OFF - 9)
  40. ;
  41. ; Space we use for temp storage, beyond the end of
  42. ; the active partition table entry, and thus safe.
  43. ;
  44. UsingBackup EQU SIZE_PART_TAB_ENT
  45. ;
  46. ; Partition types
  47. ;
  48. PART_IFS EQU 07h
  49. PART_FAT32 EQU 0bh
  50. PART_FAT32_XINT13 EQU 0ch
  51. PART_XINT13 EQU 0eh
  52. ;
  53. ; Filesystem and pbr stuff
  54. ;
  55. BOOTSECTRAILSIGH EQU 0aa55h
  56. FAT32_BACKUP EQU 6
  57. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  58. RELOCATION_ORG EQU 600h
  59. READ_RETRY_CNT EQU 5
  60. _data segment public
  61. assume cs:_data,ds:nothing,es:nothing,ss:nothing
  62. org 100h
  63. start100 label near
  64. org RELOCATION_ORG
  65. ; Move ourselves so that we can load the partition boot record from
  66. ; the active partition at 0:VOLBOOT_ORG without trashing our own code.
  67. ;
  68. ; WARNING: We are not executing at 0:RELOCATION_ORG until the far
  69. ; immediate jump, below. This basically means beware of OFFSETs of
  70. ; any labels until we get there. Until then, we're still executing at
  71. ; 0:VOLBOOT_ORG.
  72. reloc_delta = 1Bh
  73. start:
  74. xor ax,ax
  75. mov ss,ax
  76. mov sp,VOLBOOT_ORG ; new stack at 0:7c00
  77. sti
  78. push ax
  79. pop es
  80. assume es:_data
  81. push ax
  82. pop ds
  83. assume ds:_data
  84. cld
  85. mov si,VOLBOOT_ORG + reloc_delta
  86. mov di,RELOCATION_ORG + reloc_delta
  87. push ax
  88. push di
  89. mov cx,SIZE_SECTOR - reloc_delta
  90. rep movsb ; relocate to 0:0600
  91. retf
  92. ; We are now RELOCATED and are now executing at 0:RELOCATION_ORG.
  93. ;
  94. ; Find the active partition. Once we find it, we also make sure that the
  95. ; remaining partitions are INACTIVE, too.
  96. .errnz reloc_delta NE $-start ; make sure reloc_delta is correct
  97. mov bp,offset tab ; partition table
  98. mov cl,NUM_PART_TAB_ENTS ; number of table entries (CH==0)
  99. active_loop:
  100. cmp [bp].Part_Active,ch ; is this the active entry?
  101. jl check_inactive ; yes
  102. jne display_bad ; no, it must be "00" or "8x"
  103. add bp,SIZE_PART_TAB_ENT ; yes, go to next entry
  104. loop active_loop
  105. int 18h ; no active entries - go to ROM BASIC
  106. ; Now make sure the remaining partitions are INACTIVE.
  107. check_inactive:
  108. mov si,bp ; si = active entry
  109. inactive_loop:
  110. add si,SIZE_PART_TAB_ENT ; point si to next entry
  111. dec cx ; # entries left
  112. jz StartLoad ; all entries look ok, start load
  113. cmp [si],ch ; all remaining entries should be zero
  114. je inactive_loop ; this one is ok
  115. display_bad:
  116. mov al,byte ptr [m1] ; partition table is bad
  117. display_msg:
  118. ;
  119. ; Al is the offset-256 of the message text. Adjust and
  120. ; stick in si so lodsb below will work.
  121. ;
  122. .ERRNZ RELOCATION_ORG MOD 256
  123. mov ah,(RELOCATION_ORG / 256) + 1
  124. mov si,ax
  125. display_msg1:
  126. lodsb ; get a message character
  127. @@: cmp al,0 ; end of string?
  128. je @b ; yes, loop infinitely
  129. mov bx,7
  130. mov ah,14
  131. int 10h ; and display it
  132. jmp display_msg1 ; do the entire message
  133. ;
  134. ; Now attempt to read the sector.
  135. ;
  136. ; We store a data byte indicating whether this is the backup
  137. ; sector, at the byte just beyond the end of the partition table entry.
  138. ; We know there's nothing there we care about any more, so this
  139. ; is harmless.
  140. ;
  141. ; BP is the address of the active partition entry.
  142. ; AX and CX are currently zero.
  143. ;
  144. StartLoad:
  145. mov byte ptr [bp].UsingBackup,cl ; not backup sector
  146. call ReadSector
  147. jnc CheckPbr
  148. trybackup:
  149. inc byte ptr [bp].UsingBackup
  150. ;
  151. ; Switch to backup sector for NTFS and FAT32.
  152. ;
  153. if 0
  154. ;
  155. ; (tedm) for NTFS this code is actually worthless since other code,
  156. ; such as ntldr and the filesystem itself won't all do the right thing.
  157. ; For example the filesystem won't recognize the volume if sector 0
  158. ; can be read but is bad.
  159. ;
  160. cmp byte ptr [bp].Part_Type,PART_IFS
  161. jne tryfat32
  162. ;
  163. ; We assume here that type 7 is NTFS.
  164. ; Back up to end of partition by using the end CHS and subtracting 1
  165. ; from the sector #. There is no check for the case where we underflow
  166. ; and wrap a head -- it is assumed that partitions are at least head-aligned.
  167. ; There is also no check for the case where the start sector and sector count
  168. ; are both maxdword and so adding them overflows.
  169. ;
  170. mov al,[bp].Part_EndHead ; make start head same as end head
  171. mov [bp].Part_StartHead,al
  172. mov ax,[bp].Part_EndSector ; ax = end sector and cylinder
  173. dec al ; start sector = end sector minus 1
  174. mov [bp].Part_StartSector,ax
  175. mov ax,[bp].Part_SectorCount
  176. mov dx,[bp].Part_SectorCountH
  177. add [bp].Part_AbsoluteSector,ax
  178. adc [bp].Part_AbsoluteSectorH,dx
  179. sub word ptr [bp].Part_AbsoluteSector,1
  180. sbb word ptr [bp].Part_AbsoluteSectorH,0
  181. jmp short RestartLoad
  182. endif
  183. tryfat32:
  184. cmp byte ptr [bp].Part_Type,PART_FAT32
  185. je fat32backup
  186. cmp byte ptr [bp].Part_Type,PART_FAT32_XINT13
  187. je fat32backup
  188. mov al,byte ptr [m2] ; unknown fs, so no backup sector
  189. jne display_msg
  190. fat32backup:
  191. ;
  192. ; There is no check for the case where adding to the sector value
  193. ; in the start CHS overflows and wraps to the next head. It is assumed
  194. ; that partitions are at least head-aligned and that hard drives have
  195. ; at least FAT32_BACKUP+1 sectors per track.
  196. ;
  197. add byte ptr [bp].Part_StartSector,FAT32_BACKUP
  198. add word ptr [bp].Part_AbsoluteSector,FAT32_BACKUP
  199. adc word ptr [bp].Part_AbsoluteSectorH,0
  200. RestartLoad:
  201. call ReadSector
  202. jnc CheckPbr
  203. mov al,byte ptr [m2] ; can't load, we're done.
  204. jmp short display_msg
  205. CheckPbr:
  206. cmp word ptr ds:[VOLBOOT_ORG + SIZE_SECTOR - 2],BOOTSECTRAILSIGH
  207. je done
  208. ;
  209. ; Not a valid filesystem boot sector. Switch to backup if this
  210. ; isn't already the backup.
  211. ;
  212. cmp byte ptr [bp].UsingBackup,0
  213. je trybackup
  214. mov al,byte ptr [m3]
  215. jmp short display_msg
  216. ;
  217. ; Jump to PBR. We pass a pointer to the table entry that booted us
  218. ; in bp. If we used the backup boot sector, then that table entry
  219. ; will have been altered, but neither NTFS not FAT32 use the pointer
  220. ; in BP, and no other fs type will have been loaded via the backup
  221. ; boot sector, so this isn't an issue.
  222. ;
  223. done:
  224. mov di,sp ; DI -> start of PBR
  225. push ds ; prepare for RETF, which is
  226. push di ; smaller than JMP 0:VOLBOOT_ORG
  227. mov si,bp ; pass boot partition table entry address
  228. retf ; start executing PBR
  229. ReadSector proc near
  230. mov di,5 ; retry count
  231. ;
  232. ; Calculate the maximum sector # that can be addressed via
  233. ; conventional int13. Note that the max # of heads is 256
  234. ; and the maximum # of sectors per track is 63. Thus the maximum
  235. ; # of sectors per cylinder is something less than a 16-bit quantity.
  236. ;
  237. mov dl,[bp].Part_Active ;
  238. mov ah,8 ; get disk params
  239. int 13h
  240. jc nonxint13 ; strange case, fall back to std int13
  241. mov al,cl
  242. and al,3fh ; al = # of sectors per track
  243. cbw ; ax = # of sectors per track (ah=0)
  244. mov bl,dh ; bl = max head # (0-based)
  245. mov bh,ah ; bh = 0
  246. inc bx ; bx = # of heads
  247. mul bx ; ax = sectors per cylinder, dx = 0
  248. mov dx,cx ; dx = cylinder/sector in int13 format
  249. xchg dl,dh ; dl = low 8 bits of cylinder
  250. mov cl,6
  251. shr dh,cl ; dx = max cylinder # (0-based)
  252. inc dx ; dx = # cylinders
  253. mul dx ; dx:ax = # sectors visible via int13
  254. ;
  255. ; If the sector # we're reading is less than the than number of
  256. ; addressable sectors, use conventional int 13
  257. ;
  258. cmp [bp].Part_AbsoluteSectorH,dx
  259. ja xint13
  260. jb nonxint13
  261. cmp [bp].Part_AbsoluteSector,ax
  262. jae xint13
  263. nonxint13:
  264. mov ax,201h
  265. mov bx,VOLBOOT_ORG ; es:bx = read address (0:7c00)
  266. mov cx,[bp].Part_StartSector
  267. mov dx,[bp].Part_Active
  268. int 13h
  269. jnc endread
  270. dec di ; retry? (does not affect carry)
  271. jz endread ; carry set for return
  272. xor ah,ah ; ah = 0 (reset disk system)
  273. mov dl,[bp].Part_Active ; dl = int13 unit #
  274. int 13h
  275. jmp short nonxint13
  276. xint13:
  277. ;
  278. ; We want to avoid calling xint13 unless we know it's available
  279. ; since we don't trust all BIOSes to not hang if we attempt an xint13 read.
  280. ; If xint13 isn't supported we won't be able to boot, but at least
  281. ; we'll give an error message instead of just a black screen.
  282. ;
  283. mov dl,[bp].Part_Active ; unit #
  284. .286
  285. pusha
  286. mov bx,055AAh ; signature
  287. mov ah,41h ; perform X13 interrogation
  288. int 13h ;
  289. jc endread1 ; call failed
  290. cmp bx,0AA55h ; did our signature get flipped?
  291. jne endread1 ; no
  292. test cl,1 ; is there X13 support?
  293. jz endread1 ; no
  294. popa
  295. doxint13:
  296. pusha ; save regs
  297. push 0 ; push dword of 0
  298. push 0 ; (high 32 bits of sector #)
  299. push [bp].Part_AbsoluteSectorH
  300. push [bp].Part_AbsoluteSector ; low 32 bits of sector #
  301. push 0
  302. push VOLBOOT_ORG ; transfer address
  303. push 1 ; 1 sector
  304. push 16 ; packet size and reserved byte
  305. mov ah,42h ; extended read
  306. mov si,sp ; ds:si points to parameter packet
  307. int 13h ; dl already set from above
  308. popa ; pop param packet off stack
  309. popa ; get real registers back
  310. jnc endread
  311. dec di ; retry? (does not affect carry)
  312. jz endread ; carry set for return
  313. xor ah,ah ; ah = 0 (reset disk system)
  314. mov dl,[bp].Part_Active ; dl = int13 unit #
  315. int 13h
  316. jmp short doxint13
  317. endread1:
  318. popa
  319. stc ; this is the error case
  320. .8086
  321. endread:
  322. ret
  323. ReadSector endp
  324. ;
  325. ; Message table.
  326. ;
  327. ; We put English messages here as a placeholder only, so that in case
  328. ; anyone uses bootmbr.h without patching new messages in, things will
  329. ; still be correct (in English, but at least functional).
  330. ;
  331. _m1: db "Invalid partition table",0
  332. _m2: db "Error loading operating system",0
  333. _m3: db "Missing operating system",0
  334. ;
  335. ; Now build a table with the low byte of the offset to each message.
  336. ; Code that patches the boot sector messages updates this table.
  337. ;
  338. .errnz ($ - start) GT MBR_MSG_TABLE_OFFSET
  339. org RELOCATION_ORG + MBR_MSG_TABLE_OFFSET
  340. m1: db (OFFSET _m1 - RELOCATION_ORG) - 256
  341. m2: db (OFFSET _m2 - RELOCATION_ORG) - 256
  342. m3: db (OFFSET _m3 - RELOCATION_ORG) - 256
  343. .errnz ($ - start) NE MBR_NT_OFFSET
  344. dd 0 ; NT disk administrator signature
  345. dw 0
  346. .errnz ($ - start) GT PART_TAB_OFF
  347. org RELOCATION_ORG + PART_TAB_OFF
  348. tab: ;partition table
  349. dw 0,0 ;partition 1 begin
  350. dw 0,0 ;partition 1 end
  351. dw 0,0 ;partition 1 relative sector (low, high parts)
  352. dw 0,0 ;partition 1 # of sectors (low, high parts)
  353. dw 0,0 ;partition 2 begin
  354. dw 0,0 ;partition 2 end
  355. dw 0,0 ;partition 2 relative sector
  356. dw 0,0 ;partition 2 # of sectors
  357. dw 0,0 ;partition 3 begin
  358. dw 0,0 ;partition 3 end
  359. dw 0,0 ;partition 3 relative sector
  360. dw 0,0 ;partition 3 # of sectors
  361. dw 0,0 ;partition 4 begin
  362. dw 0,0 ;partition 4 end
  363. dw 0,0 ;partition 4 relative sector
  364. dw 0,0 ;partition 4 # of sectors
  365. .errnz ($ - tab) NE (SIZE_PART_TAB_ENT * NUM_PART_TAB_ENTS)
  366. .errnz ($ - start) NE (SIZE_SECTOR - 2)
  367. signa dw BOOTSECTRAILSIGH ;signature
  368. .errnz ($ - start) NE SIZE_SECTOR
  369. _data ends
  370. end start100