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

/**
*** 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 ; <FATAL PROBLEM: main boot record exceeds available space>
org 8192
BootCode ends
end _ntfsboot
#endif NOT_YET_PORTED