/** *** Copyright (C) 1996-97 Intel Corporation. All rights reserved. *** *** The information and source code contained herein is the exclusive *** property of Intel Corporation and may not be disclosed, examined *** or reproduced in whole or in part without explicit written authorization *** from the company. **/ //++ // // Module name // NTFSBOOT.S // Author // Allen Kay (akay) May-6-97 // Description // NTFS boot code // Notes // This is the startup routine for NTFS NT boot sector. It finds // NTLDR by walk through the NTFS file system structure. // Assumptions // 1. SAL/Gambit makes sure all TLB entries are purged before // passing control to SuSetup(). // SuSetup does the following: // 1. Initialize PSR with interrupt disabled. // 2. Invalidate ALAT. // 3. Invalidate RS. // 4. Setup GP. // 5. Set region registers rr[r0] - rr[r7] to RID=0, PS=8K, E=0. // 6. Initialize SP to 0x00902000. // 7. Initialize BSP to 0x00202000. // 8. Enable register stack engine. // 9. Setup IVA to 0x001F8000. // 10. Setup virtual->physical address translation // 0x80000000->0x00000000 in dtr0/itr0 for NT kernel. // 11. Setup virtual->physical address translation // 0x80400000->0x00400000 in dtr1/itr1 for HAL.dll. // 12. Setup virtual->physical address translation // 0x00800000->0x00800000 in dtr1/itr1 for NTLDR. //--- #include "ksia64.h" #include "susetup.h" #include "ntfsdefs.h" .file "ntfsboot.s" #define NewSeg 0x100000 #define LdrSeg 0x200000 .global Multiply .type Multiply, @function .global Divide .type Divide, @function .global memcpy .type memcpy, @function .global strncmp .type strncmp, @function .global PrintName .type PrintName, @function .global BootErr$Print .type BootErr$Print, @function .global SscExit .type SscExit, @function .global SalDiskReadWrite .type SalDiskReadWrite, @function .global ReadSectors .type ReadSectors, @function .global SalPrint .type SalPrint, @function .global LoadNtldrSymbols .type LoadNtldrSymbols, @function .global RelocateLoaderSections .type RelocateLoaderSections, @function // // This is a template BPB--anyone who writes boot code to disk // should either preserve the existing BPB and NTFS information // or create it anew. // #ifdef BSDT // // First define the Boot Sector Descriptor Table (BSDT) // BsdtSignature: data1 0x01, 0x02, 0x45, 0x4d, 0x0f, 0x00 BsdtSectors: data2 64 BsdtEntryPoint: data4 mainboot BsdtVersion: data1 0 BsdtReserved: data1 0, 0 BsdtCheckSum: data1 0 #endif // // Start of the NTFS boot sector // Version: string "NTFS " // Must be 8 characters BytesPerSector: data2.ua 0 // Size of a physical sector SectorsPerCluster: data1 0 // Sectors per allocation unit // // Traditionally the next 7 bytes were the reserved sector count, fat count, // root dir entry count, and the small volume sector count. However all of // these fields must be 0 on NTFS volumes. // // We use this space to store some temporary variables used by the boot code, // which avoids the need for separate space in sector 0 to store them. // We also take advantage of the free 0-initialization to save some space // by avoiding the code to initialize them. // // Note that ideally we'd want to use an unused field for the SectorCount // and initialize it to 16. This would let us save a few bytes by avoiding // code to explicitly initialize this value before we read the 16 boot sectors. // However setup and other code tends to preserve the entire bpb area when // it updates boot code, so we avoid a dependency here and initialize // the value explicitly to 16 in the first part of the boot code. // // ReservedSectors: data2.ua 0 // Number of reserved sectors // Fats: data1 0 // Number of fats // DirectoryEntries: data2.ua 0 // Number of directory entries // Sectors: data2.ua 0 // No. of sectors-no. of hidden sectors SectorCount: data2.ua 0 // number of sectors to read SectorBase: data4.ua 0 // start sector for read request HaveXInt13: data1 0 // extended int13 available flag Media: data1 0 // Media byte FatSectors: data2.ua 0 // Number of fat sectors SectorsPerTrack: data2.ua 0 // Sectors per track Heads: data2.ua 0 // Number of surfaces HiddenSectors: data4.ua 0 // Number of hidden sectors // // The field below is traditionally the large sector count and is // always 0 on NTFS. We use it here for a value the boot code calculates, // namely the number of sectors visible on the drive via conventional int13. // // Int13Sectors: data2 0 // SectorsLong: data4.ua 0 // Number of sectors iff Sectors = 0 // // TBD: Need additition fields for 5.0 stuff. // DriveNumber: data1 0x80 // int13 unit number ReservedForBootCode:data1 0 #ifdef BSDT Unused: data1 0,0,0,0,0 // Alignment filler #else Unused: data1 0,0 // Alignment filler #endif // // The following is the rest of the NTFS Sector Zero information. // The offsets of most of these fields cannot be changed without changing // all code that validates, formats, recognizes, etc, NTFS volumes. // In other words, don't change it. // SectorsOnVolume: data8 0 MftStartLcn: data8 0 Mft2StartLcn: data8 0 ClustersPerFrs: data1 0 Unused1: data1 0,0,0 DefClustersPerBuf: data1 0 Unused2: data1 0,0,0 SerialNumber: data8 0 CheckSum: data4 0 // // TBD: What should be done for IA64? // // Make sure size of fields matches what fs_rec.sys thinks is should be // // .errnz ($-_ntfsboot) NE (54h) // // // TBD. Dummy BootErr$he function. Need to fill in at a later time. // BootErr$he: // // NTFS data // // Name we look for. ntldr_length is the number of characters, // ntldr_name is the name itself. Note that it is not NULL // terminated, and doesn't need to be. // ntldr_name_length: data2 5 ntldr_name: data2 'N', 'T', 'L', 'D', 'R' // Predefined name for index-related attributes associated with an // index over $FILE_NAME // index_name_length: data2 4 index_name: data2 '$', 'I', '3', '0' // Global variables. These offsets are all relative to NewSeg. // AttrList: data4 0x0e000 // Offset of buffer to hold attribute list MftFrs: data4 0x3000 // Offset of first MFT FRS SegmentsInMft: data4 0 // number of FRS's with MFT Data attribute records RootIndexFrs: data4 0 // Offset of Root Index FRS AllocationIndexFrs: data4 0 // Offset of Allocation Index FRS ; KPeery BitmapIndexFrs: data4 0 // Offset of Bitmap Index FRS ; KPeery IndexRoot: data4 0 // Offset of Root Index $INDEX_ROOT attribute IndexAllocation: data4 0 // Offset of Root Index $INDEX_ALLOCATION attribute IndexBitmap: data4 0 // Offset of Root Index $BITMAP attribute NtldrFrs: data4 0 // Offset of NTLDR FRS NtldrData: data4 0 // Offset of NTLDR $DATA attribute IndexBlockBuffer: data4 0 // Offset of current index buffer IndexBitmapBuffer: data4 0 // Offset of index bitmap buffer NextBuffer: data4 0 // Offset of next free byte in buffer space BytesPerCluster: data4 0 // Bytes per cluster BytesPerFrs: data4 0 // Bytes per File Record Segment Result: data4 0 // Result from Multiply and Divide Remainder: data4 0 // Remainder // // For floppyless booting, winnt32.exe creates c:\$win_nt$.~bt\bootsec.dat and // places an entry in boot.ini for it (the boot selection says something // like "Windows NT Setup or Upgrade"). When that is selected, the boot loader // loads 16 sectors worth of data from bootsect.dat into d000 (which is where // the first sector of this code would have loaded it) and jumps into it at // a known location of 256h. That was correct in earlier versions of NT // but is not correct now because the 4 fields below were added to this sector. // // Note that 0000 is "add [bx+si],al" which because of the way the boot loader // is written happens to be a benign add of 0 to something in segment 7c0, // which doesn't seem to hose anything but is still somewhat random. // // We code in a jump here so as this new code proliferates we get this // cleaned up. // // .errnz $-_ntfsboot ne 256h // SectorsPerFrs label dword ; Sectors per File Record Segment // jmp short mainboot // nop // nop // .errnz $-_ntfsboot ne 25ah SectorsPerFrs: data4 0 // Sectors per File Record Segment BytesPerIndexBlock: data4 0 // Bytes per index alloc block in root index ClustersPerIndexBlock: data4 0 // Clusters per index alloc block in root index SectorsPerIndexBlock: data4 0 // Sectors per index block in root index //*************************************************************************** // // mainboot - entry point after 16 boot sectors have been read in // // .align 0x10 NESTED_ENTRY(mainboot) NESTED_SETUP(3,6,8,0) PROLOGUE_END rpT0 = t22 rpT1 = t21 rpT2 = t20 rpT3 = t19 rIndexRoot = loc2 rIRAttrib = loc3 rNtldrIndex = loc4 rPlabel = loc5 // // Setup the stack scratch area // add sp = -STACK_SCRATCH_AREA, sp // // Reinitialize xint13-related variables // // br.call.sptd.many brp = Int13SecCnt // determine range of regular int13 // Set up the FRS buffers. The MFT buffer is in a fixed // location, and the other three come right after it. The // buffer for index allocation blocks comes after that. // // // Compute the useful constants associated with the volume // movl rpT0 = BytesPerSector // Bytes Per Sector ld2 out0 = [rpT0] movl rpT0 = SectorsPerCluster // Sectors Per Cluster ld1 out1 = [rpT0] mov ap = sp br.call.sptk.many brp = Multiply movl rpT0 = BytesPerCluster st4 [rpT0] = v0 movl rpT0 = ClustersPerFrs // Clusters Per FRS ld1 t0 = [rpT0] sxt1 t0 = t0 cmp.gt pt0,pt1 = t0, zero // ClustersPerFrs less than zero? (pt0) br.cond.sptk.clr mainboot1 // If the ClustersPerFrs field is negative, we calculate the number // of bytes per FRS by negating the value and using that as a shift count. // sub t0 = zero, t0 movl t1 = 1 shl t3 = t1, t0 // bytes per frs br.cond.sptk.clr mainboot2 mainboot1: // Otherwise if ClustersPerFrs was positive, we multiply by bytes // per cluster. movl rpT0 = BytesPerCluster ld4 out1 = [rpT0] mov out0 = t0 mov ap = sp br.call.sptk.many brp = Multiply mainboot2: movl rpT0 = BytesPerFrs st4 [rpT0] = v0 movl rpT0 = BytesPerSector ld2 t2 = [rpT0] mov out0 = t3 mov out1 = t2 movl out2 = Result movl out3 = Remainder mov ap = sp br.call.sptk.many brp = Divide movl rpT0 = Result ld4 t0 = [rpT0] movl rpT0 = SectorsPerFrs st4 [rpT0] = t0 // Set up the MFT FRS's---this will read all the $DATA attribute // records for the MFT. // mov ap = sp br.call.sptk.many brp = SetupMft // Set up the remaining FRS buffers. The RootIndex FRS comes // directly after the last MFT FRS, followed by the NTLdr FRS // and the Index Block buffer. // movl rpT0 = NextBuffer ld4 t0 = [rpT0] movl rpT0 = RootIndexFrs st4 [rpT0] = t0 movl rpT0 = BytesPerFrs ld4 t1 = [rpT0] add t0 = t0, t1 // AllocationFrs may be different movl rpT0 = AllocationIndexFrs // from RootIndexFrs - KPeery st4 [rpT0] = t0 add t0 = t0, t1 // BitmapFrs may be different movl rpT0 = BitmapIndexFrs // from RootIndexFrs - KPeery st4 [rpT0] = t0 add t0 = t0, t1 movl rpT0 = NtldrFrs st4 [rpT0] = t0 add t0 = t0, t1 movl rpT0 = IndexBlockBuffer st4 [rpT0] = t0 // // Read the root index, allocation index and bitmap FRS's and locate // the interesting attributes. // movl out0 = $INDEX_ROOT movl rpT0 = RootIndexFrs ld4 out1 = [rpT0] mov ap = sp br.call.sptk.many brp = LoadIndexFrs cmp.eq pt0, pt1 = v0, zero (pt0) br.cond.sptk.clr BootErr$he mov rIndexRoot = v0 movl rpT0 = IndexRoot // offset in Frs buffer st4 [rpT0] = rIndexRoot movl out0 = $INDEX_ALLOCATION // Attribute type code movl rpT0 = AllocationIndexFrs // FRS to search ld4 out1 = [rpT0] br.call.sptk.many brp = LoadIndexFrs movl rpT0 = IndexAllocation st4 [rpT0] = v0 movl out0 = $BITMAP // Attribute type code movl rpT0 = BitmapIndexFrs // FRS to search ld4 out1 = [rpT0] br.call.sptk.many brp = LoadIndexFrs movl rpT0 = IndexBitmap st4 [rpT0] = v0 // Consistency check: the index root must exist, and it // must be resident. // cmp.eq pt0, pt1 = rIndexRoot, zero (pt0) br.cond.sptk.clr BootErr$he add rpT0 = ATTR_FormCode, rIndexRoot ld1 t0 = [rpT0] cmp.eq pt0, pt1 = RESIDENT_FORM, t0 (pt1) br.cond.sptk.clr BootErr$he // Determine the size of the index allocation buffer based // on information in the $INDEX_ROOT attribute. The index // bitmap buffer comes immediately after the index block buffer. // // rIndexRoot -> $INDEX_ROOT attribute record // add rpT3 = RES_ValueOffset, rIndexRoot // value of $INDEX_ROOT ld2 t0 = [rpT3] add rIRAttrib = rIndexRoot, t0 add rpT0 = IR_BlocksPerIndexBuffer, rIRAttrib ld1 t0 = [rpT0] movl rpT1 = ClustersPerIndexBlock st4 [rpT1] = t0 add rpT0 = IR_BytesPerIndexBuffer, rIRAttrib ld4 t0 = [rpT0] movl rpT1 = BytesPerIndexBlock st4 [rpT1] = t0 mov out0 = t0 movl rpT0 = BytesPerSector ld2 out1 = [rpT0] movl out2 = Result movl out3 = Remainder mov ap = sp br.call.sptk.many brp = Divide movl rpT0 = Result ld4 t0 = [rpT0] movl rpT1 = SectorsPerIndexBlock st4 [rpT1] = t0 movl rpT2 = IndexBlockBuffer ld4 t0 = [rpT2] movl rpT3 = BytesPerIndexBlock ld4 t1 = [rpT3] add t2 = t0, t1 movl rpT0 = IndexBitmapBuffer st4 [rpT0] = t2 // Next consistency check: if the $INDEX_ALLOCATION attribute // exists, the $INDEX_BITMAP attribute must also exist. // movl rpT0 = IndexAllocation ld4 t0 = [rpT0] cmp.eq pt0, pt1 = t0, zero (pt0) br.cond.sptk.clr mainboot30 movl rpT0 = IndexBitmap ld4 t0 = [rpT0] cmp.eq pt0, pt1 = t0, zero // since IndexAllocation exists, the (pt0) br.cond.sptk.clr BootErr$he // bitmap must exist, too. // Since the bitmap exists, we need to read it into the bitmap // buffer. If it's resident, we can just copy the data. // movl rpT0 = IndexBitmap ld4 out0 = [rpT0] // out0 -> index bitmap attribute movl rpT1 = IndexBitmapBuffer ld4 out1 = [rpT1] // out1 -> index bitmap buffer mov ap = sp br.call.sptk.many brp = ReadWholeAttribute mainboot30: // // OK, we've got the index-related attributes. // movl out0 = ntldr_name // out0 -> name movl rpT0 = ntldr_name_length ld2 out1 = [rpT0] // out1 = name length in characters mov ap = sp br.call.sptk.many brp = FindFile cmp.eq pt0, pt1 = v0, zero (pt0) br.cond.sptk.clr BootErr$fnf mov rNtldrIndex = v0 // Read the FRS for NTLDR and find its data attribute. // // rNtldrIndex -> Index Entry for NTLDR. // add rpT0 = IE_FileReference+LowPart, rNtldrIndex ld4 out0 = [rpT0] movl rpT1 = NtldrFrs ld4 out1 = [rpT1] mov ap = sp br.call.sptk.many brp = ReadFrs movl rpT0 = NtldrFrs ld4 out0 = [rpT0] // pointer to FRS movl out1 = $DATA // requested attribute type mov out2 = zero // attribute name length in characters mov out3 = zero // attribute name (NULL if none) mov ap = sp br.call.sptk.many brp = LocateAttributeRecord // v0 -> $DATA attribute for NTLDR // cmp.eq pt0, pt1 = v0, zero (pt1) br.cond.sptk.clr mainboot$FoundData // found attribute // // The ntldr $DATA segment is fragmented. Search the attribute list // for the $DATA member. And load it from there. // movl out0 = $DATA // Attribute type code movl rpT0 = NtldrFrs ld4 out1 = [rpT0] // FRS to search mov ap = sp br.call.sptk.many brp = SearchAttrList // search attribute list for FRN // of specified ($DATA) cmp.eq pt0, pt1 = v0, zero // if v0 is zero, attribute not found. (pt0) br.cond.sptk.clr BootErr$fnf // // We found the FRN of the $DATA attribute; load that into memory. // movl rpT0 = NtldrFrs ld4 out0 = [rpT0] mov ap = sp br.call.sptk.many brp = ReadFrs // // Determine the beginning offset of the $DATA in the FRS // movl rpT0 = NtldrFrs // pointer to FRS ld4 out0 = [rpT0] movl out1 = $DATA // requested attribute type mov out2 = zero // attribute name length in characters mov out3 = zero // attribute name (NULL if none) mov ap = sp br.call.sptk.many brp = LocateAttributeRecord // v0 -> $DATA attribute for NTLDR // cmp.eq pt0, pt1 = v0, zero // if v0 is zero, attribute not found. (pt0) br.cond.sptk.clr BootErr$fnf mainboot$FoundData: // Get the attribute record header flags, and make sure none of the // `compressed' bits are set add rpT0 = ATTR_Flags, v0 ld2 t0 = [rpT0] movl t1 = ATTRIBUTE_FLAG_COMPRESSION_MASK and t2 = t0, t1 cmp.eq pt0, pt1 = t2, zero (pt1) br.cond.sptk.clr BootErr$ntc mov out0 = v0 // out0 -> $DATA attribute for NTLDR movl out1 = LdrSeg // out1 = buffer address mov ap = sp br.call.sptk.many brp = ReadWholeAttribute // // Relocate the NTLDR image from LdrSeg to what is specified by the PE header // movl out0 = LdrSeg // out1 = buffer address mov ap = sp br.call.sptk.many brp = RelocateLoaderSections mov rPlabel = v0 // // Tell simdb to load NTLDR symbols // mov ap = sp br.call.sptk.many brp = LoadNtldrSymbols // // We've loaded NTLDR--jump to it. // // Before we go to NTLDR, set up the registers the way it wants them: // movl out0 = DriveNumber movl out1 = BytesPerSector mov psr.l = zero 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) mov cr.ipsr = t1 add rpT0 = PlEntryPoint, rPlabel ld8 t0 = [rpT0] mov cr.iip = t0 add rpT1 = PlGlobalPointer, rPlabel ld8 gp = [rpT1] rfi // "return" to NTLDR. ;; add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN NESTED_EXIT(mainboot) //**************************************************************************** // // ReadClusters - Reads a run of clusters from the disk. // // ENTRY: in0 == LCN to read // in1 == clusters to read // in2 -> Target buffer // // USES: none (preserves all registers) // NESTED_ENTRY(ReadClusters) NESTED_SETUP(3,4,8,0) PROLOGUE_END rpT0 = t22 rpT1 = t21 rLcn = in0 rCluster = in1 rBuffer = in2 rSectorBase = loc2 rSectorsPerCluster = loc3 // // setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp movl rpT0 = SectorsPerCluster ld1 rSectorsPerCluster = [rpT0] mov out0 = rLcn mov out1 = rSectorsPerCluster mov ap = sp br.call.sptk.many brp = Multiply mov rSectorBase= v0 mov out0 = rCluster mov out1 = rSectorsPerCluster mov ap = sp br.call.sptk.many brp = Multiply mov out1 = v0 // Number of sectors to read mov out0 = rSectorBase mov out2 = rBuffer mov ap = sp br.call.sptk.many brp = ReadSectors add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN NESTED_EXIT(ReadClusters) // //**************************************************************************** // // LocateAttributeRecord -- Find an attribute record in an FRS. // // ENTRY: in0 -- pointer to FRS // in1 -- desired attribute type code // in2 -- length of attribute name in characters // in3 -- pointer to attribute name // // EXIT: v0 points at attribute record (0 indicates not found) // // USES: All // NESTED_ENTRY(LocateAttributeRecord) NESTED_SETUP(4,3,8,0) PROLOGUE_END rpFrs = in0 rTypeCode = in1 rLength = in2 rpAttrName = in3 rpCurrentName = loc2 rpT0 = t22 rpT1 = t21 // // Setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp // // get the first attribute record. // add rpT0 = FRS_FirstAttributeOffset, rpFrs ld2 t0 = [rpT0] add rpFrs = rpFrs, t0 // rpFrs -> next attribute record to investigate. // rTypeCode == desired type // rLength == name length // rpAttrName -> pointer to name // lar10: add rpT0 = ATTR_TypeCode, rpFrs ld4 t0 = [rpT0] movl t1 = 0xffffffff cmp.eq pt0, pt1 = t0, t1 (pt0) br.cond.sptk.clr lar99 cmp.eq pt0, pt1 = t0, rTypeCode (pt1) br.cond.sptk.clr lar80 // this record is a potential match. Compare the names: // // rpFrs -> candidate record // rTypeCode == desired type // rLength == name length // rpAttrName -> pointer to name // cmp.eq pt0, pt1 = zero, rLength //Did the caller pass in a name length? (pt1) br.cond.sptk.clr lar20 // We want an attribute with no name--the current record is // a match if and only if it has no name. // add rpT0 = ATTR_NameLength, rpFrs ld1 t0 = [rpT0] cmp.eq pt0, pt1 = zero, t0 (pt1) br.cond.sptk.clr lar80 // Not a match. // It's a match, and rpFrs is set up correctly, so return. // mov v0 = rpFrs add sp = STACK_SCRATCH_AREA, sp // retore the original sp NESTED_RETURN // We want a named attribute. // // rpFrs -> candidate record // rTypeCode == desired type // rLength == name length // rpAttrName -> pointer to name // lar20: add rpT0 = ATTR_NameLength, rpFrs ld1 t0 = [rpT0] cmp.eq pt0, pt1 = rLength, t0 (pt1) br.cond.sptk.clr lar80 // Not a match. // Convert name in current record to uppercase. // add rpT0 = ATTR_NameOffset, rpFrs ld2 t0 = [rpT0] add rpCurrentName = rpFrs, t0 mov out0 = rpCurrentName add out1 = ATTR_NameLength, rpFrs mov ap = sp br.call.sptk.clr brp = UpcaseName // rpFrs -> candidate record // rTypeCode == desired type // rLength == name length // rpAttrName -> pointer to name // in4 -> Name in current record (upcased) // mov t2 = rLength mov rpT0 = rpCurrentName mov rpT1 = rpAttrName lar79: ld2 t0 = [rpT0], 2 ld2 t1 = [rpT1], 2 cmp.eq pt0, pt1 = t0, t1 (pt1) br.cond.sptk.clr lar80 add t2 = -1, t2 cmp.gt pt0, pt1 = t2, zero (pt0) br.cond.sptk.clr lar79 // t1 points at a matching record. // mov v0 = rpFrs add sp = STACK_SCRATCH_AREA, sp // restore sp before returning NESTED_RETURN // // This record doesn't match; go on to the next. // // rpFrs -> rejected candidate attribute record // rTypeCode == desired type // rLength == Name length // rpAttrName -> desired name // lar80: add rpT0 = ATTR_RecordLength, rpFrs ld1 t0 = [rpT0] cmp.eq pt0, pt1 = zero, t0 // if the record length is zero (pt0) br.cond.sptk.clr lar99 // the FRS is corrupt. add rpFrs = rpFrs, t0 br.cond.sptk.clr lar10 // Didn't find it. // lar99: mov v0 = zero add sp = STACK_SCRATCH_AREA, sp // restore sp before returning NESTED_RETURN NESTED_EXIT(LocateAttributeRecord) //**************************************************************************** // // LocateIndexEntry -- Find an index entry in a file name index // // ENTRY: in0 -> pointer to index header // in1 -> file name to find // in2 == length of file name in characters // // EXIT: v0 points at index entry. NULL to indicate failure. // // USES: All // NESTED_ENTRY(LocateIndexEntry) NESTED_SETUP(3,4,8,0) PROLOGUE_END rpT0 = t22 rHeader = in0 rpName = in1 rLength = in2 rEntry = loc2 rAttr = loc3 // // Setup the stack scratch area // add sp = -STACK_SCRATCH_AREA, sp // Convert the input name to upper-case // mov out0 = rpName mov out1 = rLength mov ap = sp br.call.sptk.many brp = UpcaseName #ifdef DEBUG mov out0 = rpName mov ap = sp br.call.sptk.many brp = PrintName mov ap = sp br.call.sptk.many brp = Debug2 #endif DEBUG add rpT0 = IH_FirstIndexEntry, rHeader ld4 t0 = [rpT0] add rEntry = rHeader, t0 // rEntry -> current entry // rpName -> file name to find // rLength == length of file name in characters // lie10: add rpT0 = IE_Flags, rEntry ld2 t0 = [rpT0] and t1 = INDEX_ENTRY_END, t0 // Is it the end entry? cmp.eq pt0, pt1 = t1, zero (pt1) br.cond.sptk.clr lie99 // quit if it is add rAttr = IE_Reserved+0x2, rEntry // FILE_NAME attribute value // was IE_Value #ifdef DEBUG // DEBUG CODE -- list file names as they are examined mov ap = sp br.call.sptk.many brp = Debug3 mov rpT0 = FN_FileNameLength, rAttr ld1 out1 = [rpT0] add out0 = FN_FileName, rAttr mov ap = sp br.call.sptk.many brp = PrintName #endif DEBUG // rEntry -> current entry // rpName -> file name to find // rLength == length of file name in characters // rAttr -> FILE_NAME attribute add rpT0 = FN_FileNameLength, rAttr ld1 t0 = [rpT0] cmp.eq pt0, pt1 = t0, rLength // Is name the right length? (pt1) br.cond.sptk.clr lie80 add out0 = FN_FileName, rAttr // Get name from FILE_NAME structure mov out1 = rLength mov ap = sp br.call.sptk.many brp = UpcaseName add out0 = FN_FileName, rAttr mov out1 = rpName // out0 alread setup by last call mov out2 = rLength br.call.sptk.many brp = strncmp cmp.eq pt0, pt1 = v0, zero (pt1) br.cond.sptk.clr lie80 // the current entry matches the search name, and eax points at it. // mov v0 = rEntry add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN // The current entry is not a match--get the next one. // rEntry -> current entry // rpName -> file name to find // rLength == length of file name in characters // lie80: add rpT0 = IE_Length, rEntry ld2 t0 = [rpT0] cmp.eq pt0, pt1 = t0, zero // If the entry length is zero (pt0) br.cond.sptk.clr lie99 // then the index block is corrupt. add rEntry = rEntry, t0 // Get the next entry. br.cond.sptk.clr lie10 // Name not found in this block. Set v0 to zero and return // lie99: mov v0 = zero add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN NESTED_EXIT(LocateIndexEntry) //**************************************************************************** // // ReadWholeAttribute - Read an entire attribute value // // ENTRY: in0 -> attribute // in1 -> target buffer // // USES: ALL // NESTED_ENTRY(ReadWholeAttribute) NESTED_SETUP(2,4,8,0) rAttribute = in0 rBuffer = in1 rpT0 = t22 // setup sp and ap for all function calls add sp = -STACK_SCRATCH_AREA, sp add rpT0 = ATTR_FormCode, in0 ld1 t0 = [rpT0] cmp.eq pt0, pt1 = RESIDENT_FORM, t0 (pt1) br.cond.sptk.clr rwa10 // The attribute is resident. // rAttribute -> attribute // rBuffer -> target buffer // add rpT0 = RES_ValueOffset, rAttribute ld2 t0 = [rpT0] add out0 = rAttribute, t0 mov out1 = rBuffer add rpT0 = RES_ValueLength, rAttribute ld4 out2 = [rpT0] mov ap = sp br.call.sptk.many brp = memcpy add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN // That's all! rwa10: // // The attribute type is non-resident. Just call // ReadNonresidentAttribute starting at VCN 0 and // asking for the whole thing. // // rAttribute -> attribute // rBuffer -> target buffer // mov out0 = zero // 0 (first VCN to read) mov out1 = rAttribute // Attribute add rpT0 = NONRES_HighestVcn+LowPart, rAttribute // # of clusters ld4 out2 = [rpT0] add out2 = 1, out2 mov out3 = rBuffer // Target Buffer mov ap = sp br.call.sptk.many brp = ReadNonresidentAttribute add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN NESTED_EXIT(ReadWholeAttribute) //**************************************************************************** // // ReadNonresidentAttribute - Read clusters from a nonresident attribute // // ENTRY: in0 == First VCN to read // in1 -> Attribute // in2 == Number of clusters to read // in3 == Target of read // // EXIT: None. // // USES: None (preserves all registers with SAVE_ALL/RESTORE_ALL) // NESTED_ENTRY(ReadNonresidentAttribute) NESTED_SETUP(4,4,8,0) PROLOGUE_END rVcn = in0 rAttribute = in1 rCluster = in2 rBuffer = in3 rRun = loc2 rTmp = loc3 // // setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp add rpT0 = ATTR_FormCode, rAttribute ld1 t0 = [rpT0] cmp.eq pt0, pt1 = NONRESIDENT_FORM, t0 (pt0) br.cond.sptk.clr ReadNR10 // This attribute is not resident--the disk is corrupt. br.cond.sptk.clr BootErr$he ReadNR10: // rVcn == Next VCN to read // rAttribute -> Attribute // rCluster -> Remaining clusters to read // rBuffer -> Target of read // cmp.eq pt0, pt1 = rCluster,zero (pt1) br.cond.sptk.clr ReadNR20 // Nothing left to read--return success. // add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN ReadNR20: mov out0 = rVcn mov out1 = rAttribute mov ap = sp br.call.sptk.many brp = ComputeLcn mov rLcn = t0 // rLcn = LCN mov rRun = t1 // rRun = remaining run length // rLcn == LCN to read // rCluster == remaining clusters to read // rRun == remaining clusters in current run // rBuffer == Target of read // cmp.ge pt0, pt1 = rCluster, rRun (pt0) br.cond.sptk.clr ReadNR30 // Run length is greater than remaining request// only read // remaining request. // mov rRun = rCluster // rRun = Remaining request ReadNR30: // rLcn == LCN to read // rCluster == remaining clusters to read // rRun == clusters to read in current run // rBuffer == Target of read // mov out0 = rLcn mov out1 = rCluster mov out2 = rBuffer mov ap = sp br.call.sptk.many brp = ReadClusters sub rCluster = rCluster, rRun // Decrement clusters remaining mov out0 = rRun movl rpT0 = SectorsPerCluster ld1 out1 = [rpT0] mov ap = sp br.call.sptk.many brp = Multiply mov out0 = v0 movl rpT0 = BytesPerSector ld4 out1 = [rpT0] mov ap = sp br.call.sptk.many brp = Multiply add rBuffer = rBuffer, v0 // Update target of read add rVcn = rVcn, rRun // Update VCN to read br.cond.sptk.clr ReadNR10 add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN NESTED_EXIT(ReadNonresidentAttribute) //**************************************************************************** // // ReadIndexBlockSectors - Read sectors from an index allocation attribute // // ENTRY: in0 == First VBN to read // in1 -> Attribute // in2 == Number of sectors to read // in3 == Target of read // // EXIT: None. // // USES: None (preserves all registers with SAVE_ALL/RESTORE_ALL) // NESTED_ENTRY(ReadIndexBlockSectors) NESTED_SETUP(4,6,8,0) PROLOGUE_END rpT0 = t22 rVbn = in0 rAttr = in1 rSectors = in2 rBuffer = in3 rSectorsPerCluster = loc2 rRemainClusters = loc3 rRunSectors = loc4 rLbn = loc5 // // Setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp add rpT0 = ATTR_FormCode, rAttr ld1 t0 = [rpT0] cmp.eq pt0, pt1 = NONRESIDENT_FORM, t0 (pt0) br.cond.sptk.clr ReadIBS_10 // This attribute is resident--the disk is corrupt. br.cond.sptk.clr BootErr$he ReadIBS_10: // rVbn == Next VBN to read // rAttr -> Attribute // rSectors -> Remaining sectors to read // rBuffer -> Target of read // cmp.eq pt0, pt1 = rSectors, zero (pt1) br.cond.sptk.clr ReadIBS_20 // Nothing left to read--return success. // add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN ReadIBS_20: // Convert rVbn from a VBN back to a VCN by dividing by SectorsPerCluster. // The remainder of this division is the sector offset in the cluster we // want. Then use the mapping information to get the LCN for this VCN, // then multiply to get back to LBN. // mov out0 = rVbn movl rpT0 = SectorsPerCluster ld1 rSectorsPerCluster = [rpT0] mov out1 = rSectorsPerCluster movl out2 = Result movl out3 = Remainder mov ap = sp br.call.sptk.many brp = Divide movl rpT0 = Result ld4 out0 = [rpT0] mov out1 = rAttr mov ap = sp br.call.sptk.many brp = ComputeLcn // t0 = LCN to read, // t1 = remaining run length mov rRemainClusters = t1 mov out0 = t0 mov out1 = rSectorsPerCluster mov ap = sp br.call.sptk.many brp = Multiply // v0 = LBN of cluster movl rpT0 = Remainder ld4 t0 = [rpT0] // t0 = remainder add rLbn = v0, t0 // rLbn = LBN we want mov out0 = rRemainClusters mov out1 = rSectorsPerCluster mov ap = sp br.call.sptk.many brp = Multiply // v0 = remaining run length in sectors mov rRunSectors = v0 // remaining run length // rLbn == LBN to read // rSectors == remaining sectors to read // rRunSectors == remaining sectors in current run // rBuffer == Target of read // cmp.ge pt0, pt1 = rSectors, rRunSectors (pt0) br.cond.sptk.clr ReadIBS_30 // Run length is greater than remaining request; only read // remaining request. // mov rRunSectors = rSectors // rRunSectors = Remaining request ReadIBS_30: // rLbn == LBN to read // rSectors == remaining sectors to read // rRunSectors == sectors to read in current run // rBuffer == Target of read // mov out0 = rLbn mov out1 = rRunSectors mov out2 = rBuffer mov ap = sp br.call.sptk.many brp = ReadSectors // // Decrement sectors remaining in request // sub rSectors = rSectors, rRunSectors mov out0 = rRunSectors // eax = sectors read movl rpT0 = BytesPerSector ld2 out1 = [rpT0] br.call.sptk.many brp = Multiply // v0 = bytes read (wipes out edx!) add rBuffer = rBuffer, v0 // Update target of read add rVbn = rVbn, rRunSectors // update VBN to read br.cond.sptk.clr ReadIBS_10 add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN NESTED_EXIT(ReadIndexBlockSectors) //**************************************************************************** // // MultiSectorFixup - fixup a structure read off the disk // to reflect Update Sequence Array. // // ENTRY: in0 = Target buffer // // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL) // // Note: in0 must point at a structure which is protected // by an update sequence array, and which begins with // a multi-sector-header structure. // NESTED_ENTRY(MultiSectorFixup) NESTED_SETUP(3,3,8,0) PROLOGUE_END #define MshUpdateSeqenceArrayOffset 4 #define SEQUENCE_NUMBER_STRIDE 512 add rpT0 = MshUpdateSeqenceArrayOffset, in0 ld2 t0 = [rpT0], 2 // t0 = update array offset ld2 t1 = [rpT0] // t1 = update array size cmp.eq pt0, pt1 = zero, t1 // if the size of the update sequence array (pt0) br.cond.sptk.clr BootErr$he // is zero, this structure is corrupt. add rpT0 = t0, in0 // rpT0 -> update sequence array count word add rpT0 = 2, rpT0 // rpT0 -> 1st entry of update array add rpT1=SEQUENCE_NUMBER_STRIDE-2,in0 //t2->last word of first chunk movl t2 = 1 sub t1 = t1, t2 // decrement to reflect count word cmp.eq pt0, pt1 = zero, t2 (pt0) br.cond.sptk.clr MSF30 MSF10: // t1 = number of entries remaining in update sequence array // rpT0 -> next entry in update sequence array // rpT1 -> next target word for update sequence array ld2 t0 = [rpT0] // copy next update sequence array entry st2 [rpT0] = t0 // to next target word add rpT0 = 2, rpT0 // go on to next entry add rpT1 = SEQUENCE_NUMBER_STRIDE, rpT1 // go on to next target sub t1 = t1, t2 cmp.lt pt0, pt1 = zero, t1 (pt0) br.cond.sptk.clr MSF10 MSF30: NESTED_RETURN NESTED_EXIT(MultiSectorFixup) //**************************************************************************** // // SetupMft - Reads MFT File Record Segments into memory. // // ENTRY: none. // // EXIT: NextBuffer is set to the free byte after the last MFT FRS // SegmentsInMft is initialized // // NESTED_ENTRY(SetupMft) NESTED_SETUP(3,6,8,0) PROLOGUE_END rpT0 = t22 rpT1 = t21 rpT2 = t20 rpT3 = t19 rAttrList = loc2 rAttrLength = loc3 rNextBuffer = loc4 rBytesPerFrs = loc5 // // Setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp // // Update MftFrs with NewSeg base offset // movl rpT0 = MftFrs ld4 t0 = [rpT0] movl t1 = NewSeg add t2 = t0, t1 st4 [rpT0] = t2 // Initialize SegmentsInMft and NextBuffer as if the MFT // had only one FRS. // movl t0 = 1 movl rpT0 = SegmentsInMft st4 [rpT0] = t0 movl rpT1 = MftFrs ld4 t1 = [rpT1] movl rpT2 = BytesPerFrs ld4 rBytesPerFrs = [rpT2] add rNextBuffer = t1, rBytesPerFrs movl rpT3 = NextBuffer st4 [rpT3] = t3 // Read FRS 0 into the first MFT FRS buffer, being sure // to resolve the Update Sequence Array. // movl rpT0 = MftStartLcn ld8 out0 = [rpT0] movl rpT1 = SectorsPerCluster ld8 out1 = [rpT1] mov ap = sp br.call.sptk.many brp = Multiply movl rpT0 = SectorBase // SectorBase = mft starting sector st4 [rpT0] = v0 movl rpT0 = SectorsPerFrs ld8 t0 = [rpT0] movl rpT0 = SectorCount // SectorCount = SectorsPerFrs st2 [rpT0] = t0 movl rpT0 = MftFrs ld4 t0 = [rpT0] movl rpT0 = SectorBase ld4 out0 = [rpT0] // Sector count is zero for some reason. Manually set to 1 // movl rpT1 = SectorCount ld4 out1 = [rpT1] movl rpT0 = MftFrs ld4 out2 = [rpT0] mov ap = sp br.call.sptk.many brp = ReadSectors movl rpT0 = MftFrs ld4 out0 = [rpT0] #ifdef MFT_FRS movl t1 = NewSeg add out0 = t0, t1 #endif mov ap = sp br.call.sptk.many brp = MultiSectorFixup // Determine whether the MFT has an Attribute List attribute movl rpT0 = MftFrs ld4 out0 = [rpT0] #ifdef MFT_FRS movl t1 = NewSeg add out0 = t0, t1 #endif movl out1 = $ATTRIBUTE_LIST mov out2 = zero mov out3 = zero mov ap = sp br.call.sptk.many brp = LocateAttributeRecord cmp.eq pt0, pt1 = zero, v0 // If there's no Attribute list, (pt0) br.cond.sptk.clr SetupMft99 // we're done! // Read the attribute list. // v0 -> attribute list attribute // mov out0 = v0 // out0 -> attribute list attribute mov out1 = rAttrList // rAttrList -> attribute list buffer mov ap = sp br.call.sptk.many brp = ReadWholeAttribute // Now, traverse the attribute list looking for the first // entry for the $DATA type. We know it must have at least // one. // // rAttrList -> first attribute list entry // SetupMft10: add rpT0 = ATTRLIST_AttributeTypeCode, rAttrList ld4 t0 = [rpT0] movl t1 = $DATA cmp.eq pt0, pt1 = t0, t1 (pt0) br.cond.sptk.clr SetupMft20 add rpT0 = ATTRLIST_RecordLength, rAttrList ld4 t0 = [rpT0] add rAttrList = rAttrList, t0 br.cond.sptk.clr SetupMft10 SetupMft20: // Scan forward through the attribute list entries for the // $DATA attribute, reading each referenced FRS. Note that // there will be at least one non-$DATA entry after the entries // for the $DATA attribute, since there's a $BITMAP. // // rAttrList -> Next attribute list entry // rNextBuffer -> Target for next read // SegmentsInMft == number of MFT segments read so far // add rpT0 = ATTRLIST_AttributeTypeCode, rAttrList ld4 t0 = [rpT0] movl t1 = $DATA cmp.eq pt0, pt1 = t0, t1 (pt1) br.cond.sptk.clr SetupMft99 // Read the FRS referred to by this attribute list entry into // the next buffer, and increment rNextBuffer and SegmentsInMft. // add rpT0 = ATTRLIST_SegmentReference, rAttrList add rpT0 = REF_SegmentNumberLowPart, rAttrList ld4 out0 = [rpT0] mov out1 = rNextBuffer mov ap = sp br.call.sptk.many brp = ReadFrs // Increment rNextBuffer and SegmentsInMft add rNextBuffer = rNextBuffer, rBytesPerFrs movl rpT0 = SegmentsInMft ld4 t0 = [rpT0] add t0 = 1, t0 st4 [rpT0] = t0 // Go on to the next attribute list entry add rAttrList = rAttrList, rAttrLength br.cond.sptk.clr SetupMft20 SetupMft99: movl rpT0 = NextBuffer st4 [rpT0] = rNextBuffer add sp = STACK_SCRATCH_AREA, sp // readjust sp before exiting NESTED_RETURN NESTED_EXIT(SetupMft) //**************************************************************************** // // ComputeMftLcn -- Computes the LCN for a cluster of the MFT // // // ENTRY: in0 == VCN // // EXIT: v0 == LCN // // USES: ALL // NESTED_ENTRY(ComputeMftLcn) NESTED_SETUP(3,5,8,0) PROLOGUE_END rpT0 = t22 rFrsCount = loc2 rNextFrs = loc3 rVcn = loc4 // // Setup sp and ap for all function calls // add sp = -STACK_SCRATCH_AREA, sp mov ap = sp mov rVcn = in0 // rVcn = VCN movl rpT0 = SegmentsInMft // rFrsCount = # of FRS's to search ld4 rFrsCount = [rpT0] movl rpT0 = MftFrs // rNextFrs -> first FRS to search ld4 rNextFrs = [rpT0] MftLcn10: // rNextFrs -> Next FRS to search // rFrsCount == number of remaining FRS's to search // rVcn == VCN // mov out0 = rNextFrs movl out1 = $DATA mov out2 = zero mov out3 = zero mov ap = sp br.call.sptk.many brp = LocateAttributeRecord cmp.eq pt0, pt1 = zero, v0 (pt0) br.cond.sptk.clr BootErr$he // No $DATA attribute in this FRS! mov out0 = rVcn // out0 = VCN mov out1 = v0 // out1 -> attribute mov ap = sp br.call.sptk.many brp = ComputeLcn cmp.eq pt0, pt1 = zero, t0 // t0 is return value of ComputeLcn (pt0) br.cond.sptk.clr MftLcn20 mov v0 = t0 add sp = STACK_SCRATCH_AREA, sp // readjust sp before exiting NESTED_RETURN MftLcn20: // // Didn't find the VCN in this FRS; try the next one. // movl rpT0 = BytesPerFrs // rNextFrs -> next FRS ld4 t0 = [rpT0] add rNextFrs = rNextFrs, t0 br.cond.sptk.clr MftLcn10 // decrement ecx and try next FRS // This VCN was not found. // mov v0 = zero add sp = STACK_SCRATCH_AREA, sp // readjust sp before exiting NESTED_RETURN NESTED_EXIT(ComputeMftLcn) //**************************************************************************** // // ReadMftSectors - Read sectors from the MFT // // ENTRY: in0 == starting VBN // in1 == number of sectors to read // in2 == Target buffer // // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL) // NESTED_ENTRY(ReadMftSectors) NESTED_SETUP(3,4,8,0) PROLOGUE_END rpT0 = t22 rVbn = in0 rSectorCount = in1 rBuffer = in2 rSectorsPerCluster = loc2 rBytesPerCluster = loc3 // Reserve the stack scratch area add sp = -STACK_SCRATCH_AREA, sp movl rpT0 = BytesPerCluster ld4 rBytesPerCluster = [rpT0] RMS$Again: // Divide the VBN by SectorsPerCluster to get the VCN mov out0 = in0 movl rpT0 = SectorsPerCluster ld1 rSectorsPerCluster = [rpT0] mov out1 = rSectorsPerCluster movl out2 = Result movl out3 = Remainder mov ap = sp br.call.sptk.many brp = Divide movl rpT0 = Result ld4 out0 = [rpT0] mov ap = sp br.call.sptk.many brp = ComputeMftLcn cmp.eq pt0, pt1 = zero, v0 // LCN equal to zero? (pt0) br.cond.sptk.clr BootErr$he // zero is not a possible LCN // Change the LCN back into a LBN and add the remainder back in to get // the sector we want to read, which goes into SectorBase. // mov out0 = v0 mov out1 = rSectorsPerCluster mov ap = sp br.call.sptk.many brp = Multiply // v0 = cluster first LBN movl rpT0 = Remainder ld4 t0 = [rpT0] add t1 = v0, t0 // t1 = desired LBN movl rpT0 = SectorBase st4 [rpT0] = t1 // // Figure out how many sectors to read this time// we never attempt // to read more than one cluster at a time. // cmp.le pt0, pt1 = rSectorCount,rSectorsPerCluster (pt0) br.cond.sptk.clr RMS10 // // Read only a single cluster at a time, to avoid problems with fragmented // runs in the mft. // movl rpT0 = SectorCount st2 [rpT0] = rSectorsPerCluster // this time read 1 cluster sub rSectorCount = rSectorCount, rSectorsPerCluster // sect. remain add rVbn = rVbn, rSectorsPerCluster // VBN += sectors this read br.cond.sptk.clr RMS20 RMS10: add rVbn = rVbn, rSectorCount // VBN += sectors this read movl rpT0 = SectorCount st2 [rpT0] = rSectorCount mov rSectorCount = zero // remaining sector count (0) RMS20: // The target buffer was passed in es:edi, but we want it in es:bx. // Do the conversion. // movl rpT0 = SectorBase ld4 out0 = [rpT0] movl rpT0 = SectorCount ld2 out1 = [rpT0] mov out2 = rBuffer mov ap = sp br.call.sptk.many brp = ReadSectors add rBuffer = rBuffer, rBytesPerCluster cmp.gt pt0, pt1 = rSectorCount, zero // are we done? (pt0) br.cond.sptk.clr RMS$Again // repeat until desired == 0 add sp = STACK_SCRATCH_AREA, sp // Reclaim the scratch area NESTED_RETURN NESTED_EXIT(ReadMftSectors) //**************************************************************************** // // ReadFrs - Read an FRS // // ENTRY: in0 == FRS number // in1 == Target buffer // // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL) // NESTED_ENTRY(ReadFrs) NESTED_SETUP(3,3,8,0) PROLOGUE_END rpT0 = t22 rSectorsPerFrs = loc2 // // Adjust sp with sratch area // add sp = -STACK_SCRATCH_AREA, sp movl rpT0 = SectorsPerFrs ld4 rSectorsPerFrs = [rpT0] mov out0 = in0 // FRS number mov out1 = rSectorsPerFrs // Sectors per FRS mov ap = sp br.call.sptk.many brp = Multiply mov out0 = v0 // out0 = starting VBN mov out1 = rSectorsPerFrs // out1 = number of sectors to read mov out2 = in1 // out2 = target buffer mov ap = sp br.call.sptk.many brp = ReadMftSectors mov out0 = in1 // out2 = target buffer mov ap = sp br.call.sptk.many brp = MultiSectorFixup add sp = STACK_SCRATCH_AREA, sp // Readjust sp before exiting NESTED_RETURN NESTED_EXIT(ReadFrs) //**************************************************************************** // // ReadIndexBlock - read an index block from the root index. // // ENTRY: in0 == Block number // // USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL) // NESTED_ENTRY(ReadIndexBlock) NESTED_SETUP(3,3,8,0) rpT0 = t22 rpT1 = t21 rpT2 = t20 rBlock = in0 rBuffer = loc2 // // Setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp mov out0 = rBlock movl rpT0 = SectorsPerIndexBlock ld4 out1 = [rpT0] mov ap = sp br.call.sptk.many brp = Multiply mov out0 = v0 // v0 = first VBN to read movl rpT0 = IndexAllocation ld4 out1 = [rpT0] // out1 -> $INDEX_ALLOCATION attribute movl rpT1 = SectorsPerIndexBlock // out2 == Sectors to read ld4 out2 = [rpT1] movl rpT2 = IndexBlockBuffer // out3 -> index block buffer ld4 rBuffer = [rpT2] mov out3 = rBuffer mov ap = sp br.call.sptk.many brp = ReadIndexBlockSectors mov out0 = rBuffer mov ap = sp br.call.sptk.many brp = MultiSectorFixup add sp = STACK_SCRATCH_AREA, sp // Readjust sp before exiting NESTED_RETURN NESTED_EXIT(ReadIndexBlock) //**************************************************************************** // // IsBlockInUse - Checks the index bitmap to see if an index // allocation block is in use. // // ENTRY: in0 == block number // // EXIT: Carry flag clear if block is in use // Carry flag set if block is not in use. // NESTED_ENTRY(IsBlockInUse) NESTED_SETUP(3,5,8,0) PROLOGUE_END rpT0 = t22 rBlock = in0 rTest = loc2 rByte = loc3 rBit = loc4 // // Reserve stack scratch area // add sp = -STACK_SCRATCH_AREA, sp movl rpT0 = IndexBitmapBuffer ld4 rTest = [rpT0] mov t0 = rBlock // t0 = block number shr rByte = t0, 3 // rByte = byte number and rBit = 7, rBlock // rBit = bit number in byte add rTest = rTest, rByte // rTest = byte to test movl t0 = 1 shl t0 = t0, rBit // t0 = mask ld1 t1 = [rTest] and t2 = t1, t0 cmp.eq pt0, pt1 = t2, zero (pt0) br.cond.sptk.clr IBU10 mov v0 = zero // Block is not in use. br.cond.sptk.clr IBU20 IBU10: movl v0 = 1 // Block is in use. IBU20: add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN NESTED_EXIT(IsBlockInUse) //**************************************************************************** // // ComputeLcn - Converts a VCN into an LCN // // ENTRY: in0 -> VCN // in1 -> Attribute // // EXIT: t0 -> LCN (zero indicates not found) // t1 -> Remaining run length // // USES: ALL. // NESTED_ENTRY(ComputeLcn) NESTED_SETUP(3,7,8,0) PROLOGUE_END rpT0 = t22 rVcn = in0 // VCN rAttribute = in1 // Attribute rpMappingPair = loc2 rDeltaVcn = loc3 rCurrentVcn = loc4 rCurrentLcn = loc5 rNextVcn = loc6 // // Setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp add rpT0 = ATTR_FormCode, rAttribute ld1 t0 = [rpT0] cmp.eq pt0, pt1 = NONRESIDENT_FORM, t0 (pt1) br.cond.sptk.clr clcn99 // This is a resident attribute. clcn10: // // See if the desired VCN is in range. // add rpT0 = NONRES_HighestVcn+LowPart, rAttribute ld4 t0 = [rpT0] // t0 = HighestVcn cmp.gt pt0, pt1 = rVcn, t0 (pt0) br.cond.sptk.clr clcn99 // VCN is greater than HighestVcn add rpT0 = NONRES_LowestVcn+LowPart, rAttribute ld4 rCurrentVcn = [rpT0] // rCurrentVcn = LowestVcn cmp.lt pt0, pt1 = rVcn, rCurrentVcn (pt0) br.cond.sptk.clr clcn99 // VCN is less than LowestVcn clcn20: add rpT0 = NONRES_MappingPairOffset, rAttribute ld2 t0 = [rpT0] add rpMappingPair = rAttribute, t0 ld1 t0 = [rpMappingPair] mov rCurrentLcn = zero // Initialize Current LCN clcn30: cmp.eq pt0, pt1 = zero, t0 // if count byte is zero... (pt0) br.cond.sptk.clr clcn99 // ... we're done (and didn't find it) // Update CurrentLcn // mov out0 = rpMappingPair mov ap = sp br.call.sptk.many brp = LcnFromMappingPair add rCurrentLcn = rCurrentLcn, v0 mov out0 = rpMappingPair mov ap = sp br.call.sptk.many brp = VcnFromMappingPair // out0 = previous out0 mov rDeltaVcn = v0 // rVcn == VCN to find // rpMappingPair -> Current mapping pair count byte // rDeltaVcn == DeltaVcn for current mapping pair // rCurrentVcn == Current VCN // rCurrentLcn == Current LCN // add rNextVcn = rDeltaVcn, rCurrentVcn // NextVcn cmp.lt pt0, pt1 = rVcn, rNextVcn // If target < NextVcn ... (pt0) br.cond.sptk.clr clcn80 // ... we found the right mapping pair. // Go on to next mapping pair. // mov rCurrentVcn = rNextVcn // CurrentVcn = NextVcn ld1 t0 = [rpMappingPair] // t0 = count byte mov t1 = t0 // t1 = count byte and t1 = 0x0f, t1 // t1 = number of vcn bytes shr t0 = t0, 4 // t0 = number of lcn bytes add rpMappingPair = rpMappingPair, t0 add rpMappingPair = rpMappingPair, t1 add rpMappingPair = 1, rpMappingPair // -> next count byte br.cond.sptk.clr clcn30 clcn80: // We found the mapping pair we want. // // rVcn == target VCN // rMappingPair -> mapping pair count byte // rCurrentVcn == Starting VCN of run // rNextVcn == Next VCN (ie. start of next run) // rCurrentLcn == starting LCN of run // sub t1 = rNextVcn, rVcn // t1 = remaining run length sub t0 = rVcn, rCurrentVcn // t0 = offset into run add t0 = t0, rCurrentLcn // t0 = LCN to return add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN // The target VCN is not in this attribute. clcn99: mov v0 = zero // Not found. add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN NESTED_EXIT(ComputeLcn) //**************************************************************************** // // VcnFromMappingPair // // ENTRY: in0 -> Mapping Pair count byte // // EXIT: v0 == DeltaVcn from mapping pair // // LEAF_ENTRY(VcnFromMappingPair) LEAF_SETUP(3,4,8,0) PROLOGUE_END rpMP = in0 rv = loc2 rVcn = loc3 ld1 rv = [rpMP] // rv = count byte and rv = 0x0f, rv // rv = v cmp.eq pt0, pt1 = zero, rv // if rv is zero, volume is corrupt. (pt1) br.cond.sptk.clr VFMP5 mov v0 = zero br.cond.sptk.clr VFMP99 VFMP5: add rpMP = rpMP, rv // rpMP -> last byte of compressed vcn ld1 rVcn = [rpMP] sxt1 rVcn = rVcn add rv = -1, rv add rpMP = -1, rpMP // rpMP -> Next byte to add in // rv == Number of bytes remaining // rVcn == Accumulated value // VFMP10: cmp.eq pt0, pt1 = zero, rv // When rv == 0, we're done. (pt0) br.cond.sptk.clr VFMP20 shl rVcn = rVcn, 8 ld1 t0 = [rpMP] or rVcn = rVcn, t0 add rpMP = -1, rpMP // Back up through bytes to process. add rv = -1, rv // One less byte to process. br.cond.sptk.clr VFMP10 VFMP20: // rVcn == Accumulated value to return movl t0 = 0xffffffff // return the lower 32-bits and v0 = rVcn, t0 VFMP99: LEAF_RETURN LEAF_EXIT(VcnFromMappingPair) //**************************************************************************** // // LcnFromMappingPair // // ENTRY: in0 -> Mapping Pair count byte // // EXIT: v0 == DeltaLcn from mapping pair // LEAF_ENTRY(LcnFromMappingPair) LEAF_SETUP(3,5,8,0) PROLOGUE_END rpMP = in0 rv = loc2 rl = loc3 rLcn = loc4 ld1 rv = [rpMP] and rv = 0xf, rv // rv = v ld1 rl = [rpMP] shr rl = rl, 4 // rl = l cmp.eq pt0, pt1 = zero, rl // if rl is zero, volume is corrupt. (pt1) br.cond.sptk.clr LFMP5 mov v0 = zero br.cond.sptk.clr LFMP99 LFMP5: // rpMP -> count byte // rl == l // rv == v // add rpMP = rpMP, rv // rpMP -> last byte of compressed vcn add rpMP = rpMP, rl // rpMP -> last byte of compressed lcn ld1 rLcn = [rpMP] sxt1 rLcn = rLcn add rl = -1, rl add rpMP = -1, rpMP // rpMP -> Next byte to add in // rl == Number of bytes remaining // rLcn == Accumulated value // LFMP10: cmp.eq pt0, pt1 = zero, rl // When rl == 0, we're done. (pt0) br.cond.sptk.clr LFMP20 shl rLcn = rLcn, 8 ld1 t0 = [rpMP] or rLcn = rLcn, t0 add rpMP = -1, rpMP // Back up through bytes to process. add rl = -1, rl // One less byte to process. br.cond.sptk.clr LFMP10 LFMP20: // rLcn == Accumulated value to return movl t0 = 0xffffffff // return the lower 32-bits and v0 = rLcn, t0 LFMP99: LEAF_RETURN LEAF_EXIT(LcnFromMappingPair) //*************************************************************************** // // UpcaseName - Converts the name of the file to all upper-case // // ENTRY: in0 -> Name // in1 -> Length of name // // USES: none // LEAF_ENTRY(UpcaseName) LEAF_SETUP(2,3,0,0) PROLOGUE_END rpName = in0 rLength = in1 cmp.eq pt0, pt1 = zero, rLength (pt0) br.cond.sptk.clr UN30 UN10: ld2 t0 = [rpName] cmp.gt pt0, pt1 = 'a', t0 // if it's less than 'a' (pt0) br.cond.sptk.clr UN20 // leave it alone cmp.lt pt0, pt1 = 'z', t0 // if it's greater than 'z' (pt0) br.cond.sptk.clr UN20 // leave it alone. movl t1 = 'a' - 'A' // the letter is lower-case--convert it. sub t0 = t0, t1 UN20: add rpName = 2, rpName // move on to next unicode character add rLength = -1, rLength cmp.eq pt0, pt1 = zero, rLength (pt0) br.cond.sptk.clr UN10 UN30: LEAF_RETURN LEAF_EXIT(UpcaseName) //**************************************************************************** // // FindFile - Locates the index entry for a file in the root index. // // ENTRY: in0 -> name to find // in1 == length of file name in characters // // EXIT: v0 -> Index Entry. NULL to indicate failure. // // USES: ALL // NESTED_ENTRY(FindFile) NESTED_SETUP(3,4,8,0) PROLOGUE_END rpT0 = t22 rpT1 = t21 rpName = in0 rLength = in1 rIndexAllocation = loc2 rBlock = loc3 // // Setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp // First, search the index root. // // rpName -> name to find // rLength == name length // movl rpT0 = IndexRoot ld4 t0 = [rpT0] add rpT1 = RES_ValueOffset, t0 ld2 t1 = [rpT1] add t2 = t0, t1 add out0 = IR_IndexHeader, t2 mov out1 = rpName mov out2 = rLength mov ap = sp br.call.sptk.many brp = LocateIndexEntry cmp.eq pt0, pt1 = v0, zero (pt0) br.cond.sptk.clr FindFile20 // Found it in the root! The result is already in eax. // Clean up the stack and return. // add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN FindFile20: // // We didn't find the index entry we want in the root, so we have to // crawl through the index allocation buffers. // movl rpT0 = IndexAllocation ld4 rIndexAllocation = [rpT0] cmp.eq pt0, pt1 = t0, zero (pt1) br.cond.sptk.clr FindFile30 // There is no index allocation attribute; clean up // the stack and return failure. // mov v0 = zero add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN FindFile30: // // Search the index allocation blocks for the name we want. // Instead of searching in tree order, we'll just start with // the last one and work our way backwards. // add rpT1 = NONRES_HighestVcn+LowPart, rIndexAllocation ld4 t1 = [rpT1] // t1 = HighestVcn add out0 = 1, t1 // out0 = clusters in attribute movl rpT2 = BytesPerCluster ld4 out1 = [rpT2] mov ap = sp br.call.sptk.many brp = Multiply // v0 = bytes in attribute mov out0 = v0 movl rpT0 = BytesPerIndexBlock ld4 out1 = [rpT0] movl out2 = Result movl out3 = Remainder mov ap = sp br.call.sptk.many brp = Divide // convert bytes to index blocks movl rpT0 = Result ld4 rBlock = [rpT0] // number of blocks to process FindFile40: cmp.eq pt0, pt1 = rBlock, zero (pt0) br.cond.sptk.clr FindFile90 add rBlock = -1, rBlock // rBlock == number of next block to process // // See if the block is in use; if not, go on to next. // mov out0 = rBlock mov ap = sp br.call.sptk.many brp = IsBlockInUse cmp.eq pt0, pt1 = v0, zero (pt1) br.cond.sptk.clr FindFile40 // v0 == zero if not in use // rBlock == block number to process // rLength == name length // rpName -> name to find // mov out0 = rBlock mov ap = sp br.call.sptk.many brp = ReadIndexBlock // rpName -> name to find // rLength == name length in characters // // Index buffer to search is in index allocation block buffer. // movl rpT0 = IndexBlockBuffer // t0 -> Index allocation block ld4 t0 = [rpT0] add out0 = IB_IndexHeader, t0 // out0 -> Index Header mov out1 = rpName mov out2 = rLength mov ap = sp br.call.sptk.many brp = LocateIndexEntry // v0 -> found entry cmp.eq pt0, pt1 = v0, zero (pt0) br.cond.sptk.clr FindFile40 // Found it! // // v0 -> Found entry // add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN FindFile90: // // Name not found. // mov v0 = zero // zero out v0. add sp = STACK_SCRATCH_AREA, sp // restore the original sp NESTED_RETURN NESTED_EXIT(FindFile) #ifdef DEBUG #ifdef NOT_YET_PORTED ;**************************************************************************** ; ; DumpIndexBlock - dumps the index block buffer ; DumpIndexBlock proc near SAVE_ALL mov esi, IndexBlockBuffer mov ecx, 20h ; dwords to dump DIB10: test ecx, 3 jnz DIB20 call DebugNewLine DIB20: lodsd call PrintNumber loop DIB10 RESTORE_ALL ret DumpIndexBlock endp ;**************************************************************************** ; ; DebugNewLine ; DebugNewLine proc near SAVE_ALL xor eax, eax xor ebx, ebx mov al, 0dh mov ah, 14 mov bx, 7 int 10h mov al, 0ah mov ah, 14 mov bx, 7 int 10h RESTORE_ALL ret DebugNewLine endp ;**************************************************************************** ; ; DebugPrint - Display a debug string. ; ; ENTRY: DS:SI -> null-terminated string ; ; USES: None. ; .286 DebugPrint proc near pusha DbgPr20: lodsb cmp al, 0 je DbgPr30 mov ah, 14 ; write teletype mov bx, 7 ; attribute int 10h ; print it jmp DbgPr20 DbgPr30: popa nop ret DebugPrint endp ;**************************************************************************** ; ; ; PrintNumber ; ; ENTRY: EAX == number to print ; ; PRESERVES ALL REGISTERS ; .386 PrintNumber proc near SAVE_ALL mov ecx, 8 ; number of digits in a DWORD PrintNumber10: mov edx, eax and edx, 0fh ; edx = lowest-order digit push edx ; put it on the stack shr eax, 4 ; drop low-order digit loop PrintNumber10 mov ecx, 8 ; number of digits on stack. PrintNumber20: pop eax ; eax = next digit to print cmp eax, 9 jg PrintNumber22 add eax, '0' jmp PrintNumber25 PrintNumber22: sub eax, 10 add eax, 'A' PrintNumber25: xor ebx, ebx mov ah, 14 mov bx, 7 int 10h loop PrintNumber20 ; Print a space to separate numbers mov al, ' ' mov ah, 14 mov bx, 7 int 10h RESTORE_ALL call Pause ret PrintNumber endp #endif NOT_YET_PORTED //**************************************************************************** // // Debug0 - Print debug string 0 -- used for checkpoints in mainboot // NESTED_ENTRY(Debug0) NESTED_SETUP(3,3,8,0) PROLOGUE_END add sp = STACK_SCRATCH_AREA, sp movl out0 = DbgString0 mov ap = sp br.call.sptk.many brp = BootErr$Print add sp = -STACK_SCRATCH_AREA, sp NESTED_RETURN NESTED_EXIT(Debug0) //**************************************************************************** // // Debug1 - Print debug string 1 -- // NESTED_ENTRY(Debug1) NESTED_SETUP(3,3,8,0) add sp = STACK_SCRATCH_AREA, sp movl out0 = DbgString1 mov ap = sp br.call.sptk.many brp = BootErr$Print add sp = -STACK_SCRATCH_AREA, sp NESTED_RETURN NESTED_EXIT(Debug1) //**************************************************************************** // // Debug2 - Print debug string 2 // NESTED_ENTRY(Debug2) NESTED_SETUP(3,3,8,0) add sp = -STACK_SCRATCH_AREA, sp movl out0 = DbgString2 mov ap = sp br.call.sptk.many brp = BootErr$Print add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN NESTED_EXIT(Debug2) //**************************************************************************** // // Debug3 - Print debug string 3 -- // NESTED_ENTRY(Debug3) NESTED_SETUP(3,3,8,0) PROLOGUE_END add sp = -STACK_SCRATCH_AREA, sp movl out0 = DbgString3 mov ap = sp br.call.sptk.many brp = BootErr$Print add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN NESTED_EXIT(Debug3) //**************************************************************************** // // Debug4 - Print debug string 4 // NESTED_ENTRY(Debug4) NESTED_SETUP(3,3,8,0) PROLOGUE_END add sp = -STACK_SCRATCH_AREA, sp movl out0 = DbgString4 mov ap = sp br.call.sptk.many brp = BootErr$Print add sp = STACK_SCRATCH_AREA, sp NESTED_RETURN NESTED_EXIT(Debug4) #ifdef NOT_YET_PORTED ;**************************************************************************** ; ; Pause - Pause for about 1/2 a second. Simply count until you overlap ; to zero. ; Pause proc near push eax mov eax, 0fff10000h PauseLoopy: inc eax or eax, eax jnz PauseLoopy pop eax ret Pause endp #endif NOT_YET_PORTED #endif DEBUG //************************************************************************* // // LoadIndexFrs - For the requested index type code locate and // load the associated Frs. // // ENTRY: in0 - requested index type code // in1 - Points to empty Frs buffer // // EXIT: v0 - points to offset in Frs buffer of requested index type // code or Zero if not found. // USES: All // NESTED_ENTRY(LoadIndexFrs) NESTED_SETUP(3,3,8,0) PROLOGUE_END rTypeCode = in0 // index type code rpFrs = in1 // pointer to FRS // // setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp movl out0 = ROOT_FILE_NAME_INDEX_NUMBER mov out1 = rpFrs mov ap = sp br.call.sptk.many brp = ReadFrs mov out0 = rpFrs // FRS to search mov out1 = rTypeCode // index type code movl out3 = index_name // Attribute name movl rpT0 = index_name_length // Attribute name length ld2 out2 = [rpT0] mov ap = sp br.call.sptk.many brp = LocateAttributeRecord cmp.eq pt0, pt1 = v0, zero (pt1) br.cond.sptk.clr LoadIndexFrs$Exit // if found in root return // // if not found in current Frs, search in attribute list // mov out0 = rTypeCode // type code mov out1 = rpFrs // FRS to search mov ap = sp br.call.sptk.many brp = SearchAttrList // search attribute list for FRN // of specified ($INDEX_ROOT, // $INDEX_ALLOCATION, or $BITMAP) // v0 - holds FRN for Frs, or Zero cmp.eq pt0, pt1 = v0, zero // if we cann't find it in attribute (pt0) br.cond.sptk.clr LoadIndexFrs$Exit // list then we are hosed // We should now have the File Record Number where the index for the // specified type code we are searching for is, load this into the // Frs target buffer. // // EAX - holds FRN // EBX - holds type code // EDI - holds target buffer mov out0 = v0 mov out1 = rTypeCode mov out2 = rpFrs mov ap = sp br.call.sptk.many brp = ReadFrs // // Now determine the offset in the Frs of the index // mov out0 = rpFrs // Frs to search mov out1 = rTypeCode // FRS Type Code movl rpT0 = index_name_length ld4 out2 = [rpT0] // Attribute name length movl out3 = index_name mov ap = sp br.call.sptk.many brp = LocateAttributeRecord // v0 - holds offset or Zero. LoadIndexFrs$Exit: add sp = STACK_SCRATCH_AREA, sp // restore original sp NESTED_RETURN NESTED_EXIT(LoadIndexFrs) //**************************************************************************** // // SearchAttrList // // Search the Frs for the attribute list. Then search the attribute list // for the specifed type code. When you find it return the FRN in the // attribute list entry found or Zero if no match found. // // ENTRY: in0 - type code to search attrib list for // in1 - Frs buffer holding head of attribute list // EXIT: v0 - FRN file record number to load, Zero if none. // // USES: All // NESTED_ENTRY(SearchAttrList) NESTED_SETUP(2,4,8,0) PROLOGUE_END rTypeCode = in0 rFrs = in1 rAttrList = loc2 // // Setup stack scratch area // add sp = -STACK_SCRATCH_AREA, sp mov out0 = rFrs mov out1 = $ATTRIBUTE_LIST // Attribute type code mov out2 = 0 // Attribute name length mov out3 = 0 // Attribute name mov ap = sp br.call.sptk.many brp = LocateAttributeRecord cmp.eq pt0, pt1 = v0, zero // If there's no Attribute list, (pt0) br.cond.sptk.clr SearchAttrList$NotFoundIndex1 // We are done // Read the attribute list. // eax -> attribute list attribute mov out0 = v0 // out0 -> attribute list attribute movl out1 = AttrList // out1 -> attribute list buffer mov ap = sp br.call.sptk.many brp = ReadWholeAttribute movl rpT0 = AttrList ld4 rAttrList = [rpT0] // rAttrList -> first attribute list entry // Now, traverse the attribute list looking for the entry for // the Index type code. // // rAttrList -> first attribute list entry // SearchAttrList$LookingForIndex: #ifdef DEBUG add rpT0 = ATTRLIST_AttributeTypeCode, rAttrList ld4 out0 = [rpT0] mov ap = sp br.call.sptk.many brp = PrintNumber add rpT0 = ATTRLIST_RecordLength, rAttrList ld4 out0 = [rpT0] mov ap = sp br.call.sptk.many brp = PrintNumber mov out0 = rAttrList mov ap = sp br.call.sptk.many brp = PrintNumber add out0 = ATTRLIST_Name, rAttrList mov ap = sp br.call.sptk.many brp = PrintName #endif add rpT0 = ATTRLIST_AttributeTypeCode, rpT0 ld4 t0 = [rpT0] cmp.eq pt0, pt1 = rTypeCode, t0 (pt0) br.cond.sptk.clr SearchAttrList$FoundIndex movl t1 = $END cmp.eq pt0, pt1 = t0, t1 // reached invalid attribute (pt0) br.cond.sptk.clr SearchAttrList$NotFoundIndex2 // so must be at end add rpT0 = ATTRLIST_RecordLength, rpT0 ld4 t0 = [rpT0] cmp.eq pt0, pt1 = 0, t0 (pt0) br.cond.sptk.clr SearchAttrList$NotFoundIndex2 //reached end of list and // nothing found add rAttrList = rAttrList, t0 // Next attribute br.cond.sptk.clr SearchAttrList$LookingForIndex SearchAttrList$FoundIndex: // found the index, return the FRN add rpT0 = ATTRLIST_SegmentReference, rAttrList add rpT0 = REF_SegmentNumberLowPart, rAttrList ld4 v0 = [rpT0] NESTED_RETURN SearchAttrList$NotFoundIndex1: // pop ecx SearchAttrList$NotFoundIndex2: mov v0 = zero add sp = -STACK_SCRATCH_AREA, sp // restore original sp NESTED_RETURN NESTED_EXIT(SearchAttrList) // // Boot message printing, relocated from sector 0 to sace space // BootErr2: // temporary label BootErr$fnf: movl out0 = TXT_MSG_SYSINIT_FILE_NOT_FD br.cond.sptk.clr BootErr2 BootErr$ntc: movl out0 = TXT_MSG_SYSINIT_NTLDR_CMPRS br.cond.sptk.clr BootErr2 TXT_MSG_SYSINIT_BOOT_ERROR: stringz "A disk read error occurred" TXT_MSG_SYSINIT_FILE_NOT_FD: stringz "NTLDR is missing" TXT_MSG_SYSINIT_NTLDR_CMPRS: stringz "NTLDR is compressed" TXT_MSG_SYSINIT_REBOOT: stringz "Press Ctrl+Alt+Del to restart" #ifdef DEBUG DbgString0 stringz "Debug Point 0" DbgString1 stringz "Debug Point 1" DbgString2 stringz "Debug Point 2" DbgString3 stringz "Debug Point 3" DbgString4 stringz "Debug Point 4" #endif DEBUG #ifdef NOT_YET_PORTED .errnz ($-_ntfsboot) GT 8192 ; org 8192 BootCode ends end _ntfsboot #endif NOT_YET_PORTED