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.

2955 lines
81 KiB

  1. /**
  2. *** Copyright (C) 1996-97 Intel Corporation. All rights reserved.
  3. ***
  4. *** The information and source code contained herein is the exclusive
  5. *** property of Intel Corporation and may not be disclosed, examined
  6. *** or reproduced in whole or in part without explicit written authorization
  7. *** from the company.
  8. **/
  9. //++
  10. //
  11. // Module name
  12. // NTFSBOOT.S
  13. // Author
  14. // Allen Kay (akay) May-6-97
  15. // Description
  16. // NTFS boot code
  17. // Notes
  18. // This is the startup routine for NTFS NT boot sector. It finds
  19. // NTLDR by walk through the NTFS file system structure.
  20. // Assumptions
  21. // 1. SAL/Gambit makes sure all TLB entries are purged before
  22. // passing control to SuSetup().
  23. // SuSetup does the following:
  24. // 1. Initialize PSR with interrupt disabled.
  25. // 2. Invalidate ALAT.
  26. // 3. Invalidate RS.
  27. // 4. Setup GP.
  28. // 5. Set region registers rr[r0] - rr[r7] to RID=0, PS=8K, E=0.
  29. // 6. Initialize SP to 0x00902000.
  30. // 7. Initialize BSP to 0x00202000.
  31. // 8. Enable register stack engine.
  32. // 9. Setup IVA to 0x001F8000.
  33. // 10. Setup virtual->physical address translation
  34. // 0x80000000->0x00000000 in dtr0/itr0 for NT kernel.
  35. // 11. Setup virtual->physical address translation
  36. // 0x80400000->0x00400000 in dtr1/itr1 for HAL.dll.
  37. // 12. Setup virtual->physical address translation
  38. // 0x00800000->0x00800000 in dtr1/itr1 for NTLDR.
  39. //---
  40. #include "ksia64.h"
  41. #include "susetup.h"
  42. #include "ntfsdefs.h"
  43. .file "ntfsboot.s"
  44. #define NewSeg 0x100000
  45. #define LdrSeg 0x200000
  46. .global Multiply
  47. .type Multiply, @function
  48. .global Divide
  49. .type Divide, @function
  50. .global memcpy
  51. .type memcpy, @function
  52. .global strncmp
  53. .type strncmp, @function
  54. .global PrintName
  55. .type PrintName, @function
  56. .global BootErr$Print
  57. .type BootErr$Print, @function
  58. .global SscExit
  59. .type SscExit, @function
  60. .global SalDiskReadWrite
  61. .type SalDiskReadWrite, @function
  62. .global ReadSectors
  63. .type ReadSectors, @function
  64. .global SalPrint
  65. .type SalPrint, @function
  66. .global LoadNtldrSymbols
  67. .type LoadNtldrSymbols, @function
  68. .global RelocateLoaderSections
  69. .type RelocateLoaderSections, @function
  70. //
  71. // This is a template BPB--anyone who writes boot code to disk
  72. // should either preserve the existing BPB and NTFS information
  73. // or create it anew.
  74. //
  75. #ifdef BSDT
  76. //
  77. // First define the Boot Sector Descriptor Table (BSDT)
  78. //
  79. BsdtSignature: data1 0x01, 0x02, 0x45, 0x4d, 0x0f, 0x00
  80. BsdtSectors: data2 64
  81. BsdtEntryPoint: data4 mainboot
  82. BsdtVersion: data1 0
  83. BsdtReserved: data1 0, 0
  84. BsdtCheckSum: data1 0
  85. #endif
  86. //
  87. // Start of the NTFS boot sector
  88. //
  89. Version: string "NTFS " // Must be 8 characters
  90. BytesPerSector: data2.ua 0 // Size of a physical sector
  91. SectorsPerCluster: data1 0 // Sectors per allocation unit
  92. //
  93. // Traditionally the next 7 bytes were the reserved sector count, fat count,
  94. // root dir entry count, and the small volume sector count. However all of
  95. // these fields must be 0 on NTFS volumes.
  96. //
  97. // We use this space to store some temporary variables used by the boot code,
  98. // which avoids the need for separate space in sector 0 to store them.
  99. // We also take advantage of the free 0-initialization to save some space
  100. // by avoiding the code to initialize them.
  101. //
  102. // Note that ideally we'd want to use an unused field for the SectorCount
  103. // and initialize it to 16. This would let us save a few bytes by avoiding
  104. // code to explicitly initialize this value before we read the 16 boot sectors.
  105. // However setup and other code tends to preserve the entire bpb area when
  106. // it updates boot code, so we avoid a dependency here and initialize
  107. // the value explicitly to 16 in the first part of the boot code.
  108. //
  109. // ReservedSectors: data2.ua 0 // Number of reserved sectors
  110. // Fats: data1 0 // Number of fats
  111. // DirectoryEntries: data2.ua 0 // Number of directory entries
  112. // Sectors: data2.ua 0 // No. of sectors-no. of hidden sectors
  113. SectorCount: data2.ua 0 // number of sectors to read
  114. SectorBase: data4.ua 0 // start sector for read request
  115. HaveXInt13: data1 0 // extended int13 available flag
  116. Media: data1 0 // Media byte
  117. FatSectors: data2.ua 0 // Number of fat sectors
  118. SectorsPerTrack: data2.ua 0 // Sectors per track
  119. Heads: data2.ua 0 // Number of surfaces
  120. HiddenSectors: data4.ua 0 // Number of hidden sectors
  121. //
  122. // The field below is traditionally the large sector count and is
  123. // always 0 on NTFS. We use it here for a value the boot code calculates,
  124. // namely the number of sectors visible on the drive via conventional int13.
  125. //
  126. // Int13Sectors: data2 0
  127. //
  128. SectorsLong: data4.ua 0 // Number of sectors iff Sectors = 0
  129. //
  130. // TBD: Need additition fields for 5.0 stuff.
  131. //
  132. DriveNumber: data1 0x80 // int13 unit number
  133. ReservedForBootCode:data1 0
  134. #ifdef BSDT
  135. Unused: data1 0,0,0,0,0 // Alignment filler
  136. #else
  137. Unused: data1 0,0 // Alignment filler
  138. #endif
  139. //
  140. // The following is the rest of the NTFS Sector Zero information.
  141. // The offsets of most of these fields cannot be changed without changing
  142. // all code that validates, formats, recognizes, etc, NTFS volumes.
  143. // In other words, don't change it.
  144. //
  145. SectorsOnVolume: data8 0
  146. MftStartLcn: data8 0
  147. Mft2StartLcn: data8 0
  148. ClustersPerFrs: data1 0
  149. Unused1: data1 0,0,0
  150. DefClustersPerBuf: data1 0
  151. Unused2: data1 0,0,0
  152. SerialNumber: data8 0
  153. CheckSum: data4 0
  154. //
  155. // TBD: What should be done for IA64?
  156. //
  157. // Make sure size of fields matches what fs_rec.sys thinks is should be
  158. //
  159. // .errnz ($-_ntfsboot) NE (54h)
  160. //
  161. //
  162. // TBD. Dummy BootErr$he function. Need to fill in at a later time.
  163. //
  164. BootErr$he:
  165. //
  166. // NTFS data
  167. //
  168. // Name we look for. ntldr_length is the number of characters,
  169. // ntldr_name is the name itself. Note that it is not NULL
  170. // terminated, and doesn't need to be.
  171. //
  172. ntldr_name_length: data2 5
  173. ntldr_name: data2 'N', 'T', 'L', 'D', 'R'
  174. // Predefined name for index-related attributes associated with an
  175. // index over $FILE_NAME
  176. //
  177. index_name_length: data2 4
  178. index_name: data2 '$', 'I', '3', '0'
  179. // Global variables. These offsets are all relative to NewSeg.
  180. //
  181. AttrList: data4 0x0e000 // Offset of buffer to hold attribute list
  182. MftFrs: data4 0x3000 // Offset of first MFT FRS
  183. SegmentsInMft: data4 0 // number of FRS's with MFT Data attribute records
  184. RootIndexFrs: data4 0 // Offset of Root Index FRS
  185. AllocationIndexFrs: data4 0 // Offset of Allocation Index FRS ; KPeery
  186. BitmapIndexFrs: data4 0 // Offset of Bitmap Index FRS ; KPeery
  187. IndexRoot: data4 0 // Offset of Root Index $INDEX_ROOT attribute
  188. IndexAllocation: data4 0 // Offset of Root Index $INDEX_ALLOCATION attribute
  189. IndexBitmap: data4 0 // Offset of Root Index $BITMAP attribute
  190. NtldrFrs: data4 0 // Offset of NTLDR FRS
  191. NtldrData: data4 0 // Offset of NTLDR $DATA attribute
  192. IndexBlockBuffer: data4 0 // Offset of current index buffer
  193. IndexBitmapBuffer: data4 0 // Offset of index bitmap buffer
  194. NextBuffer: data4 0 // Offset of next free byte in buffer space
  195. BytesPerCluster: data4 0 // Bytes per cluster
  196. BytesPerFrs: data4 0 // Bytes per File Record Segment
  197. Result: data4 0 // Result from Multiply and Divide
  198. Remainder: data4 0 // Remainder
  199. //
  200. // For floppyless booting, winnt32.exe creates c:\$win_nt$.~bt\bootsec.dat and
  201. // places an entry in boot.ini for it (the boot selection says something
  202. // like "Windows NT Setup or Upgrade"). When that is selected, the boot loader
  203. // loads 16 sectors worth of data from bootsect.dat into d000 (which is where
  204. // the first sector of this code would have loaded it) and jumps into it at
  205. // a known location of 256h. That was correct in earlier versions of NT
  206. // but is not correct now because the 4 fields below were added to this sector.
  207. //
  208. // Note that 0000 is "add [bx+si],al" which because of the way the boot loader
  209. // is written happens to be a benign add of 0 to something in segment 7c0,
  210. // which doesn't seem to hose anything but is still somewhat random.
  211. //
  212. // We code in a jump here so as this new code proliferates we get this
  213. // cleaned up.
  214. //
  215. // .errnz $-_ntfsboot ne 256h
  216. // SectorsPerFrs label dword ; Sectors per File Record Segment
  217. // jmp short mainboot
  218. // nop
  219. // nop
  220. // .errnz $-_ntfsboot ne 25ah
  221. SectorsPerFrs: data4 0 // Sectors per File Record Segment
  222. BytesPerIndexBlock: data4 0 // Bytes per index alloc block in root index
  223. ClustersPerIndexBlock: data4 0 // Clusters per index alloc block in root index
  224. SectorsPerIndexBlock: data4 0 // Sectors per index block in root index
  225. //***************************************************************************
  226. //
  227. // mainboot - entry point after 16 boot sectors have been read in
  228. //
  229. //
  230. .align 0x10
  231. NESTED_ENTRY(mainboot)
  232. NESTED_SETUP(3,6,8,0)
  233. PROLOGUE_END
  234. rpT0 = t22
  235. rpT1 = t21
  236. rpT2 = t20
  237. rpT3 = t19
  238. rIndexRoot = loc2
  239. rIRAttrib = loc3
  240. rNtldrIndex = loc4
  241. rPlabel = loc5
  242. //
  243. // Setup the stack scratch area
  244. //
  245. add sp = -STACK_SCRATCH_AREA, sp
  246. //
  247. // Reinitialize xint13-related variables
  248. //
  249. // br.call.sptd.many brp = Int13SecCnt // determine range of regular int13
  250. // Set up the FRS buffers. The MFT buffer is in a fixed
  251. // location, and the other three come right after it. The
  252. // buffer for index allocation blocks comes after that.
  253. //
  254. //
  255. // Compute the useful constants associated with the volume
  256. //
  257. movl rpT0 = BytesPerSector // Bytes Per Sector
  258. ld2 out0 = [rpT0]
  259. movl rpT0 = SectorsPerCluster // Sectors Per Cluster
  260. ld1 out1 = [rpT0]
  261. mov ap = sp
  262. br.call.sptk.many brp = Multiply
  263. movl rpT0 = BytesPerCluster
  264. st4 [rpT0] = v0
  265. movl rpT0 = ClustersPerFrs // Clusters Per FRS
  266. ld1 t0 = [rpT0]
  267. sxt1 t0 = t0
  268. cmp.gt pt0,pt1 = t0, zero // ClustersPerFrs less than zero?
  269. (pt0) br.cond.sptk.clr mainboot1
  270. // If the ClustersPerFrs field is negative, we calculate the number
  271. // of bytes per FRS by negating the value and using that as a shift count.
  272. //
  273. sub t0 = zero, t0
  274. movl t1 = 1
  275. shl t3 = t1, t0 // bytes per frs
  276. br.cond.sptk.clr mainboot2
  277. mainboot1:
  278. // Otherwise if ClustersPerFrs was positive, we multiply by bytes
  279. // per cluster.
  280. movl rpT0 = BytesPerCluster
  281. ld4 out1 = [rpT0]
  282. mov out0 = t0
  283. mov ap = sp
  284. br.call.sptk.many brp = Multiply
  285. mainboot2:
  286. movl rpT0 = BytesPerFrs
  287. st4 [rpT0] = v0
  288. movl rpT0 = BytesPerSector
  289. ld2 t2 = [rpT0]
  290. mov out0 = t3
  291. mov out1 = t2
  292. movl out2 = Result
  293. movl out3 = Remainder
  294. mov ap = sp
  295. br.call.sptk.many brp = Divide
  296. movl rpT0 = Result
  297. ld4 t0 = [rpT0]
  298. movl rpT0 = SectorsPerFrs
  299. st4 [rpT0] = t0
  300. // Set up the MFT FRS's---this will read all the $DATA attribute
  301. // records for the MFT.
  302. //
  303. mov ap = sp
  304. br.call.sptk.many brp = SetupMft
  305. // Set up the remaining FRS buffers. The RootIndex FRS comes
  306. // directly after the last MFT FRS, followed by the NTLdr FRS
  307. // and the Index Block buffer.
  308. //
  309. movl rpT0 = NextBuffer
  310. ld4 t0 = [rpT0]
  311. movl rpT0 = RootIndexFrs
  312. st4 [rpT0] = t0
  313. movl rpT0 = BytesPerFrs
  314. ld4 t1 = [rpT0]
  315. add t0 = t0, t1 // AllocationFrs may be different
  316. movl rpT0 = AllocationIndexFrs // from RootIndexFrs - KPeery
  317. st4 [rpT0] = t0
  318. add t0 = t0, t1 // BitmapFrs may be different
  319. movl rpT0 = BitmapIndexFrs // from RootIndexFrs - KPeery
  320. st4 [rpT0] = t0
  321. add t0 = t0, t1
  322. movl rpT0 = NtldrFrs
  323. st4 [rpT0] = t0
  324. add t0 = t0, t1
  325. movl rpT0 = IndexBlockBuffer
  326. st4 [rpT0] = t0
  327. //
  328. // Read the root index, allocation index and bitmap FRS's and locate
  329. // the interesting attributes.
  330. //
  331. movl out0 = $INDEX_ROOT
  332. movl rpT0 = RootIndexFrs
  333. ld4 out1 = [rpT0]
  334. mov ap = sp
  335. br.call.sptk.many brp = LoadIndexFrs
  336. cmp.eq pt0, pt1 = v0, zero
  337. (pt0) br.cond.sptk.clr BootErr$he
  338. mov rIndexRoot = v0
  339. movl rpT0 = IndexRoot // offset in Frs buffer
  340. st4 [rpT0] = rIndexRoot
  341. movl out0 = $INDEX_ALLOCATION // Attribute type code
  342. movl rpT0 = AllocationIndexFrs // FRS to search
  343. ld4 out1 = [rpT0]
  344. br.call.sptk.many brp = LoadIndexFrs
  345. movl rpT0 = IndexAllocation
  346. st4 [rpT0] = v0
  347. movl out0 = $BITMAP // Attribute type code
  348. movl rpT0 = BitmapIndexFrs // FRS to search
  349. ld4 out1 = [rpT0]
  350. br.call.sptk.many brp = LoadIndexFrs
  351. movl rpT0 = IndexBitmap
  352. st4 [rpT0] = v0
  353. // Consistency check: the index root must exist, and it
  354. // must be resident.
  355. //
  356. cmp.eq pt0, pt1 = rIndexRoot, zero
  357. (pt0) br.cond.sptk.clr BootErr$he
  358. add rpT0 = ATTR_FormCode, rIndexRoot
  359. ld1 t0 = [rpT0]
  360. cmp.eq pt0, pt1 = RESIDENT_FORM, t0
  361. (pt1) br.cond.sptk.clr BootErr$he
  362. // Determine the size of the index allocation buffer based
  363. // on information in the $INDEX_ROOT attribute. The index
  364. // bitmap buffer comes immediately after the index block buffer.
  365. //
  366. // rIndexRoot -> $INDEX_ROOT attribute record
  367. //
  368. add rpT3 = RES_ValueOffset, rIndexRoot // value of $INDEX_ROOT
  369. ld2 t0 = [rpT3]
  370. add rIRAttrib = rIndexRoot, t0
  371. add rpT0 = IR_BlocksPerIndexBuffer, rIRAttrib
  372. ld1 t0 = [rpT0]
  373. movl rpT1 = ClustersPerIndexBlock
  374. st4 [rpT1] = t0
  375. add rpT0 = IR_BytesPerIndexBuffer, rIRAttrib
  376. ld4 t0 = [rpT0]
  377. movl rpT1 = BytesPerIndexBlock
  378. st4 [rpT1] = t0
  379. mov out0 = t0
  380. movl rpT0 = BytesPerSector
  381. ld2 out1 = [rpT0]
  382. movl out2 = Result
  383. movl out3 = Remainder
  384. mov ap = sp
  385. br.call.sptk.many brp = Divide
  386. movl rpT0 = Result
  387. ld4 t0 = [rpT0]
  388. movl rpT1 = SectorsPerIndexBlock
  389. st4 [rpT1] = t0
  390. movl rpT2 = IndexBlockBuffer
  391. ld4 t0 = [rpT2]
  392. movl rpT3 = BytesPerIndexBlock
  393. ld4 t1 = [rpT3]
  394. add t2 = t0, t1
  395. movl rpT0 = IndexBitmapBuffer
  396. st4 [rpT0] = t2
  397. // Next consistency check: if the $INDEX_ALLOCATION attribute
  398. // exists, the $INDEX_BITMAP attribute must also exist.
  399. //
  400. movl rpT0 = IndexAllocation
  401. ld4 t0 = [rpT0]
  402. cmp.eq pt0, pt1 = t0, zero
  403. (pt0) br.cond.sptk.clr mainboot30
  404. movl rpT0 = IndexBitmap
  405. ld4 t0 = [rpT0]
  406. cmp.eq pt0, pt1 = t0, zero // since IndexAllocation exists, the
  407. (pt0) br.cond.sptk.clr BootErr$he // bitmap must exist, too.
  408. // Since the bitmap exists, we need to read it into the bitmap
  409. // buffer. If it's resident, we can just copy the data.
  410. //
  411. movl rpT0 = IndexBitmap
  412. ld4 out0 = [rpT0] // out0 -> index bitmap attribute
  413. movl rpT1 = IndexBitmapBuffer
  414. ld4 out1 = [rpT1] // out1 -> index bitmap buffer
  415. mov ap = sp
  416. br.call.sptk.many brp = ReadWholeAttribute
  417. mainboot30:
  418. //
  419. // OK, we've got the index-related attributes.
  420. //
  421. movl out0 = ntldr_name // out0 -> name
  422. movl rpT0 = ntldr_name_length
  423. ld2 out1 = [rpT0] // out1 = name length in characters
  424. mov ap = sp
  425. br.call.sptk.many brp = FindFile
  426. cmp.eq pt0, pt1 = v0, zero
  427. (pt0) br.cond.sptk.clr BootErr$fnf
  428. mov rNtldrIndex = v0
  429. // Read the FRS for NTLDR and find its data attribute.
  430. //
  431. // rNtldrIndex -> Index Entry for NTLDR.
  432. //
  433. add rpT0 = IE_FileReference+LowPart, rNtldrIndex
  434. ld4 out0 = [rpT0]
  435. movl rpT1 = NtldrFrs
  436. ld4 out1 = [rpT1]
  437. mov ap = sp
  438. br.call.sptk.many brp = ReadFrs
  439. movl rpT0 = NtldrFrs
  440. ld4 out0 = [rpT0] // pointer to FRS
  441. movl out1 = $DATA // requested attribute type
  442. mov out2 = zero // attribute name length in characters
  443. mov out3 = zero // attribute name (NULL if none)
  444. mov ap = sp
  445. br.call.sptk.many brp = LocateAttributeRecord
  446. // v0 -> $DATA attribute for NTLDR
  447. //
  448. cmp.eq pt0, pt1 = v0, zero
  449. (pt1) br.cond.sptk.clr mainboot$FoundData // found attribute
  450. //
  451. // The ntldr $DATA segment is fragmented. Search the attribute list
  452. // for the $DATA member. And load it from there.
  453. //
  454. movl out0 = $DATA // Attribute type code
  455. movl rpT0 = NtldrFrs
  456. ld4 out1 = [rpT0] // FRS to search
  457. mov ap = sp
  458. br.call.sptk.many brp = SearchAttrList // search attribute list for FRN
  459. // of specified ($DATA)
  460. cmp.eq pt0, pt1 = v0, zero // if v0 is zero, attribute not found.
  461. (pt0) br.cond.sptk.clr BootErr$fnf
  462. //
  463. // We found the FRN of the $DATA attribute; load that into memory.
  464. //
  465. movl rpT0 = NtldrFrs
  466. ld4 out0 = [rpT0]
  467. mov ap = sp
  468. br.call.sptk.many brp = ReadFrs
  469. //
  470. // Determine the beginning offset of the $DATA in the FRS
  471. //
  472. movl rpT0 = NtldrFrs // pointer to FRS
  473. ld4 out0 = [rpT0]
  474. movl out1 = $DATA // requested attribute type
  475. mov out2 = zero // attribute name length in characters
  476. mov out3 = zero // attribute name (NULL if none)
  477. mov ap = sp
  478. br.call.sptk.many brp = LocateAttributeRecord
  479. // v0 -> $DATA attribute for NTLDR
  480. //
  481. cmp.eq pt0, pt1 = v0, zero // if v0 is zero, attribute not found.
  482. (pt0) br.cond.sptk.clr BootErr$fnf
  483. mainboot$FoundData:
  484. // Get the attribute record header flags, and make sure none of the
  485. // `compressed' bits are set
  486. add rpT0 = ATTR_Flags, v0
  487. ld2 t0 = [rpT0]
  488. movl t1 = ATTRIBUTE_FLAG_COMPRESSION_MASK
  489. and t2 = t0, t1
  490. cmp.eq pt0, pt1 = t2, zero
  491. (pt1) br.cond.sptk.clr BootErr$ntc
  492. mov out0 = v0 // out0 -> $DATA attribute for NTLDR
  493. movl out1 = LdrSeg // out1 = buffer address
  494. mov ap = sp
  495. br.call.sptk.many brp = ReadWholeAttribute
  496. //
  497. // Relocate the NTLDR image from LdrSeg to what is specified by the PE header
  498. //
  499. movl out0 = LdrSeg // out1 = buffer address
  500. mov ap = sp
  501. br.call.sptk.many brp = RelocateLoaderSections
  502. mov rPlabel = v0
  503. //
  504. // Tell simdb to load NTLDR symbols
  505. //
  506. mov ap = sp
  507. br.call.sptk.many brp = LoadNtldrSymbols
  508. //
  509. // We've loaded NTLDR--jump to it.
  510. //
  511. // Before we go to NTLDR, set up the registers the way it wants them:
  512. //
  513. movl out0 = DriveNumber
  514. movl out1 = BytesPerSector
  515. mov psr.l = zero
  516. movl t1 = MASK(PSR_BN,1) | MASK(PSR_IT,1) | MASK(PSR_DA,1) | MASK(PSR_RT,1) | MASK(PSR_DT,1) | MASK(PSR_PK,1) | MASK(PSR_I,1)| MASK(PSR_IC,1)
  517. mov cr.ipsr = t1
  518. add rpT0 = PlEntryPoint, rPlabel
  519. ld8 t0 = [rpT0]
  520. mov cr.iip = t0
  521. add rpT1 = PlGlobalPointer, rPlabel
  522. ld8 gp = [rpT1]
  523. rfi // "return" to NTLDR.
  524. ;;
  525. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  526. NESTED_RETURN
  527. NESTED_EXIT(mainboot)
  528. //****************************************************************************
  529. //
  530. // ReadClusters - Reads a run of clusters from the disk.
  531. //
  532. // ENTRY: in0 == LCN to read
  533. // in1 == clusters to read
  534. // in2 -> Target buffer
  535. //
  536. // USES: none (preserves all registers)
  537. //
  538. NESTED_ENTRY(ReadClusters)
  539. NESTED_SETUP(3,4,8,0)
  540. PROLOGUE_END
  541. rpT0 = t22
  542. rpT1 = t21
  543. rLcn = in0
  544. rCluster = in1
  545. rBuffer = in2
  546. rSectorBase = loc2
  547. rSectorsPerCluster = loc3
  548. //
  549. // setup stack scratch area
  550. //
  551. add sp = -STACK_SCRATCH_AREA, sp
  552. movl rpT0 = SectorsPerCluster
  553. ld1 rSectorsPerCluster = [rpT0]
  554. mov out0 = rLcn
  555. mov out1 = rSectorsPerCluster
  556. mov ap = sp
  557. br.call.sptk.many brp = Multiply
  558. mov rSectorBase= v0
  559. mov out0 = rCluster
  560. mov out1 = rSectorsPerCluster
  561. mov ap = sp
  562. br.call.sptk.many brp = Multiply
  563. mov out1 = v0 // Number of sectors to read
  564. mov out0 = rSectorBase
  565. mov out2 = rBuffer
  566. mov ap = sp
  567. br.call.sptk.many brp = ReadSectors
  568. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  569. NESTED_RETURN
  570. NESTED_EXIT(ReadClusters)
  571. //
  572. //****************************************************************************
  573. //
  574. // LocateAttributeRecord -- Find an attribute record in an FRS.
  575. //
  576. // ENTRY: in0 -- pointer to FRS
  577. // in1 -- desired attribute type code
  578. // in2 -- length of attribute name in characters
  579. // in3 -- pointer to attribute name
  580. //
  581. // EXIT: v0 points at attribute record (0 indicates not found)
  582. //
  583. // USES: All
  584. //
  585. NESTED_ENTRY(LocateAttributeRecord)
  586. NESTED_SETUP(4,3,8,0)
  587. PROLOGUE_END
  588. rpFrs = in0
  589. rTypeCode = in1
  590. rLength = in2
  591. rpAttrName = in3
  592. rpCurrentName = loc2
  593. rpT0 = t22
  594. rpT1 = t21
  595. //
  596. // Setup stack scratch area
  597. //
  598. add sp = -STACK_SCRATCH_AREA, sp
  599. //
  600. // get the first attribute record.
  601. //
  602. add rpT0 = FRS_FirstAttributeOffset, rpFrs
  603. ld2 t0 = [rpT0]
  604. add rpFrs = rpFrs, t0
  605. // rpFrs -> next attribute record to investigate.
  606. // rTypeCode == desired type
  607. // rLength == name length
  608. // rpAttrName -> pointer to name
  609. //
  610. lar10:
  611. add rpT0 = ATTR_TypeCode, rpFrs
  612. ld4 t0 = [rpT0]
  613. movl t1 = 0xffffffff
  614. cmp.eq pt0, pt1 = t0, t1
  615. (pt0) br.cond.sptk.clr lar99
  616. cmp.eq pt0, pt1 = t0, rTypeCode
  617. (pt1) br.cond.sptk.clr lar80
  618. // this record is a potential match. Compare the names:
  619. //
  620. // rpFrs -> candidate record
  621. // rTypeCode == desired type
  622. // rLength == name length
  623. // rpAttrName -> pointer to name
  624. //
  625. cmp.eq pt0, pt1 = zero, rLength //Did the caller pass in a name length?
  626. (pt1) br.cond.sptk.clr lar20
  627. // We want an attribute with no name--the current record is
  628. // a match if and only if it has no name.
  629. //
  630. add rpT0 = ATTR_NameLength, rpFrs
  631. ld1 t0 = [rpT0]
  632. cmp.eq pt0, pt1 = zero, t0
  633. (pt1) br.cond.sptk.clr lar80 // Not a match.
  634. // It's a match, and rpFrs is set up correctly, so return.
  635. //
  636. mov v0 = rpFrs
  637. add sp = STACK_SCRATCH_AREA, sp // retore the original sp
  638. NESTED_RETURN
  639. // We want a named attribute.
  640. //
  641. // rpFrs -> candidate record
  642. // rTypeCode == desired type
  643. // rLength == name length
  644. // rpAttrName -> pointer to name
  645. //
  646. lar20:
  647. add rpT0 = ATTR_NameLength, rpFrs
  648. ld1 t0 = [rpT0]
  649. cmp.eq pt0, pt1 = rLength, t0
  650. (pt1) br.cond.sptk.clr lar80 // Not a match.
  651. // Convert name in current record to uppercase.
  652. //
  653. add rpT0 = ATTR_NameOffset, rpFrs
  654. ld2 t0 = [rpT0]
  655. add rpCurrentName = rpFrs, t0
  656. mov out0 = rpCurrentName
  657. add out1 = ATTR_NameLength, rpFrs
  658. mov ap = sp
  659. br.call.sptk.clr brp = UpcaseName
  660. // rpFrs -> candidate record
  661. // rTypeCode == desired type
  662. // rLength == name length
  663. // rpAttrName -> pointer to name
  664. // in4 -> Name in current record (upcased)
  665. //
  666. mov t2 = rLength
  667. mov rpT0 = rpCurrentName
  668. mov rpT1 = rpAttrName
  669. lar79:
  670. ld2 t0 = [rpT0], 2
  671. ld2 t1 = [rpT1], 2
  672. cmp.eq pt0, pt1 = t0, t1
  673. (pt1) br.cond.sptk.clr lar80
  674. add t2 = -1, t2
  675. cmp.gt pt0, pt1 = t2, zero
  676. (pt0) br.cond.sptk.clr lar79
  677. // t1 points at a matching record.
  678. //
  679. mov v0 = rpFrs
  680. add sp = STACK_SCRATCH_AREA, sp // restore sp before returning
  681. NESTED_RETURN
  682. //
  683. // This record doesn't match; go on to the next.
  684. //
  685. // rpFrs -> rejected candidate attribute record
  686. // rTypeCode == desired type
  687. // rLength == Name length
  688. // rpAttrName -> desired name
  689. //
  690. lar80: add rpT0 = ATTR_RecordLength, rpFrs
  691. ld1 t0 = [rpT0]
  692. cmp.eq pt0, pt1 = zero, t0 // if the record length is zero
  693. (pt0) br.cond.sptk.clr lar99 // the FRS is corrupt.
  694. add rpFrs = rpFrs, t0
  695. br.cond.sptk.clr lar10
  696. // Didn't find it.
  697. //
  698. lar99: mov v0 = zero
  699. add sp = STACK_SCRATCH_AREA, sp // restore sp before returning
  700. NESTED_RETURN
  701. NESTED_EXIT(LocateAttributeRecord)
  702. //****************************************************************************
  703. //
  704. // LocateIndexEntry -- Find an index entry in a file name index
  705. //
  706. // ENTRY: in0 -> pointer to index header
  707. // in1 -> file name to find
  708. // in2 == length of file name in characters
  709. //
  710. // EXIT: v0 points at index entry. NULL to indicate failure.
  711. //
  712. // USES: All
  713. //
  714. NESTED_ENTRY(LocateIndexEntry)
  715. NESTED_SETUP(3,4,8,0)
  716. PROLOGUE_END
  717. rpT0 = t22
  718. rHeader = in0
  719. rpName = in1
  720. rLength = in2
  721. rEntry = loc2
  722. rAttr = loc3
  723. //
  724. // Setup the stack scratch area
  725. //
  726. add sp = -STACK_SCRATCH_AREA, sp
  727. // Convert the input name to upper-case
  728. //
  729. mov out0 = rpName
  730. mov out1 = rLength
  731. mov ap = sp
  732. br.call.sptk.many brp = UpcaseName
  733. #ifdef DEBUG
  734. mov out0 = rpName
  735. mov ap = sp
  736. br.call.sptk.many brp = PrintName
  737. mov ap = sp
  738. br.call.sptk.many brp = Debug2
  739. #endif DEBUG
  740. add rpT0 = IH_FirstIndexEntry, rHeader
  741. ld4 t0 = [rpT0]
  742. add rEntry = rHeader, t0
  743. // rEntry -> current entry
  744. // rpName -> file name to find
  745. // rLength == length of file name in characters
  746. //
  747. lie10: add rpT0 = IE_Flags, rEntry
  748. ld2 t0 = [rpT0]
  749. and t1 = INDEX_ENTRY_END, t0 // Is it the end entry?
  750. cmp.eq pt0, pt1 = t1, zero
  751. (pt1) br.cond.sptk.clr lie99 // quit if it is
  752. add rAttr = IE_Reserved+0x2, rEntry // FILE_NAME attribute value
  753. // was IE_Value
  754. #ifdef DEBUG
  755. // DEBUG CODE -- list file names as they are examined
  756. mov ap = sp
  757. br.call.sptk.many brp = Debug3
  758. mov rpT0 = FN_FileNameLength, rAttr
  759. ld1 out1 = [rpT0]
  760. add out0 = FN_FileName, rAttr
  761. mov ap = sp
  762. br.call.sptk.many brp = PrintName
  763. #endif DEBUG
  764. // rEntry -> current entry
  765. // rpName -> file name to find
  766. // rLength == length of file name in characters
  767. // rAttr -> FILE_NAME attribute
  768. add rpT0 = FN_FileNameLength, rAttr
  769. ld1 t0 = [rpT0]
  770. cmp.eq pt0, pt1 = t0, rLength // Is name the right length?
  771. (pt1) br.cond.sptk.clr lie80
  772. add out0 = FN_FileName, rAttr // Get name from FILE_NAME structure
  773. mov out1 = rLength
  774. mov ap = sp
  775. br.call.sptk.many brp = UpcaseName
  776. add out0 = FN_FileName, rAttr
  777. mov out1 = rpName // out0 alread setup by last call
  778. mov out2 = rLength
  779. br.call.sptk.many brp = strncmp
  780. cmp.eq pt0, pt1 = v0, zero
  781. (pt1) br.cond.sptk.clr lie80
  782. // the current entry matches the search name, and eax points at it.
  783. //
  784. mov v0 = rEntry
  785. add sp = STACK_SCRATCH_AREA, sp
  786. NESTED_RETURN
  787. // The current entry is not a match--get the next one.
  788. // rEntry -> current entry
  789. // rpName -> file name to find
  790. // rLength == length of file name in characters
  791. //
  792. lie80: add rpT0 = IE_Length, rEntry
  793. ld2 t0 = [rpT0]
  794. cmp.eq pt0, pt1 = t0, zero // If the entry length is zero
  795. (pt0) br.cond.sptk.clr lie99 // then the index block is corrupt.
  796. add rEntry = rEntry, t0 // Get the next entry.
  797. br.cond.sptk.clr lie10
  798. // Name not found in this block. Set v0 to zero and return
  799. //
  800. lie99: mov v0 = zero
  801. add sp = STACK_SCRATCH_AREA, sp
  802. NESTED_RETURN
  803. NESTED_EXIT(LocateIndexEntry)
  804. //****************************************************************************
  805. //
  806. // ReadWholeAttribute - Read an entire attribute value
  807. //
  808. // ENTRY: in0 -> attribute
  809. // in1 -> target buffer
  810. //
  811. // USES: ALL
  812. //
  813. NESTED_ENTRY(ReadWholeAttribute)
  814. NESTED_SETUP(2,4,8,0)
  815. rAttribute = in0
  816. rBuffer = in1
  817. rpT0 = t22
  818. // setup sp and ap for all function calls
  819. add sp = -STACK_SCRATCH_AREA, sp
  820. add rpT0 = ATTR_FormCode, in0
  821. ld1 t0 = [rpT0]
  822. cmp.eq pt0, pt1 = RESIDENT_FORM, t0
  823. (pt1) br.cond.sptk.clr rwa10
  824. // The attribute is resident.
  825. // rAttribute -> attribute
  826. // rBuffer -> target buffer
  827. //
  828. add rpT0 = RES_ValueOffset, rAttribute
  829. ld2 t0 = [rpT0]
  830. add out0 = rAttribute, t0
  831. mov out1 = rBuffer
  832. add rpT0 = RES_ValueLength, rAttribute
  833. ld4 out2 = [rpT0]
  834. mov ap = sp
  835. br.call.sptk.many brp = memcpy
  836. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  837. NESTED_RETURN // That's all!
  838. rwa10:
  839. //
  840. // The attribute type is non-resident. Just call
  841. // ReadNonresidentAttribute starting at VCN 0 and
  842. // asking for the whole thing.
  843. //
  844. // rAttribute -> attribute
  845. // rBuffer -> target buffer
  846. //
  847. mov out0 = zero // 0 (first VCN to read)
  848. mov out1 = rAttribute // Attribute
  849. add rpT0 = NONRES_HighestVcn+LowPart, rAttribute // # of clusters
  850. ld4 out2 = [rpT0]
  851. add out2 = 1, out2
  852. mov out3 = rBuffer // Target Buffer
  853. mov ap = sp
  854. br.call.sptk.many brp = ReadNonresidentAttribute
  855. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  856. NESTED_RETURN
  857. NESTED_EXIT(ReadWholeAttribute)
  858. //****************************************************************************
  859. //
  860. // ReadNonresidentAttribute - Read clusters from a nonresident attribute
  861. //
  862. // ENTRY: in0 == First VCN to read
  863. // in1 -> Attribute
  864. // in2 == Number of clusters to read
  865. // in3 == Target of read
  866. //
  867. // EXIT: None.
  868. //
  869. // USES: None (preserves all registers with SAVE_ALL/RESTORE_ALL)
  870. //
  871. NESTED_ENTRY(ReadNonresidentAttribute)
  872. NESTED_SETUP(4,4,8,0)
  873. PROLOGUE_END
  874. rVcn = in0
  875. rAttribute = in1
  876. rCluster = in2
  877. rBuffer = in3
  878. rRun = loc2
  879. rTmp = loc3
  880. //
  881. // setup stack scratch area
  882. //
  883. add sp = -STACK_SCRATCH_AREA, sp
  884. add rpT0 = ATTR_FormCode, rAttribute
  885. ld1 t0 = [rpT0]
  886. cmp.eq pt0, pt1 = NONRESIDENT_FORM, t0
  887. (pt0) br.cond.sptk.clr ReadNR10
  888. // This attribute is not resident--the disk is corrupt.
  889. br.cond.sptk.clr BootErr$he
  890. ReadNR10:
  891. // rVcn == Next VCN to read
  892. // rAttribute -> Attribute
  893. // rCluster -> Remaining clusters to read
  894. // rBuffer -> Target of read
  895. //
  896. cmp.eq pt0, pt1 = rCluster,zero
  897. (pt1) br.cond.sptk.clr ReadNR20
  898. // Nothing left to read--return success.
  899. //
  900. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  901. NESTED_RETURN
  902. ReadNR20:
  903. mov out0 = rVcn
  904. mov out1 = rAttribute
  905. mov ap = sp
  906. br.call.sptk.many brp = ComputeLcn
  907. mov rLcn = t0 // rLcn = LCN
  908. mov rRun = t1 // rRun = remaining run length
  909. // rLcn == LCN to read
  910. // rCluster == remaining clusters to read
  911. // rRun == remaining clusters in current run
  912. // rBuffer == Target of read
  913. //
  914. cmp.ge pt0, pt1 = rCluster, rRun
  915. (pt0) br.cond.sptk.clr ReadNR30
  916. // Run length is greater than remaining request// only read
  917. // remaining request.
  918. //
  919. mov rRun = rCluster // rRun = Remaining request
  920. ReadNR30:
  921. // rLcn == LCN to read
  922. // rCluster == remaining clusters to read
  923. // rRun == clusters to read in current run
  924. // rBuffer == Target of read
  925. //
  926. mov out0 = rLcn
  927. mov out1 = rCluster
  928. mov out2 = rBuffer
  929. mov ap = sp
  930. br.call.sptk.many brp = ReadClusters
  931. sub rCluster = rCluster, rRun // Decrement clusters remaining
  932. mov out0 = rRun
  933. movl rpT0 = SectorsPerCluster
  934. ld1 out1 = [rpT0]
  935. mov ap = sp
  936. br.call.sptk.many brp = Multiply
  937. mov out0 = v0
  938. movl rpT0 = BytesPerSector
  939. ld4 out1 = [rpT0]
  940. mov ap = sp
  941. br.call.sptk.many brp = Multiply
  942. add rBuffer = rBuffer, v0 // Update target of read
  943. add rVcn = rVcn, rRun // Update VCN to read
  944. br.cond.sptk.clr ReadNR10
  945. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  946. NESTED_RETURN
  947. NESTED_EXIT(ReadNonresidentAttribute)
  948. //****************************************************************************
  949. //
  950. // ReadIndexBlockSectors - Read sectors from an index allocation attribute
  951. //
  952. // ENTRY: in0 == First VBN to read
  953. // in1 -> Attribute
  954. // in2 == Number of sectors to read
  955. // in3 == Target of read
  956. //
  957. // EXIT: None.
  958. //
  959. // USES: None (preserves all registers with SAVE_ALL/RESTORE_ALL)
  960. //
  961. NESTED_ENTRY(ReadIndexBlockSectors)
  962. NESTED_SETUP(4,6,8,0)
  963. PROLOGUE_END
  964. rpT0 = t22
  965. rVbn = in0
  966. rAttr = in1
  967. rSectors = in2
  968. rBuffer = in3
  969. rSectorsPerCluster = loc2
  970. rRemainClusters = loc3
  971. rRunSectors = loc4
  972. rLbn = loc5
  973. //
  974. // Setup stack scratch area
  975. //
  976. add sp = -STACK_SCRATCH_AREA, sp
  977. add rpT0 = ATTR_FormCode, rAttr
  978. ld1 t0 = [rpT0]
  979. cmp.eq pt0, pt1 = NONRESIDENT_FORM, t0
  980. (pt0) br.cond.sptk.clr ReadIBS_10
  981. // This attribute is resident--the disk is corrupt.
  982. br.cond.sptk.clr BootErr$he
  983. ReadIBS_10:
  984. // rVbn == Next VBN to read
  985. // rAttr -> Attribute
  986. // rSectors -> Remaining sectors to read
  987. // rBuffer -> Target of read
  988. //
  989. cmp.eq pt0, pt1 = rSectors, zero
  990. (pt1) br.cond.sptk.clr ReadIBS_20
  991. // Nothing left to read--return success.
  992. //
  993. add sp = STACK_SCRATCH_AREA, sp
  994. NESTED_RETURN
  995. ReadIBS_20:
  996. // Convert rVbn from a VBN back to a VCN by dividing by SectorsPerCluster.
  997. // The remainder of this division is the sector offset in the cluster we
  998. // want. Then use the mapping information to get the LCN for this VCN,
  999. // then multiply to get back to LBN.
  1000. //
  1001. mov out0 = rVbn
  1002. movl rpT0 = SectorsPerCluster
  1003. ld1 rSectorsPerCluster = [rpT0]
  1004. mov out1 = rSectorsPerCluster
  1005. movl out2 = Result
  1006. movl out3 = Remainder
  1007. mov ap = sp
  1008. br.call.sptk.many brp = Divide
  1009. movl rpT0 = Result
  1010. ld4 out0 = [rpT0]
  1011. mov out1 = rAttr
  1012. mov ap = sp
  1013. br.call.sptk.many brp = ComputeLcn // t0 = LCN to read,
  1014. // t1 = remaining run length
  1015. mov rRemainClusters = t1
  1016. mov out0 = t0
  1017. mov out1 = rSectorsPerCluster
  1018. mov ap = sp
  1019. br.call.sptk.many brp = Multiply // v0 = LBN of cluster
  1020. movl rpT0 = Remainder
  1021. ld4 t0 = [rpT0] // t0 = remainder
  1022. add rLbn = v0, t0 // rLbn = LBN we want
  1023. mov out0 = rRemainClusters
  1024. mov out1 = rSectorsPerCluster
  1025. mov ap = sp
  1026. br.call.sptk.many brp = Multiply // v0 = remaining run length in sectors
  1027. mov rRunSectors = v0 // remaining run length
  1028. // rLbn == LBN to read
  1029. // rSectors == remaining sectors to read
  1030. // rRunSectors == remaining sectors in current run
  1031. // rBuffer == Target of read
  1032. //
  1033. cmp.ge pt0, pt1 = rSectors, rRunSectors
  1034. (pt0) br.cond.sptk.clr ReadIBS_30
  1035. // Run length is greater than remaining request; only read
  1036. // remaining request.
  1037. //
  1038. mov rRunSectors = rSectors // rRunSectors = Remaining request
  1039. ReadIBS_30:
  1040. // rLbn == LBN to read
  1041. // rSectors == remaining sectors to read
  1042. // rRunSectors == sectors to read in current run
  1043. // rBuffer == Target of read
  1044. //
  1045. mov out0 = rLbn
  1046. mov out1 = rRunSectors
  1047. mov out2 = rBuffer
  1048. mov ap = sp
  1049. br.call.sptk.many brp = ReadSectors
  1050. //
  1051. // Decrement sectors remaining in request
  1052. //
  1053. sub rSectors = rSectors, rRunSectors
  1054. mov out0 = rRunSectors // eax = sectors read
  1055. movl rpT0 = BytesPerSector
  1056. ld2 out1 = [rpT0]
  1057. br.call.sptk.many brp = Multiply // v0 = bytes read (wipes out edx!)
  1058. add rBuffer = rBuffer, v0 // Update target of read
  1059. add rVbn = rVbn, rRunSectors // update VBN to read
  1060. br.cond.sptk.clr ReadIBS_10
  1061. add sp = STACK_SCRATCH_AREA, sp
  1062. NESTED_RETURN
  1063. NESTED_EXIT(ReadIndexBlockSectors)
  1064. //****************************************************************************
  1065. //
  1066. // MultiSectorFixup - fixup a structure read off the disk
  1067. // to reflect Update Sequence Array.
  1068. //
  1069. // ENTRY: in0 = Target buffer
  1070. //
  1071. // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
  1072. //
  1073. // Note: in0 must point at a structure which is protected
  1074. // by an update sequence array, and which begins with
  1075. // a multi-sector-header structure.
  1076. //
  1077. NESTED_ENTRY(MultiSectorFixup)
  1078. NESTED_SETUP(3,3,8,0)
  1079. PROLOGUE_END
  1080. #define MshUpdateSeqenceArrayOffset 4
  1081. #define SEQUENCE_NUMBER_STRIDE 512
  1082. add rpT0 = MshUpdateSeqenceArrayOffset, in0
  1083. ld2 t0 = [rpT0], 2 // t0 = update array offset
  1084. ld2 t1 = [rpT0] // t1 = update array size
  1085. cmp.eq pt0, pt1 = zero, t1 // if the size of the update sequence array
  1086. (pt0) br.cond.sptk.clr BootErr$he // is zero, this structure is corrupt.
  1087. add rpT0 = t0, in0 // rpT0 -> update sequence array count word
  1088. add rpT0 = 2, rpT0 // rpT0 -> 1st entry of update array
  1089. add rpT1=SEQUENCE_NUMBER_STRIDE-2,in0 //t2->last word of first chunk
  1090. movl t2 = 1
  1091. sub t1 = t1, t2 // decrement to reflect count word
  1092. cmp.eq pt0, pt1 = zero, t2
  1093. (pt0) br.cond.sptk.clr MSF30
  1094. MSF10:
  1095. // t1 = number of entries remaining in update sequence array
  1096. // rpT0 -> next entry in update sequence array
  1097. // rpT1 -> next target word for update sequence array
  1098. ld2 t0 = [rpT0] // copy next update sequence array entry
  1099. st2 [rpT0] = t0 // to next target word
  1100. add rpT0 = 2, rpT0 // go on to next entry
  1101. add rpT1 = SEQUENCE_NUMBER_STRIDE, rpT1 // go on to next target
  1102. sub t1 = t1, t2
  1103. cmp.lt pt0, pt1 = zero, t1
  1104. (pt0) br.cond.sptk.clr MSF10
  1105. MSF30:
  1106. NESTED_RETURN
  1107. NESTED_EXIT(MultiSectorFixup)
  1108. //****************************************************************************
  1109. //
  1110. // SetupMft - Reads MFT File Record Segments into memory.
  1111. //
  1112. // ENTRY: none.
  1113. //
  1114. // EXIT: NextBuffer is set to the free byte after the last MFT FRS
  1115. // SegmentsInMft is initialized
  1116. //
  1117. //
  1118. NESTED_ENTRY(SetupMft)
  1119. NESTED_SETUP(3,6,8,0)
  1120. PROLOGUE_END
  1121. rpT0 = t22
  1122. rpT1 = t21
  1123. rpT2 = t20
  1124. rpT3 = t19
  1125. rAttrList = loc2
  1126. rAttrLength = loc3
  1127. rNextBuffer = loc4
  1128. rBytesPerFrs = loc5
  1129. //
  1130. // Setup stack scratch area
  1131. //
  1132. add sp = -STACK_SCRATCH_AREA, sp
  1133. //
  1134. // Update MftFrs with NewSeg base offset
  1135. //
  1136. movl rpT0 = MftFrs
  1137. ld4 t0 = [rpT0]
  1138. movl t1 = NewSeg
  1139. add t2 = t0, t1
  1140. st4 [rpT0] = t2
  1141. // Initialize SegmentsInMft and NextBuffer as if the MFT
  1142. // had only one FRS.
  1143. //
  1144. movl t0 = 1
  1145. movl rpT0 = SegmentsInMft
  1146. st4 [rpT0] = t0
  1147. movl rpT1 = MftFrs
  1148. ld4 t1 = [rpT1]
  1149. movl rpT2 = BytesPerFrs
  1150. ld4 rBytesPerFrs = [rpT2]
  1151. add rNextBuffer = t1, rBytesPerFrs
  1152. movl rpT3 = NextBuffer
  1153. st4 [rpT3] = t3
  1154. // Read FRS 0 into the first MFT FRS buffer, being sure
  1155. // to resolve the Update Sequence Array.
  1156. //
  1157. movl rpT0 = MftStartLcn
  1158. ld8 out0 = [rpT0]
  1159. movl rpT1 = SectorsPerCluster
  1160. ld8 out1 = [rpT1]
  1161. mov ap = sp
  1162. br.call.sptk.many brp = Multiply
  1163. movl rpT0 = SectorBase // SectorBase = mft starting sector
  1164. st4 [rpT0] = v0
  1165. movl rpT0 = SectorsPerFrs
  1166. ld8 t0 = [rpT0]
  1167. movl rpT0 = SectorCount // SectorCount = SectorsPerFrs
  1168. st2 [rpT0] = t0
  1169. movl rpT0 = MftFrs
  1170. ld4 t0 = [rpT0]
  1171. movl rpT0 = SectorBase
  1172. ld4 out0 = [rpT0]
  1173. // Sector count is zero for some reason. Manually set to 1
  1174. //
  1175. movl rpT1 = SectorCount
  1176. ld4 out1 = [rpT1]
  1177. movl rpT0 = MftFrs
  1178. ld4 out2 = [rpT0]
  1179. mov ap = sp
  1180. br.call.sptk.many brp = ReadSectors
  1181. movl rpT0 = MftFrs
  1182. ld4 out0 = [rpT0]
  1183. #ifdef MFT_FRS
  1184. movl t1 = NewSeg
  1185. add out0 = t0, t1
  1186. #endif
  1187. mov ap = sp
  1188. br.call.sptk.many brp = MultiSectorFixup
  1189. // Determine whether the MFT has an Attribute List attribute
  1190. movl rpT0 = MftFrs
  1191. ld4 out0 = [rpT0]
  1192. #ifdef MFT_FRS
  1193. movl t1 = NewSeg
  1194. add out0 = t0, t1
  1195. #endif
  1196. movl out1 = $ATTRIBUTE_LIST
  1197. mov out2 = zero
  1198. mov out3 = zero
  1199. mov ap = sp
  1200. br.call.sptk.many brp = LocateAttributeRecord
  1201. cmp.eq pt0, pt1 = zero, v0 // If there's no Attribute list,
  1202. (pt0) br.cond.sptk.clr SetupMft99 // we're done!
  1203. // Read the attribute list.
  1204. // v0 -> attribute list attribute
  1205. //
  1206. mov out0 = v0 // out0 -> attribute list attribute
  1207. mov out1 = rAttrList // rAttrList -> attribute list buffer
  1208. mov ap = sp
  1209. br.call.sptk.many brp = ReadWholeAttribute
  1210. // Now, traverse the attribute list looking for the first
  1211. // entry for the $DATA type. We know it must have at least
  1212. // one.
  1213. //
  1214. // rAttrList -> first attribute list entry
  1215. //
  1216. SetupMft10:
  1217. add rpT0 = ATTRLIST_AttributeTypeCode, rAttrList
  1218. ld4 t0 = [rpT0]
  1219. movl t1 = $DATA
  1220. cmp.eq pt0, pt1 = t0, t1
  1221. (pt0) br.cond.sptk.clr SetupMft20
  1222. add rpT0 = ATTRLIST_RecordLength, rAttrList
  1223. ld4 t0 = [rpT0]
  1224. add rAttrList = rAttrList, t0
  1225. br.cond.sptk.clr SetupMft10
  1226. SetupMft20:
  1227. // Scan forward through the attribute list entries for the
  1228. // $DATA attribute, reading each referenced FRS. Note that
  1229. // there will be at least one non-$DATA entry after the entries
  1230. // for the $DATA attribute, since there's a $BITMAP.
  1231. //
  1232. // rAttrList -> Next attribute list entry
  1233. // rNextBuffer -> Target for next read
  1234. // SegmentsInMft == number of MFT segments read so far
  1235. //
  1236. add rpT0 = ATTRLIST_AttributeTypeCode, rAttrList
  1237. ld4 t0 = [rpT0]
  1238. movl t1 = $DATA
  1239. cmp.eq pt0, pt1 = t0, t1
  1240. (pt1) br.cond.sptk.clr SetupMft99
  1241. // Read the FRS referred to by this attribute list entry into
  1242. // the next buffer, and increment rNextBuffer and SegmentsInMft.
  1243. //
  1244. add rpT0 = ATTRLIST_SegmentReference, rAttrList
  1245. add rpT0 = REF_SegmentNumberLowPart, rAttrList
  1246. ld4 out0 = [rpT0]
  1247. mov out1 = rNextBuffer
  1248. mov ap = sp
  1249. br.call.sptk.many brp = ReadFrs
  1250. // Increment rNextBuffer and SegmentsInMft
  1251. add rNextBuffer = rNextBuffer, rBytesPerFrs
  1252. movl rpT0 = SegmentsInMft
  1253. ld4 t0 = [rpT0]
  1254. add t0 = 1, t0
  1255. st4 [rpT0] = t0
  1256. // Go on to the next attribute list entry
  1257. add rAttrList = rAttrList, rAttrLength
  1258. br.cond.sptk.clr SetupMft20
  1259. SetupMft99:
  1260. movl rpT0 = NextBuffer
  1261. st4 [rpT0] = rNextBuffer
  1262. add sp = STACK_SCRATCH_AREA, sp // readjust sp before exiting
  1263. NESTED_RETURN
  1264. NESTED_EXIT(SetupMft)
  1265. //****************************************************************************
  1266. //
  1267. // ComputeMftLcn -- Computes the LCN for a cluster of the MFT
  1268. //
  1269. //
  1270. // ENTRY: in0 == VCN
  1271. //
  1272. // EXIT: v0 == LCN
  1273. //
  1274. // USES: ALL
  1275. //
  1276. NESTED_ENTRY(ComputeMftLcn)
  1277. NESTED_SETUP(3,5,8,0)
  1278. PROLOGUE_END
  1279. rpT0 = t22
  1280. rFrsCount = loc2
  1281. rNextFrs = loc3
  1282. rVcn = loc4
  1283. //
  1284. // Setup sp and ap for all function calls
  1285. //
  1286. add sp = -STACK_SCRATCH_AREA, sp
  1287. mov ap = sp
  1288. mov rVcn = in0 // rVcn = VCN
  1289. movl rpT0 = SegmentsInMft // rFrsCount = # of FRS's to search
  1290. ld4 rFrsCount = [rpT0]
  1291. movl rpT0 = MftFrs // rNextFrs -> first FRS to search
  1292. ld4 rNextFrs = [rpT0]
  1293. MftLcn10:
  1294. // rNextFrs -> Next FRS to search
  1295. // rFrsCount == number of remaining FRS's to search
  1296. // rVcn == VCN
  1297. //
  1298. mov out0 = rNextFrs
  1299. movl out1 = $DATA
  1300. mov out2 = zero
  1301. mov out3 = zero
  1302. mov ap = sp
  1303. br.call.sptk.many brp = LocateAttributeRecord
  1304. cmp.eq pt0, pt1 = zero, v0
  1305. (pt0) br.cond.sptk.clr BootErr$he // No $DATA attribute in this FRS!
  1306. mov out0 = rVcn // out0 = VCN
  1307. mov out1 = v0 // out1 -> attribute
  1308. mov ap = sp
  1309. br.call.sptk.many brp = ComputeLcn
  1310. cmp.eq pt0, pt1 = zero, t0 // t0 is return value of ComputeLcn
  1311. (pt0) br.cond.sptk.clr MftLcn20
  1312. mov v0 = t0
  1313. add sp = STACK_SCRATCH_AREA, sp // readjust sp before exiting
  1314. NESTED_RETURN
  1315. MftLcn20:
  1316. //
  1317. // Didn't find the VCN in this FRS; try the next one.
  1318. //
  1319. movl rpT0 = BytesPerFrs // rNextFrs -> next FRS
  1320. ld4 t0 = [rpT0]
  1321. add rNextFrs = rNextFrs, t0
  1322. br.cond.sptk.clr MftLcn10 // decrement ecx and try next FRS
  1323. // This VCN was not found.
  1324. //
  1325. mov v0 = zero
  1326. add sp = STACK_SCRATCH_AREA, sp // readjust sp before exiting
  1327. NESTED_RETURN
  1328. NESTED_EXIT(ComputeMftLcn)
  1329. //****************************************************************************
  1330. //
  1331. // ReadMftSectors - Read sectors from the MFT
  1332. //
  1333. // ENTRY: in0 == starting VBN
  1334. // in1 == number of sectors to read
  1335. // in2 == Target buffer
  1336. //
  1337. // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
  1338. //
  1339. NESTED_ENTRY(ReadMftSectors)
  1340. NESTED_SETUP(3,4,8,0)
  1341. PROLOGUE_END
  1342. rpT0 = t22
  1343. rVbn = in0
  1344. rSectorCount = in1
  1345. rBuffer = in2
  1346. rSectorsPerCluster = loc2
  1347. rBytesPerCluster = loc3
  1348. // Reserve the stack scratch area
  1349. add sp = -STACK_SCRATCH_AREA, sp
  1350. movl rpT0 = BytesPerCluster
  1351. ld4 rBytesPerCluster = [rpT0]
  1352. RMS$Again:
  1353. // Divide the VBN by SectorsPerCluster to get the VCN
  1354. mov out0 = in0
  1355. movl rpT0 = SectorsPerCluster
  1356. ld1 rSectorsPerCluster = [rpT0]
  1357. mov out1 = rSectorsPerCluster
  1358. movl out2 = Result
  1359. movl out3 = Remainder
  1360. mov ap = sp
  1361. br.call.sptk.many brp = Divide
  1362. movl rpT0 = Result
  1363. ld4 out0 = [rpT0]
  1364. mov ap = sp
  1365. br.call.sptk.many brp = ComputeMftLcn
  1366. cmp.eq pt0, pt1 = zero, v0 // LCN equal to zero?
  1367. (pt0) br.cond.sptk.clr BootErr$he // zero is not a possible LCN
  1368. // Change the LCN back into a LBN and add the remainder back in to get
  1369. // the sector we want to read, which goes into SectorBase.
  1370. //
  1371. mov out0 = v0
  1372. mov out1 = rSectorsPerCluster
  1373. mov ap = sp
  1374. br.call.sptk.many brp = Multiply // v0 = cluster first LBN
  1375. movl rpT0 = Remainder
  1376. ld4 t0 = [rpT0]
  1377. add t1 = v0, t0 // t1 = desired LBN
  1378. movl rpT0 = SectorBase
  1379. st4 [rpT0] = t1
  1380. //
  1381. // Figure out how many sectors to read this time// we never attempt
  1382. // to read more than one cluster at a time.
  1383. //
  1384. cmp.le pt0, pt1 = rSectorCount,rSectorsPerCluster
  1385. (pt0) br.cond.sptk.clr RMS10
  1386. //
  1387. // Read only a single cluster at a time, to avoid problems with fragmented
  1388. // runs in the mft.
  1389. //
  1390. movl rpT0 = SectorCount
  1391. st2 [rpT0] = rSectorsPerCluster // this time read 1 cluster
  1392. sub rSectorCount = rSectorCount, rSectorsPerCluster // sect. remain
  1393. add rVbn = rVbn, rSectorsPerCluster // VBN += sectors this read
  1394. br.cond.sptk.clr RMS20
  1395. RMS10:
  1396. add rVbn = rVbn, rSectorCount // VBN += sectors this read
  1397. movl rpT0 = SectorCount
  1398. st2 [rpT0] = rSectorCount
  1399. mov rSectorCount = zero // remaining sector count (0)
  1400. RMS20:
  1401. // The target buffer was passed in es:edi, but we want it in es:bx.
  1402. // Do the conversion.
  1403. //
  1404. movl rpT0 = SectorBase
  1405. ld4 out0 = [rpT0]
  1406. movl rpT0 = SectorCount
  1407. ld2 out1 = [rpT0]
  1408. mov out2 = rBuffer
  1409. mov ap = sp
  1410. br.call.sptk.many brp = ReadSectors
  1411. add rBuffer = rBuffer, rBytesPerCluster
  1412. cmp.gt pt0, pt1 = rSectorCount, zero // are we done?
  1413. (pt0) br.cond.sptk.clr RMS$Again // repeat until desired == 0
  1414. add sp = STACK_SCRATCH_AREA, sp // Reclaim the scratch area
  1415. NESTED_RETURN
  1416. NESTED_EXIT(ReadMftSectors)
  1417. //****************************************************************************
  1418. //
  1419. // ReadFrs - Read an FRS
  1420. //
  1421. // ENTRY: in0 == FRS number
  1422. // in1 == Target buffer
  1423. //
  1424. // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
  1425. //
  1426. NESTED_ENTRY(ReadFrs)
  1427. NESTED_SETUP(3,3,8,0)
  1428. PROLOGUE_END
  1429. rpT0 = t22
  1430. rSectorsPerFrs = loc2
  1431. //
  1432. // Adjust sp with sratch area
  1433. //
  1434. add sp = -STACK_SCRATCH_AREA, sp
  1435. movl rpT0 = SectorsPerFrs
  1436. ld4 rSectorsPerFrs = [rpT0]
  1437. mov out0 = in0 // FRS number
  1438. mov out1 = rSectorsPerFrs // Sectors per FRS
  1439. mov ap = sp
  1440. br.call.sptk.many brp = Multiply
  1441. mov out0 = v0 // out0 = starting VBN
  1442. mov out1 = rSectorsPerFrs // out1 = number of sectors to read
  1443. mov out2 = in1 // out2 = target buffer
  1444. mov ap = sp
  1445. br.call.sptk.many brp = ReadMftSectors
  1446. mov out0 = in1 // out2 = target buffer
  1447. mov ap = sp
  1448. br.call.sptk.many brp = MultiSectorFixup
  1449. add sp = STACK_SCRATCH_AREA, sp // Readjust sp before exiting
  1450. NESTED_RETURN
  1451. NESTED_EXIT(ReadFrs)
  1452. //****************************************************************************
  1453. //
  1454. // ReadIndexBlock - read an index block from the root index.
  1455. //
  1456. // ENTRY: in0 == Block number
  1457. //
  1458. // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
  1459. //
  1460. NESTED_ENTRY(ReadIndexBlock)
  1461. NESTED_SETUP(3,3,8,0)
  1462. rpT0 = t22
  1463. rpT1 = t21
  1464. rpT2 = t20
  1465. rBlock = in0
  1466. rBuffer = loc2
  1467. //
  1468. // Setup stack scratch area
  1469. //
  1470. add sp = -STACK_SCRATCH_AREA, sp
  1471. mov out0 = rBlock
  1472. movl rpT0 = SectorsPerIndexBlock
  1473. ld4 out1 = [rpT0]
  1474. mov ap = sp
  1475. br.call.sptk.many brp = Multiply
  1476. mov out0 = v0 // v0 = first VBN to read
  1477. movl rpT0 = IndexAllocation
  1478. ld4 out1 = [rpT0] // out1 -> $INDEX_ALLOCATION attribute
  1479. movl rpT1 = SectorsPerIndexBlock // out2 == Sectors to read
  1480. ld4 out2 = [rpT1]
  1481. movl rpT2 = IndexBlockBuffer // out3 -> index block buffer
  1482. ld4 rBuffer = [rpT2]
  1483. mov out3 = rBuffer
  1484. mov ap = sp
  1485. br.call.sptk.many brp = ReadIndexBlockSectors
  1486. mov out0 = rBuffer
  1487. mov ap = sp
  1488. br.call.sptk.many brp = MultiSectorFixup
  1489. add sp = STACK_SCRATCH_AREA, sp // Readjust sp before exiting
  1490. NESTED_RETURN
  1491. NESTED_EXIT(ReadIndexBlock)
  1492. //****************************************************************************
  1493. //
  1494. // IsBlockInUse - Checks the index bitmap to see if an index
  1495. // allocation block is in use.
  1496. //
  1497. // ENTRY: in0 == block number
  1498. //
  1499. // EXIT: Carry flag clear if block is in use
  1500. // Carry flag set if block is not in use.
  1501. //
  1502. NESTED_ENTRY(IsBlockInUse)
  1503. NESTED_SETUP(3,5,8,0)
  1504. PROLOGUE_END
  1505. rpT0 = t22
  1506. rBlock = in0
  1507. rTest = loc2
  1508. rByte = loc3
  1509. rBit = loc4
  1510. //
  1511. // Reserve stack scratch area
  1512. //
  1513. add sp = -STACK_SCRATCH_AREA, sp
  1514. movl rpT0 = IndexBitmapBuffer
  1515. ld4 rTest = [rpT0]
  1516. mov t0 = rBlock // t0 = block number
  1517. shr rByte = t0, 3 // rByte = byte number
  1518. and rBit = 7, rBlock // rBit = bit number in byte
  1519. add rTest = rTest, rByte // rTest = byte to test
  1520. movl t0 = 1
  1521. shl t0 = t0, rBit // t0 = mask
  1522. ld1 t1 = [rTest]
  1523. and t2 = t1, t0
  1524. cmp.eq pt0, pt1 = t2, zero
  1525. (pt0) br.cond.sptk.clr IBU10
  1526. mov v0 = zero // Block is not in use.
  1527. br.cond.sptk.clr IBU20
  1528. IBU10: movl v0 = 1 // Block is in use.
  1529. IBU20: add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  1530. NESTED_RETURN
  1531. NESTED_EXIT(IsBlockInUse)
  1532. //****************************************************************************
  1533. //
  1534. // ComputeLcn - Converts a VCN into an LCN
  1535. //
  1536. // ENTRY: in0 -> VCN
  1537. // in1 -> Attribute
  1538. //
  1539. // EXIT: t0 -> LCN (zero indicates not found)
  1540. // t1 -> Remaining run length
  1541. //
  1542. // USES: ALL.
  1543. //
  1544. NESTED_ENTRY(ComputeLcn)
  1545. NESTED_SETUP(3,7,8,0)
  1546. PROLOGUE_END
  1547. rpT0 = t22
  1548. rVcn = in0 // VCN
  1549. rAttribute = in1 // Attribute
  1550. rpMappingPair = loc2
  1551. rDeltaVcn = loc3
  1552. rCurrentVcn = loc4
  1553. rCurrentLcn = loc5
  1554. rNextVcn = loc6
  1555. //
  1556. // Setup stack scratch area
  1557. //
  1558. add sp = -STACK_SCRATCH_AREA, sp
  1559. add rpT0 = ATTR_FormCode, rAttribute
  1560. ld1 t0 = [rpT0]
  1561. cmp.eq pt0, pt1 = NONRESIDENT_FORM, t0
  1562. (pt1) br.cond.sptk.clr clcn99 // This is a resident attribute.
  1563. clcn10:
  1564. //
  1565. // See if the desired VCN is in range.
  1566. //
  1567. add rpT0 = NONRES_HighestVcn+LowPart, rAttribute
  1568. ld4 t0 = [rpT0] // t0 = HighestVcn
  1569. cmp.gt pt0, pt1 = rVcn, t0
  1570. (pt0) br.cond.sptk.clr clcn99 // VCN is greater than HighestVcn
  1571. add rpT0 = NONRES_LowestVcn+LowPart, rAttribute
  1572. ld4 rCurrentVcn = [rpT0] // rCurrentVcn = LowestVcn
  1573. cmp.lt pt0, pt1 = rVcn, rCurrentVcn
  1574. (pt0) br.cond.sptk.clr clcn99 // VCN is less than LowestVcn
  1575. clcn20:
  1576. add rpT0 = NONRES_MappingPairOffset, rAttribute
  1577. ld2 t0 = [rpT0]
  1578. add rpMappingPair = rAttribute, t0
  1579. ld1 t0 = [rpMappingPair]
  1580. mov rCurrentLcn = zero // Initialize Current LCN
  1581. clcn30:
  1582. cmp.eq pt0, pt1 = zero, t0 // if count byte is zero...
  1583. (pt0) br.cond.sptk.clr clcn99 // ... we're done (and didn't find it)
  1584. // Update CurrentLcn
  1585. //
  1586. mov out0 = rpMappingPair
  1587. mov ap = sp
  1588. br.call.sptk.many brp = LcnFromMappingPair
  1589. add rCurrentLcn = rCurrentLcn, v0
  1590. mov out0 = rpMappingPair
  1591. mov ap = sp
  1592. br.call.sptk.many brp = VcnFromMappingPair // out0 = previous out0
  1593. mov rDeltaVcn = v0
  1594. // rVcn == VCN to find
  1595. // rpMappingPair -> Current mapping pair count byte
  1596. // rDeltaVcn == DeltaVcn for current mapping pair
  1597. // rCurrentVcn == Current VCN
  1598. // rCurrentLcn == Current LCN
  1599. //
  1600. add rNextVcn = rDeltaVcn, rCurrentVcn // NextVcn
  1601. cmp.lt pt0, pt1 = rVcn, rNextVcn // If target < NextVcn ...
  1602. (pt0) br.cond.sptk.clr clcn80 // ... we found the right mapping pair.
  1603. // Go on to next mapping pair.
  1604. //
  1605. mov rCurrentVcn = rNextVcn // CurrentVcn = NextVcn
  1606. ld1 t0 = [rpMappingPair] // t0 = count byte
  1607. mov t1 = t0 // t1 = count byte
  1608. and t1 = 0x0f, t1 // t1 = number of vcn bytes
  1609. shr t0 = t0, 4 // t0 = number of lcn bytes
  1610. add rpMappingPair = rpMappingPair, t0
  1611. add rpMappingPair = rpMappingPair, t1
  1612. add rpMappingPair = 1, rpMappingPair // -> next count byte
  1613. br.cond.sptk.clr clcn30
  1614. clcn80:
  1615. // We found the mapping pair we want.
  1616. //
  1617. // rVcn == target VCN
  1618. // rMappingPair -> mapping pair count byte
  1619. // rCurrentVcn == Starting VCN of run
  1620. // rNextVcn == Next VCN (ie. start of next run)
  1621. // rCurrentLcn == starting LCN of run
  1622. //
  1623. sub t1 = rNextVcn, rVcn // t1 = remaining run length
  1624. sub t0 = rVcn, rCurrentVcn // t0 = offset into run
  1625. add t0 = t0, rCurrentLcn // t0 = LCN to return
  1626. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  1627. NESTED_RETURN
  1628. // The target VCN is not in this attribute.
  1629. clcn99: mov v0 = zero // Not found.
  1630. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  1631. NESTED_RETURN
  1632. NESTED_EXIT(ComputeLcn)
  1633. //****************************************************************************
  1634. //
  1635. // VcnFromMappingPair
  1636. //
  1637. // ENTRY: in0 -> Mapping Pair count byte
  1638. //
  1639. // EXIT: v0 == DeltaVcn from mapping pair
  1640. //
  1641. //
  1642. LEAF_ENTRY(VcnFromMappingPair)
  1643. LEAF_SETUP(3,4,8,0)
  1644. PROLOGUE_END
  1645. rpMP = in0
  1646. rv = loc2
  1647. rVcn = loc3
  1648. ld1 rv = [rpMP] // rv = count byte
  1649. and rv = 0x0f, rv // rv = v
  1650. cmp.eq pt0, pt1 = zero, rv // if rv is zero, volume is corrupt.
  1651. (pt1) br.cond.sptk.clr VFMP5
  1652. mov v0 = zero
  1653. br.cond.sptk.clr VFMP99
  1654. VFMP5:
  1655. add rpMP = rpMP, rv // rpMP -> last byte of compressed vcn
  1656. ld1 rVcn = [rpMP]
  1657. sxt1 rVcn = rVcn
  1658. add rv = -1, rv
  1659. add rpMP = -1, rpMP
  1660. // rpMP -> Next byte to add in
  1661. // rv == Number of bytes remaining
  1662. // rVcn == Accumulated value
  1663. //
  1664. VFMP10: cmp.eq pt0, pt1 = zero, rv // When rv == 0, we're done.
  1665. (pt0) br.cond.sptk.clr VFMP20
  1666. shl rVcn = rVcn, 8
  1667. ld1 t0 = [rpMP]
  1668. or rVcn = rVcn, t0
  1669. add rpMP = -1, rpMP // Back up through bytes to process.
  1670. add rv = -1, rv // One less byte to process.
  1671. br.cond.sptk.clr VFMP10
  1672. VFMP20:
  1673. // rVcn == Accumulated value to return
  1674. movl t0 = 0xffffffff // return the lower 32-bits
  1675. and v0 = rVcn, t0
  1676. VFMP99:
  1677. LEAF_RETURN
  1678. LEAF_EXIT(VcnFromMappingPair)
  1679. //****************************************************************************
  1680. //
  1681. // LcnFromMappingPair
  1682. //
  1683. // ENTRY: in0 -> Mapping Pair count byte
  1684. //
  1685. // EXIT: v0 == DeltaLcn from mapping pair
  1686. //
  1687. LEAF_ENTRY(LcnFromMappingPair)
  1688. LEAF_SETUP(3,5,8,0)
  1689. PROLOGUE_END
  1690. rpMP = in0
  1691. rv = loc2
  1692. rl = loc3
  1693. rLcn = loc4
  1694. ld1 rv = [rpMP]
  1695. and rv = 0xf, rv // rv = v
  1696. ld1 rl = [rpMP]
  1697. shr rl = rl, 4 // rl = l
  1698. cmp.eq pt0, pt1 = zero, rl // if rl is zero, volume is corrupt.
  1699. (pt1) br.cond.sptk.clr LFMP5
  1700. mov v0 = zero
  1701. br.cond.sptk.clr LFMP99
  1702. LFMP5:
  1703. // rpMP -> count byte
  1704. // rl == l
  1705. // rv == v
  1706. //
  1707. add rpMP = rpMP, rv // rpMP -> last byte of compressed vcn
  1708. add rpMP = rpMP, rl // rpMP -> last byte of compressed lcn
  1709. ld1 rLcn = [rpMP]
  1710. sxt1 rLcn = rLcn
  1711. add rl = -1, rl
  1712. add rpMP = -1, rpMP
  1713. // rpMP -> Next byte to add in
  1714. // rl == Number of bytes remaining
  1715. // rLcn == Accumulated value
  1716. //
  1717. LFMP10: cmp.eq pt0, pt1 = zero, rl // When rl == 0, we're done.
  1718. (pt0) br.cond.sptk.clr LFMP20
  1719. shl rLcn = rLcn, 8
  1720. ld1 t0 = [rpMP]
  1721. or rLcn = rLcn, t0
  1722. add rpMP = -1, rpMP // Back up through bytes to process.
  1723. add rl = -1, rl // One less byte to process.
  1724. br.cond.sptk.clr LFMP10
  1725. LFMP20:
  1726. // rLcn == Accumulated value to return
  1727. movl t0 = 0xffffffff // return the lower 32-bits
  1728. and v0 = rLcn, t0
  1729. LFMP99:
  1730. LEAF_RETURN
  1731. LEAF_EXIT(LcnFromMappingPair)
  1732. //***************************************************************************
  1733. //
  1734. // UpcaseName - Converts the name of the file to all upper-case
  1735. //
  1736. // ENTRY: in0 -> Name
  1737. // in1 -> Length of name
  1738. //
  1739. // USES: none
  1740. //
  1741. LEAF_ENTRY(UpcaseName)
  1742. LEAF_SETUP(2,3,0,0)
  1743. PROLOGUE_END
  1744. rpName = in0
  1745. rLength = in1
  1746. cmp.eq pt0, pt1 = zero, rLength
  1747. (pt0) br.cond.sptk.clr UN30
  1748. UN10:
  1749. ld2 t0 = [rpName]
  1750. cmp.gt pt0, pt1 = 'a', t0 // if it's less than 'a'
  1751. (pt0) br.cond.sptk.clr UN20 // leave it alone
  1752. cmp.lt pt0, pt1 = 'z', t0 // if it's greater than 'z'
  1753. (pt0) br.cond.sptk.clr UN20 // leave it alone.
  1754. movl t1 = 'a' - 'A' // the letter is lower-case--convert it.
  1755. sub t0 = t0, t1
  1756. UN20:
  1757. add rpName = 2, rpName // move on to next unicode character
  1758. add rLength = -1, rLength
  1759. cmp.eq pt0, pt1 = zero, rLength
  1760. (pt0) br.cond.sptk.clr UN10
  1761. UN30:
  1762. LEAF_RETURN
  1763. LEAF_EXIT(UpcaseName)
  1764. //****************************************************************************
  1765. //
  1766. // FindFile - Locates the index entry for a file in the root index.
  1767. //
  1768. // ENTRY: in0 -> name to find
  1769. // in1 == length of file name in characters
  1770. //
  1771. // EXIT: v0 -> Index Entry. NULL to indicate failure.
  1772. //
  1773. // USES: ALL
  1774. //
  1775. NESTED_ENTRY(FindFile)
  1776. NESTED_SETUP(3,4,8,0)
  1777. PROLOGUE_END
  1778. rpT0 = t22
  1779. rpT1 = t21
  1780. rpName = in0
  1781. rLength = in1
  1782. rIndexAllocation = loc2
  1783. rBlock = loc3
  1784. //
  1785. // Setup stack scratch area
  1786. //
  1787. add sp = -STACK_SCRATCH_AREA, sp
  1788. // First, search the index root.
  1789. //
  1790. // rpName -> name to find
  1791. // rLength == name length
  1792. //
  1793. movl rpT0 = IndexRoot
  1794. ld4 t0 = [rpT0]
  1795. add rpT1 = RES_ValueOffset, t0
  1796. ld2 t1 = [rpT1]
  1797. add t2 = t0, t1
  1798. add out0 = IR_IndexHeader, t2
  1799. mov out1 = rpName
  1800. mov out2 = rLength
  1801. mov ap = sp
  1802. br.call.sptk.many brp = LocateIndexEntry
  1803. cmp.eq pt0, pt1 = v0, zero
  1804. (pt0) br.cond.sptk.clr FindFile20
  1805. // Found it in the root! The result is already in eax.
  1806. // Clean up the stack and return.
  1807. //
  1808. add sp = STACK_SCRATCH_AREA, sp
  1809. NESTED_RETURN
  1810. FindFile20:
  1811. //
  1812. // We didn't find the index entry we want in the root, so we have to
  1813. // crawl through the index allocation buffers.
  1814. //
  1815. movl rpT0 = IndexAllocation
  1816. ld4 rIndexAllocation = [rpT0]
  1817. cmp.eq pt0, pt1 = t0, zero
  1818. (pt1) br.cond.sptk.clr FindFile30
  1819. // There is no index allocation attribute; clean up
  1820. // the stack and return failure.
  1821. //
  1822. mov v0 = zero
  1823. add sp = STACK_SCRATCH_AREA, sp
  1824. NESTED_RETURN
  1825. FindFile30:
  1826. //
  1827. // Search the index allocation blocks for the name we want.
  1828. // Instead of searching in tree order, we'll just start with
  1829. // the last one and work our way backwards.
  1830. //
  1831. add rpT1 = NONRES_HighestVcn+LowPart, rIndexAllocation
  1832. ld4 t1 = [rpT1] // t1 = HighestVcn
  1833. add out0 = 1, t1 // out0 = clusters in attribute
  1834. movl rpT2 = BytesPerCluster
  1835. ld4 out1 = [rpT2]
  1836. mov ap = sp
  1837. br.call.sptk.many brp = Multiply // v0 = bytes in attribute
  1838. mov out0 = v0
  1839. movl rpT0 = BytesPerIndexBlock
  1840. ld4 out1 = [rpT0]
  1841. movl out2 = Result
  1842. movl out3 = Remainder
  1843. mov ap = sp
  1844. br.call.sptk.many brp = Divide // convert bytes to index blocks
  1845. movl rpT0 = Result
  1846. ld4 rBlock = [rpT0] // number of blocks to process
  1847. FindFile40:
  1848. cmp.eq pt0, pt1 = rBlock, zero
  1849. (pt0) br.cond.sptk.clr FindFile90
  1850. add rBlock = -1, rBlock // rBlock == number of next block to process
  1851. //
  1852. // See if the block is in use; if not, go on to next.
  1853. //
  1854. mov out0 = rBlock
  1855. mov ap = sp
  1856. br.call.sptk.many brp = IsBlockInUse
  1857. cmp.eq pt0, pt1 = v0, zero
  1858. (pt1) br.cond.sptk.clr FindFile40 // v0 == zero if not in use
  1859. // rBlock == block number to process
  1860. // rLength == name length
  1861. // rpName -> name to find
  1862. //
  1863. mov out0 = rBlock
  1864. mov ap = sp
  1865. br.call.sptk.many brp = ReadIndexBlock
  1866. // rpName -> name to find
  1867. // rLength == name length in characters
  1868. //
  1869. // Index buffer to search is in index allocation block buffer.
  1870. //
  1871. movl rpT0 = IndexBlockBuffer // t0 -> Index allocation block
  1872. ld4 t0 = [rpT0]
  1873. add out0 = IB_IndexHeader, t0 // out0 -> Index Header
  1874. mov out1 = rpName
  1875. mov out2 = rLength
  1876. mov ap = sp
  1877. br.call.sptk.many brp = LocateIndexEntry // v0 -> found entry
  1878. cmp.eq pt0, pt1 = v0, zero
  1879. (pt0) br.cond.sptk.clr FindFile40
  1880. // Found it!
  1881. //
  1882. // v0 -> Found entry
  1883. //
  1884. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  1885. NESTED_RETURN
  1886. FindFile90:
  1887. //
  1888. // Name not found.
  1889. //
  1890. mov v0 = zero // zero out v0.
  1891. add sp = STACK_SCRATCH_AREA, sp // restore the original sp
  1892. NESTED_RETURN
  1893. NESTED_EXIT(FindFile)
  1894. #ifdef DEBUG
  1895. #ifdef NOT_YET_PORTED
  1896. ;****************************************************************************
  1897. ;
  1898. ; DumpIndexBlock - dumps the index block buffer
  1899. ;
  1900. DumpIndexBlock proc near
  1901. SAVE_ALL
  1902. mov esi, IndexBlockBuffer
  1903. mov ecx, 20h ; dwords to dump
  1904. DIB10:
  1905. test ecx, 3
  1906. jnz DIB20
  1907. call DebugNewLine
  1908. DIB20:
  1909. lodsd
  1910. call PrintNumber
  1911. loop DIB10
  1912. RESTORE_ALL
  1913. ret
  1914. DumpIndexBlock endp
  1915. ;****************************************************************************
  1916. ;
  1917. ; DebugNewLine
  1918. ;
  1919. DebugNewLine proc near
  1920. SAVE_ALL
  1921. xor eax, eax
  1922. xor ebx, ebx
  1923. mov al, 0dh
  1924. mov ah, 14
  1925. mov bx, 7
  1926. int 10h
  1927. mov al, 0ah
  1928. mov ah, 14
  1929. mov bx, 7
  1930. int 10h
  1931. RESTORE_ALL
  1932. ret
  1933. DebugNewLine endp
  1934. ;****************************************************************************
  1935. ;
  1936. ; DebugPrint - Display a debug string.
  1937. ;
  1938. ; ENTRY: DS:SI -> null-terminated string
  1939. ;
  1940. ; USES: None.
  1941. ;
  1942. .286
  1943. DebugPrint proc near
  1944. pusha
  1945. DbgPr20:
  1946. lodsb
  1947. cmp al, 0
  1948. je DbgPr30
  1949. mov ah, 14 ; write teletype
  1950. mov bx, 7 ; attribute
  1951. int 10h ; print it
  1952. jmp DbgPr20
  1953. DbgPr30:
  1954. popa
  1955. nop
  1956. ret
  1957. DebugPrint endp
  1958. ;****************************************************************************
  1959. ;
  1960. ;
  1961. ; PrintNumber
  1962. ;
  1963. ; ENTRY: EAX == number to print
  1964. ;
  1965. ; PRESERVES ALL REGISTERS
  1966. ;
  1967. .386
  1968. PrintNumber proc near
  1969. SAVE_ALL
  1970. mov ecx, 8 ; number of digits in a DWORD
  1971. PrintNumber10:
  1972. mov edx, eax
  1973. and edx, 0fh ; edx = lowest-order digit
  1974. push edx ; put it on the stack
  1975. shr eax, 4 ; drop low-order digit
  1976. loop PrintNumber10
  1977. mov ecx, 8 ; number of digits on stack.
  1978. PrintNumber20:
  1979. pop eax ; eax = next digit to print
  1980. cmp eax, 9
  1981. jg PrintNumber22
  1982. add eax, '0'
  1983. jmp PrintNumber25
  1984. PrintNumber22:
  1985. sub eax, 10
  1986. add eax, 'A'
  1987. PrintNumber25:
  1988. xor ebx, ebx
  1989. mov ah, 14
  1990. mov bx, 7
  1991. int 10h
  1992. loop PrintNumber20
  1993. ; Print a space to separate numbers
  1994. mov al, ' '
  1995. mov ah, 14
  1996. mov bx, 7
  1997. int 10h
  1998. RESTORE_ALL
  1999. call Pause
  2000. ret
  2001. PrintNumber endp
  2002. #endif NOT_YET_PORTED
  2003. //****************************************************************************
  2004. //
  2005. // Debug0 - Print debug string 0 -- used for checkpoints in mainboot
  2006. //
  2007. NESTED_ENTRY(Debug0)
  2008. NESTED_SETUP(3,3,8,0)
  2009. PROLOGUE_END
  2010. add sp = STACK_SCRATCH_AREA, sp
  2011. movl out0 = DbgString0
  2012. mov ap = sp
  2013. br.call.sptk.many brp = BootErr$Print
  2014. add sp = -STACK_SCRATCH_AREA, sp
  2015. NESTED_RETURN
  2016. NESTED_EXIT(Debug0)
  2017. //****************************************************************************
  2018. //
  2019. // Debug1 - Print debug string 1 --
  2020. //
  2021. NESTED_ENTRY(Debug1)
  2022. NESTED_SETUP(3,3,8,0)
  2023. add sp = STACK_SCRATCH_AREA, sp
  2024. movl out0 = DbgString1
  2025. mov ap = sp
  2026. br.call.sptk.many brp = BootErr$Print
  2027. add sp = -STACK_SCRATCH_AREA, sp
  2028. NESTED_RETURN
  2029. NESTED_EXIT(Debug1)
  2030. //****************************************************************************
  2031. //
  2032. // Debug2 - Print debug string 2
  2033. //
  2034. NESTED_ENTRY(Debug2)
  2035. NESTED_SETUP(3,3,8,0)
  2036. add sp = -STACK_SCRATCH_AREA, sp
  2037. movl out0 = DbgString2
  2038. mov ap = sp
  2039. br.call.sptk.many brp = BootErr$Print
  2040. add sp = STACK_SCRATCH_AREA, sp
  2041. NESTED_RETURN
  2042. NESTED_EXIT(Debug2)
  2043. //****************************************************************************
  2044. //
  2045. // Debug3 - Print debug string 3 --
  2046. //
  2047. NESTED_ENTRY(Debug3)
  2048. NESTED_SETUP(3,3,8,0)
  2049. PROLOGUE_END
  2050. add sp = -STACK_SCRATCH_AREA, sp
  2051. movl out0 = DbgString3
  2052. mov ap = sp
  2053. br.call.sptk.many brp = BootErr$Print
  2054. add sp = STACK_SCRATCH_AREA, sp
  2055. NESTED_RETURN
  2056. NESTED_EXIT(Debug3)
  2057. //****************************************************************************
  2058. //
  2059. // Debug4 - Print debug string 4
  2060. //
  2061. NESTED_ENTRY(Debug4)
  2062. NESTED_SETUP(3,3,8,0)
  2063. PROLOGUE_END
  2064. add sp = -STACK_SCRATCH_AREA, sp
  2065. movl out0 = DbgString4
  2066. mov ap = sp
  2067. br.call.sptk.many brp = BootErr$Print
  2068. add sp = STACK_SCRATCH_AREA, sp
  2069. NESTED_RETURN
  2070. NESTED_EXIT(Debug4)
  2071. #ifdef NOT_YET_PORTED
  2072. ;****************************************************************************
  2073. ;
  2074. ; Pause - Pause for about 1/2 a second. Simply count until you overlap
  2075. ; to zero.
  2076. ;
  2077. Pause proc near
  2078. push eax
  2079. mov eax, 0fff10000h
  2080. PauseLoopy:
  2081. inc eax
  2082. or eax, eax
  2083. jnz PauseLoopy
  2084. pop eax
  2085. ret
  2086. Pause endp
  2087. #endif NOT_YET_PORTED
  2088. #endif DEBUG
  2089. //*************************************************************************
  2090. //
  2091. // LoadIndexFrs - For the requested index type code locate and
  2092. // load the associated Frs.
  2093. //
  2094. // ENTRY: in0 - requested index type code
  2095. // in1 - Points to empty Frs buffer
  2096. //
  2097. // EXIT: v0 - points to offset in Frs buffer of requested index type
  2098. // code or Zero if not found.
  2099. // USES: All
  2100. //
  2101. NESTED_ENTRY(LoadIndexFrs)
  2102. NESTED_SETUP(3,3,8,0)
  2103. PROLOGUE_END
  2104. rTypeCode = in0 // index type code
  2105. rpFrs = in1 // pointer to FRS
  2106. //
  2107. // setup stack scratch area
  2108. //
  2109. add sp = -STACK_SCRATCH_AREA, sp
  2110. movl out0 = ROOT_FILE_NAME_INDEX_NUMBER
  2111. mov out1 = rpFrs
  2112. mov ap = sp
  2113. br.call.sptk.many brp = ReadFrs
  2114. mov out0 = rpFrs // FRS to search
  2115. mov out1 = rTypeCode // index type code
  2116. movl out3 = index_name // Attribute name
  2117. movl rpT0 = index_name_length // Attribute name length
  2118. ld2 out2 = [rpT0]
  2119. mov ap = sp
  2120. br.call.sptk.many brp = LocateAttributeRecord
  2121. cmp.eq pt0, pt1 = v0, zero
  2122. (pt1) br.cond.sptk.clr LoadIndexFrs$Exit // if found in root return
  2123. //
  2124. // if not found in current Frs, search in attribute list
  2125. //
  2126. mov out0 = rTypeCode // type code
  2127. mov out1 = rpFrs // FRS to search
  2128. mov ap = sp
  2129. br.call.sptk.many brp = SearchAttrList // search attribute list for FRN
  2130. // of specified ($INDEX_ROOT,
  2131. // $INDEX_ALLOCATION, or $BITMAP)
  2132. // v0 - holds FRN for Frs, or Zero
  2133. cmp.eq pt0, pt1 = v0, zero // if we cann't find it in attribute
  2134. (pt0) br.cond.sptk.clr LoadIndexFrs$Exit // list then we are hosed
  2135. // We should now have the File Record Number where the index for the
  2136. // specified type code we are searching for is, load this into the
  2137. // Frs target buffer.
  2138. //
  2139. // EAX - holds FRN
  2140. // EBX - holds type code
  2141. // EDI - holds target buffer
  2142. mov out0 = v0
  2143. mov out1 = rTypeCode
  2144. mov out2 = rpFrs
  2145. mov ap = sp
  2146. br.call.sptk.many brp = ReadFrs
  2147. //
  2148. // Now determine the offset in the Frs of the index
  2149. //
  2150. mov out0 = rpFrs // Frs to search
  2151. mov out1 = rTypeCode // FRS Type Code
  2152. movl rpT0 = index_name_length
  2153. ld4 out2 = [rpT0] // Attribute name length
  2154. movl out3 = index_name
  2155. mov ap = sp
  2156. br.call.sptk.many brp = LocateAttributeRecord
  2157. // v0 - holds offset or Zero.
  2158. LoadIndexFrs$Exit:
  2159. add sp = STACK_SCRATCH_AREA, sp // restore original sp
  2160. NESTED_RETURN
  2161. NESTED_EXIT(LoadIndexFrs)
  2162. //****************************************************************************
  2163. //
  2164. // SearchAttrList
  2165. //
  2166. // Search the Frs for the attribute list. Then search the attribute list
  2167. // for the specifed type code. When you find it return the FRN in the
  2168. // attribute list entry found or Zero if no match found.
  2169. //
  2170. // ENTRY: in0 - type code to search attrib list for
  2171. // in1 - Frs buffer holding head of attribute list
  2172. // EXIT: v0 - FRN file record number to load, Zero if none.
  2173. //
  2174. // USES: All
  2175. //
  2176. NESTED_ENTRY(SearchAttrList)
  2177. NESTED_SETUP(2,4,8,0)
  2178. PROLOGUE_END
  2179. rTypeCode = in0
  2180. rFrs = in1
  2181. rAttrList = loc2
  2182. //
  2183. // Setup stack scratch area
  2184. //
  2185. add sp = -STACK_SCRATCH_AREA, sp
  2186. mov out0 = rFrs
  2187. mov out1 = $ATTRIBUTE_LIST // Attribute type code
  2188. mov out2 = 0 // Attribute name length
  2189. mov out3 = 0 // Attribute name
  2190. mov ap = sp
  2191. br.call.sptk.many brp = LocateAttributeRecord
  2192. cmp.eq pt0, pt1 = v0, zero // If there's no Attribute list,
  2193. (pt0) br.cond.sptk.clr SearchAttrList$NotFoundIndex1 // We are done
  2194. // Read the attribute list.
  2195. // eax -> attribute list attribute
  2196. mov out0 = v0 // out0 -> attribute list attribute
  2197. movl out1 = AttrList // out1 -> attribute list buffer
  2198. mov ap = sp
  2199. br.call.sptk.many brp = ReadWholeAttribute
  2200. movl rpT0 = AttrList
  2201. ld4 rAttrList = [rpT0] // rAttrList -> first attribute list entry
  2202. // Now, traverse the attribute list looking for the entry for
  2203. // the Index type code.
  2204. //
  2205. // rAttrList -> first attribute list entry
  2206. //
  2207. SearchAttrList$LookingForIndex:
  2208. #ifdef DEBUG
  2209. add rpT0 = ATTRLIST_AttributeTypeCode, rAttrList
  2210. ld4 out0 = [rpT0]
  2211. mov ap = sp
  2212. br.call.sptk.many brp = PrintNumber
  2213. add rpT0 = ATTRLIST_RecordLength, rAttrList
  2214. ld4 out0 = [rpT0]
  2215. mov ap = sp
  2216. br.call.sptk.many brp = PrintNumber
  2217. mov out0 = rAttrList
  2218. mov ap = sp
  2219. br.call.sptk.many brp = PrintNumber
  2220. add out0 = ATTRLIST_Name, rAttrList
  2221. mov ap = sp
  2222. br.call.sptk.many brp = PrintName
  2223. #endif
  2224. add rpT0 = ATTRLIST_AttributeTypeCode, rpT0
  2225. ld4 t0 = [rpT0]
  2226. cmp.eq pt0, pt1 = rTypeCode, t0
  2227. (pt0) br.cond.sptk.clr SearchAttrList$FoundIndex
  2228. movl t1 = $END
  2229. cmp.eq pt0, pt1 = t0, t1 // reached invalid attribute
  2230. (pt0) br.cond.sptk.clr SearchAttrList$NotFoundIndex2 // so must be at end
  2231. add rpT0 = ATTRLIST_RecordLength, rpT0
  2232. ld4 t0 = [rpT0]
  2233. cmp.eq pt0, pt1 = 0, t0
  2234. (pt0) br.cond.sptk.clr SearchAttrList$NotFoundIndex2 //reached end of list and
  2235. // nothing found
  2236. add rAttrList = rAttrList, t0 // Next attribute
  2237. br.cond.sptk.clr SearchAttrList$LookingForIndex
  2238. SearchAttrList$FoundIndex:
  2239. // found the index, return the FRN
  2240. add rpT0 = ATTRLIST_SegmentReference, rAttrList
  2241. add rpT0 = REF_SegmentNumberLowPart, rAttrList
  2242. ld4 v0 = [rpT0]
  2243. NESTED_RETURN
  2244. SearchAttrList$NotFoundIndex1:
  2245. // pop ecx
  2246. SearchAttrList$NotFoundIndex2:
  2247. mov v0 = zero
  2248. add sp = -STACK_SCRATCH_AREA, sp // restore original sp
  2249. NESTED_RETURN
  2250. NESTED_EXIT(SearchAttrList)
  2251. //
  2252. // Boot message printing, relocated from sector 0 to sace space
  2253. //
  2254. BootErr2: // temporary label
  2255. BootErr$fnf:
  2256. movl out0 = TXT_MSG_SYSINIT_FILE_NOT_FD
  2257. br.cond.sptk.clr BootErr2
  2258. BootErr$ntc:
  2259. movl out0 = TXT_MSG_SYSINIT_NTLDR_CMPRS
  2260. br.cond.sptk.clr BootErr2
  2261. TXT_MSG_SYSINIT_BOOT_ERROR: stringz "A disk read error occurred"
  2262. TXT_MSG_SYSINIT_FILE_NOT_FD: stringz "NTLDR is missing"
  2263. TXT_MSG_SYSINIT_NTLDR_CMPRS: stringz "NTLDR is compressed"
  2264. TXT_MSG_SYSINIT_REBOOT: stringz "Press Ctrl+Alt+Del to restart"
  2265. #ifdef DEBUG
  2266. DbgString0 stringz "Debug Point 0"
  2267. DbgString1 stringz "Debug Point 1"
  2268. DbgString2 stringz "Debug Point 2"
  2269. DbgString3 stringz "Debug Point 3"
  2270. DbgString4 stringz "Debug Point 4"
  2271. #endif DEBUG
  2272. #ifdef NOT_YET_PORTED
  2273. .errnz ($-_ntfsboot) GT 8192 ; <FATAL PROBLEM: main boot record exceeds available space>
  2274. org 8192
  2275. BootCode ends
  2276. end _ntfsboot
  2277. #endif NOT_YET_PORTED