mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 02:37:06 +00:00
![Victor Perevertkin](/assets/img/avatar_default.png)
Volume boot record is also implemented, it supports reading BTRFS tree structures with upto 64k node size. This support required to change all path in Free Loader to lowercase for better performance. CORE-13769
774 lines
19 KiB
ArmAsm
774 lines
19 KiB
ArmAsm
/*
|
|
* PROJECT: FreeLoader
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: BTRFS volume boot sector for FreeLoader
|
|
* COPYRIGHT: Copyright 2018 Victor Perevertkin (victor@perevertkin.ru)
|
|
*/
|
|
|
|
#include <asm.inc>
|
|
#include <freeldr/include/arch/pc/x86common.h>
|
|
|
|
.code16
|
|
|
|
CHUNK_MAP_OFFSET = HEX(8200) // max - 256 chunks (chunk is 24 bytes)
|
|
DATA_BUFFER_SEGMENT = HEX(9a0) // here we will store FS structures read from disk
|
|
|
|
FIRST_SUPERBLOCK_OFFSET = HEX(80) //in sectors
|
|
|
|
ROOT_TREE_OBJECTID = 1
|
|
EXTENT_TREE_OBJECTID = 2
|
|
CHUNK_TREE_OBJECTID = 3
|
|
DEV_TREE_OBJECTID = 4
|
|
FS_TREE_OBJECTID = 5
|
|
FIRST_CHUNK_TREE_OBJECTID = 256
|
|
|
|
DIR_ITEM_KEY = 84
|
|
EXTENT_DATA_KEY = 108
|
|
ROOT_ITEM_KEY = 132
|
|
EXTENT_ITEM_KEY = 168
|
|
CHUNK_ITEM_KEY = 228
|
|
|
|
BTRFS_FT_REG_FILE = 1
|
|
|
|
KEY_SIZE = 17
|
|
MAX_CHUNK_ITEMS = 255
|
|
|
|
start:
|
|
jmp short main
|
|
nop
|
|
// globals
|
|
ChunkMapSize:
|
|
.byte 0
|
|
BootDrive:
|
|
.byte 0
|
|
PartitionStartLBA:
|
|
.quad HEX(3f) // default value. Setup tool have to overwrite it upon installation
|
|
|
|
TreeRootAddress:
|
|
.quad 0
|
|
ChunkRootAddress:
|
|
.quad 0
|
|
FsRootAddress:
|
|
.quad 0
|
|
|
|
NodeSize:
|
|
.long 0
|
|
LeafSize:
|
|
.long 0
|
|
StripeSize:
|
|
.long 0
|
|
SysChunkSize:
|
|
.long 0
|
|
|
|
TreeRootLevel:
|
|
.byte 0
|
|
ChunkRootLevel:
|
|
.byte 0
|
|
FsRootLevel:
|
|
.byte 0
|
|
|
|
main:
|
|
xor eax, eax // Setup segment registers
|
|
mov ds, ax // Make DS correct
|
|
mov es, ax // Make ES correct
|
|
mov ss, ax // Make SS correct
|
|
mov sp, HEX(7c00) // Setup a stack
|
|
mov bp, sp
|
|
|
|
mov byte ptr [BootDrive], dl
|
|
|
|
// Now check if this computer supports extended reads. This boot sector will not work without it
|
|
CheckInt13hExtensions:
|
|
mov ah, HEX(41) // AH = 41h
|
|
mov bx, HEX(55aa) // BX = 55AAh
|
|
int HEX(13) // IBM/MS INT 13 Extensions - INSTALLATION CHECK
|
|
jc PrintDiskError // CF set on error (extensions not supported)
|
|
cmp bx, HEX(aa55) // BX = AA55h if installed
|
|
jne PrintDiskError
|
|
test cl, 1 // si = API subset support bitmap
|
|
jz PrintDiskError // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
|
|
|
|
LoadExtraBootCode:
|
|
// First we have to load our extra boot code into into memory at [0000:7e00h]
|
|
xor edx, edx
|
|
mov eax, 1 // read from the second sector - the first was already read
|
|
mov cx, 2
|
|
mov bx, HEX(7e00) // Read sector to [0000:7e00h]
|
|
call ReadSectors
|
|
|
|
mov ax, DATA_BUFFER_SEGMENT
|
|
mov es, ax
|
|
|
|
// reading superblock
|
|
xor edx, edx
|
|
mov eax, FIRST_SUPERBLOCK_OFFSET
|
|
mov cx, 8 // superblock is 0x1000 bytes - 8 sectors
|
|
xor bx, bx
|
|
call ReadSectors
|
|
|
|
push es // swapping segments for memory operations with superblock
|
|
push ds // ds must be DATA_BUFFER_SEGMENT
|
|
pop es
|
|
pop ds
|
|
|
|
mov si, HEX(40)
|
|
lea di, [btrfsSignature]
|
|
mov cx, 4 // magic string size (words)
|
|
repe cmpsw
|
|
je SignatureOk
|
|
|
|
mov si, wrongSignatureError
|
|
call PrintCustomError
|
|
|
|
SignatureOk:
|
|
// signature is ok - reading superblock data
|
|
add si, 8 // logical address of the root tree root
|
|
lea di, [TreeRootAddress]
|
|
mov cx, 8 // read both root tree root and chunk tree root
|
|
rep movsw
|
|
// read sizes
|
|
add si, HEX(34) // now pointing to nodesize field
|
|
lea di, [NodeSize] // read all 4 values
|
|
mov cx, 8
|
|
rep movsw
|
|
// read both levels
|
|
add si, 34
|
|
movsw // di is on the right place
|
|
|
|
push es
|
|
push ds
|
|
pop es
|
|
pop ds
|
|
|
|
// read sys chunk array
|
|
mov ax, HEX(32b) // sys_chunk_start
|
|
ReadSysChunk:
|
|
mov bx, ax
|
|
add bx, KEY_SIZE
|
|
push bx // start of the chunk
|
|
call InsertChunk
|
|
|
|
pop si
|
|
mov bx, word ptr es:[si+44] // number of stripes
|
|
shl bx, 5 // one stripe entry is 32 bytes
|
|
lea si, [si+bx+48] // 48 - size of the chunk
|
|
mov ax, si // save for next iteration
|
|
sub si, HEX(32b)
|
|
cmp si, word ptr [SysChunkSize] // the size cannot be more than 0xFFFF here so use word ptr
|
|
jb ReadSysChunk
|
|
|
|
jmp SetTreeRoots
|
|
|
|
|
|
// Reads logical sectors from disk
|
|
// INPUT:
|
|
// - ES:[BX] address at which the data will be stored
|
|
// - EDX:EAX logical sector number from which to read
|
|
// - CX number of sectors to read
|
|
// OUTPUT:
|
|
// - 512*CX bytes of memory at ES:[BX]
|
|
// LOCALS:
|
|
// - [bp-2] - LBASectorsRead
|
|
ReadSectors:
|
|
push bp
|
|
mov bp, sp
|
|
sub sp, 2
|
|
push es // we will spoil es register here
|
|
|
|
add eax, dword ptr [PartitionStartLBA]
|
|
adc edx, dword ptr [PartitionStartLBA+4]
|
|
ReadSectors_loop:
|
|
pushad // Save logical sector number & sector count
|
|
|
|
cmp cx, 8 // Maximum sectors per call is 0x7F, but VirtualBox correctly works with only 8
|
|
jbe ReadSectorsSetupDiskAddressPacket // If we are reading less than 9 sectors then just do the read
|
|
mov cx, 8 // Otherwise read only 8 sectors on this loop iteration
|
|
|
|
ReadSectorsSetupDiskAddressPacket:
|
|
mov word ptr [bp-2], cx
|
|
push edx
|
|
push eax // Put 64-bit logical block address on stack
|
|
push es // Put transfer segment on stack
|
|
push bx // Put transfer offset on stack
|
|
push cx // Set transfer count
|
|
push 16 // Set size of packet to 10h
|
|
mov si, sp // Setup disk address packet on stack
|
|
|
|
mov dl, byte ptr [BootDrive] // Drive number
|
|
mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read
|
|
int HEX(13) // Call BIOS
|
|
jc PrintDiskError // If the read failed then abort
|
|
|
|
add sp, 16 // Remove disk address packet from stack
|
|
|
|
popad // Restore sector count & logical sector number
|
|
|
|
push bx
|
|
movzx ebx, word ptr [bp-2]
|
|
add eax, ebx // Increment sector to read
|
|
adc edx, 0
|
|
shl ebx, 5 // Multiplying by 512=2^9 here.
|
|
// Shifting only by 5, because it goes to segment
|
|
// (segment will be shifter by another 4 when converted to real addr)
|
|
mov si, es
|
|
add si, bx // Setup read buffer for next sector
|
|
mov es, si
|
|
pop bx
|
|
|
|
sub cx, word ptr [bp-2]
|
|
jnz ReadSectors_loop // Read next sector
|
|
|
|
pop es
|
|
leave
|
|
ret
|
|
|
|
// Displays a disk error message
|
|
// And reboots
|
|
PrintDiskError:
|
|
mov si, msgDiskError // Bad boot disk message
|
|
PrintCustomError:
|
|
call PutChars // Display it
|
|
|
|
Reboot:
|
|
lea si, [msgAnyKey] // Press any key message
|
|
call PutChars // Display it
|
|
xor ax,ax
|
|
int HEX(16) // Wait for a keypress
|
|
int HEX(19) // Reboot
|
|
|
|
PutChars:
|
|
lodsb
|
|
or al,al
|
|
jz short Done
|
|
call PutCharsCallBios
|
|
jmp short PutChars
|
|
PutCharsCallBios:
|
|
mov ah, HEX(0e)
|
|
mov bx, HEX(07)
|
|
int HEX(10)
|
|
ret
|
|
Done:
|
|
mov al, HEX(0d)
|
|
call PutCharsCallBios
|
|
mov al, HEX(0a)
|
|
call PutCharsCallBios
|
|
ret
|
|
|
|
|
|
msgDiskError:
|
|
.asciz "Disk error"
|
|
msgAnyKey:
|
|
.asciz "Press any key to restart"
|
|
|
|
.org 510
|
|
.word HEX(aa55) // BootSector signature
|
|
|
|
SetTreeRoots:
|
|
// converting sizes to sectors. We dont need this sizes in bytes
|
|
shr dword ptr [NodeSize], 9
|
|
shr dword ptr [LeafSize], 9 // leafsize is deprecated
|
|
|
|
// finding FS_TREE root
|
|
|
|
// put the key on stack
|
|
xor eax, eax
|
|
push eax
|
|
push eax
|
|
dec sp
|
|
mov byte ptr [esp], ROOT_ITEM_KEY
|
|
push eax
|
|
push 0
|
|
push FS_TREE_OBJECTID
|
|
|
|
mov eax, dword ptr [TreeRootAddress]
|
|
mov edx, dword ptr [TreeRootAddress+4]
|
|
mov cl, byte ptr [TreeRootLevel]
|
|
|
|
call SearchTree
|
|
add sp, 17 // setting stack back
|
|
|
|
// bx - pointer to ROOT_ITEM
|
|
mov al, byte ptr es:[bx+238] // moving level
|
|
mov byte ptr [FsRootLevel], al
|
|
cld
|
|
|
|
mov eax, dword ptr es:[bx+176]
|
|
mov dword ptr [FsRootAddress], eax
|
|
mov eax, dword ptr es:[bx+176+4]
|
|
mov dword ptr [FsRootAddress+4], eax
|
|
|
|
// now we need to find DIR_ITEM_KEY with freeldr.sys hash
|
|
xor eax, eax
|
|
push eax
|
|
push dword ptr [filenameCrc]
|
|
dec sp
|
|
mov byte ptr [esp], DIR_ITEM_KEY
|
|
push eax
|
|
push 0
|
|
push 256 // root dir objectid
|
|
|
|
mov eax, dword ptr [FsRootAddress]
|
|
mov edx, dword ptr [FsRootAddress+4]
|
|
mov cl, byte ptr [FsRootLevel]
|
|
|
|
call SearchTree
|
|
add sp, 17 // setting stack back
|
|
|
|
// parsing DIR_ITEM
|
|
// bx - item addr
|
|
// cx - item length
|
|
mov ax, cx
|
|
|
|
push ds
|
|
push es
|
|
pop ds
|
|
pop es
|
|
ParseDirItem_loop:
|
|
cmp byte ptr [bx+29], BTRFS_FT_REG_FILE // checking dir_item type
|
|
jne ParseDirItem_loop_2
|
|
cmp word ptr [bx+27], 11 // checking name length
|
|
jne ParseDirItem_loop_2
|
|
lea si, [bx+30]
|
|
lea di, [freeldrFilename]
|
|
mov cx, 11
|
|
repe cmpsb
|
|
je FreeLdrFound
|
|
|
|
ParseDirItem_loop_2:
|
|
mov dx, 30
|
|
add dx, word ptr [bx+27]
|
|
cmp dx, ax
|
|
jae FreeLdrNotFound
|
|
add bx, dx
|
|
jmp ParseDirItem_loop
|
|
|
|
FreeLdrNotFound:
|
|
lea si, [notFoundError]
|
|
call PrintCustomError
|
|
|
|
FreeLdrFound:
|
|
// freeldr objectid is the first qword of DIR_ITEM structure
|
|
xor eax, eax
|
|
push eax
|
|
push eax
|
|
dec sp
|
|
mov byte ptr [esp], EXTENT_DATA_KEY
|
|
push dword ptr [bx+4]
|
|
push dword ptr [bx]
|
|
|
|
push es
|
|
pop ds
|
|
|
|
mov eax, dword ptr [FsRootAddress]
|
|
mov edx, dword ptr [FsRootAddress+4]
|
|
mov cl, byte ptr [FsRootLevel]
|
|
|
|
call SearchTree
|
|
add sp, 17
|
|
|
|
// here we have an EXTENT_ITEM with freeldr.sys
|
|
mov eax, dword ptr es:[bx+29]
|
|
shr eax, 9 // getting the number of clusters
|
|
mov cx, ax
|
|
push cx
|
|
|
|
lea di, [bx+21]
|
|
call ConvertAddress
|
|
pop cx
|
|
|
|
xor bx, bx
|
|
mov ds, bx
|
|
mov es, bx
|
|
mov bx, FREELDR_BASE
|
|
call ReadSectors
|
|
|
|
mov dl, byte ptr [BootDrive] // Load boot drive into DL
|
|
//mov dh, 0 // Load boot partition into DH (not needed, FreeLbr detects it itself)
|
|
|
|
/* Transfer execution to the bootloader */
|
|
ljmp16 0, FREELDR_BASE
|
|
|
|
|
|
// Insert chunk into chunk map (located at DS:[CHUNK_MAP_OFFSET])
|
|
// INPUT:
|
|
// - ES:[AX] chunk key address
|
|
// - ES:[BX] chunk item address
|
|
// TODO: add max items checking
|
|
InsertChunk:
|
|
push bx
|
|
push ax
|
|
push es
|
|
|
|
xor ecx, ecx // index
|
|
InsertChunk_loop:
|
|
std // numbers are little-engian, going right-to-left
|
|
mov si, CHUNK_MAP_OFFSET
|
|
lea si, [esi+ecx*8]
|
|
lea si, [esi+ecx*8]
|
|
lea si, [esi+ecx*8] // shift by 24 bytes
|
|
|
|
inc cx
|
|
cmp cl, byte ptr [ChunkMapSize]
|
|
ja InsertChunk_insert
|
|
|
|
lea si, [si+4] // set to the high dword of the 8-byte number
|
|
lea di, [eax+KEY_SIZE-4] // set to high dword of key's offset field (offset=logical addr)
|
|
|
|
cmpsd
|
|
jb InsertChunk_loop
|
|
cmpsd
|
|
jb InsertChunk_loop
|
|
lea si, [si+4] // set back to the beginning of key
|
|
|
|
// numbers are greater - need to insert Here
|
|
// shifting all to right by one element
|
|
InsertChunk_insert:
|
|
push si // here we will store new chunk
|
|
dec cx // because we increased it before comparison
|
|
|
|
mov dx, ds
|
|
mov es, dx
|
|
|
|
movzx eax, byte ptr [ChunkMapSize] // number of elements
|
|
|
|
mov si, CHUNK_MAP_OFFSET
|
|
lea si, [esi+eax*8]
|
|
lea si, [esi+eax*8]
|
|
lea si, [esi+eax*8-4] // setting to the high dword of the last element
|
|
|
|
mov di, si
|
|
add di, 20 // last byte of the last + 1 element (-4 bytes)
|
|
|
|
sub ax, cx
|
|
mov bx, 6
|
|
mul bx // 24/4 because of dwords
|
|
mov cx, ax // number of elements to shift
|
|
rep movsd
|
|
|
|
// finally we can write the element
|
|
cld
|
|
pop di // here we will store new chunk
|
|
|
|
pop ds // key-to-insert address segment
|
|
pop si // key-to-insert address
|
|
add si, 9 // move to 'offset' field
|
|
movsd
|
|
movsd // logical address loaded!
|
|
|
|
// time for stripes
|
|
pop si // chunk item address, length is the first field
|
|
movsd
|
|
movsd
|
|
|
|
add si, 48 // move to offset of the first stripe (we read only first one)
|
|
movsd
|
|
movsd
|
|
|
|
push es // swapping segments back to original
|
|
push ds
|
|
pop es
|
|
pop ds
|
|
|
|
inc byte ptr [ChunkMapSize]
|
|
ret
|
|
|
|
|
|
// Searches a key in a BTRFS tree
|
|
// INPUT:
|
|
// - [bp+4] BTRFS key to find
|
|
// - EDX:EAX logical address of root header
|
|
// - CL leaf node level
|
|
// OUTPUT:
|
|
// - ES:[SI] pointer to found item's key
|
|
// - ES:[BX] pointer to found item
|
|
// - ECX item length
|
|
// LOCALS:
|
|
// - [bp-8] - block number/current node offset
|
|
// - [bp-9] - current level
|
|
SearchTree:
|
|
push bp
|
|
mov bp, sp
|
|
sub sp, 9 // set stack frame
|
|
|
|
mov dword ptr [bp-4], edx
|
|
mov dword ptr [bp-8], eax
|
|
mov byte ptr [bp-9], cl
|
|
|
|
SearchTree_readHeader:
|
|
push ss
|
|
pop es
|
|
|
|
lea di, [bp-8]
|
|
call ConvertAddress
|
|
// LBA is in edx:eax now
|
|
mov bx, DATA_BUFFER_SEGMENT
|
|
mov es, bx
|
|
xor bx, bx
|
|
|
|
mov cl, byte ptr [bp-9]
|
|
test cl, cl
|
|
jz SearchTree_readLeaf
|
|
// read node
|
|
mov cx, word ptr [NodeSize] // word btr because we cannot read more than 65536 bytes yet
|
|
call ReadSectors // reading node to the memory
|
|
|
|
// every node begins with header
|
|
//mov ax, word ptr [DATA_BUFFER_OFFSET + HEX(60)] // number of items in this leaf
|
|
mov cx, -1 // index
|
|
// finding the key
|
|
SearchTree_findLoop_1:
|
|
inc cx
|
|
cmp word ptr es:[HEX(60)], cx
|
|
je SearchTree_findLoop_1_equal // we are at the end - taking the last element
|
|
|
|
lea si, [bp+4] // key to find
|
|
mov di, HEX(65) // first key in leaf
|
|
mov ax, 33
|
|
call CompareKeys
|
|
jb SearchTree_findLoop_1
|
|
je SearchTree_findLoop_1_equal
|
|
sub di, 33 // setting to previous element
|
|
|
|
// we are here if key is equal or greater
|
|
// (si points to the start of the key)
|
|
SearchTree_findLoop_1_equal:
|
|
push ds
|
|
push es
|
|
pop ds
|
|
pop es
|
|
|
|
lea si, [di+17]
|
|
lea di, [bp-8]
|
|
movsd
|
|
movsd
|
|
|
|
push es
|
|
pop ds
|
|
|
|
dec byte ptr [bp-9] // decrement level
|
|
jmp SearchTree_readHeader
|
|
|
|
SearchTree_readLeaf:
|
|
mov cx, word ptr [LeafSize]
|
|
call ReadSectors
|
|
|
|
// every node begins with header
|
|
//mov ax, word ptr [DATA_BUFFER_OFFSET + HEX(60)] // number of items in this leaf
|
|
mov cx, -1 // index
|
|
// finding the key
|
|
SearchTree_findLoop_2:
|
|
inc cx
|
|
cmp word ptr es:[HEX(60)], cx
|
|
je SearchTree_foundEqual
|
|
|
|
lea si, [bp+4] // key to find
|
|
mov di, HEX(65) // first key in leaf
|
|
mov ax, 25
|
|
call CompareKeys
|
|
jb SearchTree_findLoop_2
|
|
je SearchTree_foundEqual
|
|
|
|
// set pointer to previous element if greater
|
|
sub di, 25
|
|
|
|
SearchTree_foundEqual:
|
|
// found equal or greater key
|
|
mov bx, word ptr es:[di+17] // data offset relative to end of header
|
|
mov cx, word ptr es:[di+21] // data size
|
|
add bx, HEX(65) // end of header
|
|
mov si, di
|
|
|
|
leave
|
|
ret
|
|
|
|
SearchTree_notFound:
|
|
xor ecx, ecx // return ecx=0 if nothing found
|
|
|
|
leave
|
|
ret
|
|
|
|
|
|
// Converts logical address into physical LBA addr using chunk map
|
|
// INPUT:
|
|
// - ES:[DI] pointer to logical addr
|
|
// OUTPUT:
|
|
// - EDX:EAX target LBA
|
|
// - sets ZF on failure
|
|
ConvertAddress:
|
|
// NOTE: SearchTree will overwrite data buffer area and our logical addr will be erased!
|
|
// so putting it on stack
|
|
push dword ptr es:[di+4]
|
|
push dword ptr es:[di]
|
|
|
|
mov bl, 1 // indicates first try. On second try BL must be set to 0
|
|
ConvertAddress_secondTry:
|
|
push ds
|
|
pop es
|
|
xor ecx, ecx // set index to 0
|
|
ConvertAddress_loop:
|
|
cmp cl, byte ptr [ChunkMapSize]
|
|
jae ConvertAddress_checkInclusion // greater chunk is not found in chunk map - checking the last one
|
|
|
|
std // numbers are little-engian, going right-to-left
|
|
mov si, CHUNK_MAP_OFFSET
|
|
lea si, [esi+ecx*8]
|
|
lea si, [esi+ecx*8]
|
|
lea si, [esi+ecx*8] // shift by 24 bytes
|
|
|
|
lea di, [esp+4] // set to the second dword the 8-byte number
|
|
lea si, [si+4]
|
|
inc cl
|
|
|
|
cmpsd
|
|
jb ConvertAddress_loop
|
|
cmpsd
|
|
jb ConvertAddress_loop
|
|
|
|
ConvertAddress_checkInclusion:
|
|
dec cl
|
|
cld
|
|
// found chunk map item, checking inclusion with length
|
|
mov si, CHUNK_MAP_OFFSET
|
|
lea si, [esi+ecx*8]
|
|
lea si, [esi+ecx*8]
|
|
lea si, [esi+ecx*8] // shift by 24 bytes
|
|
|
|
// logical_addr + length
|
|
mov eax, dword ptr [si] // low dword of address
|
|
mov edx, dword ptr [si+4] // high dword of address
|
|
add eax, dword ptr [si+8] // low dword of length
|
|
adc edx, dword ptr [si+12] // high dword of length
|
|
// edx:eax is the end of the chunk
|
|
|
|
// (logical_addr + length) - addr_to_find
|
|
cmp edx, dword ptr [esp+4]
|
|
ja ConvertAddress_found
|
|
cmp eax, dword ptr [esp]
|
|
ja ConvertAddress_found // address is greater than end of the chunk
|
|
test bl, bl
|
|
jnz ConvertAddress_notFound
|
|
ret 8
|
|
|
|
ConvertAddress_found:
|
|
// found chunk. Calculating the address
|
|
// addr_to_find - logical_addr
|
|
pop eax // low dword of addr_to_find
|
|
pop edx // high dword of addr_to_find
|
|
sub eax, dword ptr [si]
|
|
sbb edx, dword ptr [si+4]
|
|
// (addr_to_find - logical_addr) + physical_addr
|
|
add eax, dword ptr [si+16]
|
|
adc edx, dword ptr [si+20]
|
|
|
|
// edx:eax is physical address. Converting to LBA (shifting by 9 bits)
|
|
shrd eax, edx, 9
|
|
shr edx, 9
|
|
inc bl // clears ZF (bl is 0 or 1 here)
|
|
ret
|
|
|
|
ConvertAddress_notFound:
|
|
// offset is alredy on stack
|
|
//push dword ptr [esp+4]
|
|
//push dword ptr [esp]
|
|
dec sp
|
|
mov byte ptr [esp], CHUNK_ITEM_KEY
|
|
data32 push 0
|
|
push 0
|
|
push FIRST_CHUNK_TREE_OBJECTID
|
|
|
|
mov eax, dword ptr [ChunkRootAddress]
|
|
mov edx, dword ptr [ChunkRootAddress+4]
|
|
mov cl, byte ptr [ChunkRootLevel]
|
|
|
|
call SearchTree
|
|
add sp, 9 // setting stack back
|
|
|
|
mov ax, si // ES:[SI] - found key pointer
|
|
call InsertChunk
|
|
|
|
mov bl, 0 // indicates second try
|
|
jmp ConvertAddress_secondTry
|
|
|
|
|
|
// Compare key (key1) with key in array identified by base and index (key2)
|
|
// INPUT:
|
|
// - DS:[SI] key1 pointer
|
|
// - ES:[DI] start of the array
|
|
// - AX size of one key in array
|
|
// - CX key index
|
|
// OUTPUT:
|
|
// - DS:[SI] key1 pointer
|
|
// - ES:[DI] key2 pointer
|
|
// - sets flags according to comparison
|
|
CompareKeys:
|
|
//xchg si, di
|
|
|
|
mul cx
|
|
add di, ax
|
|
push ds
|
|
push si
|
|
push es
|
|
push di
|
|
|
|
// must be replaced for proper flags after cmps
|
|
push ds
|
|
push es
|
|
pop ds
|
|
pop es
|
|
xchg si, di
|
|
|
|
lea si, [si+4] // key in array
|
|
lea di, [di+4] // searchable key
|
|
std
|
|
|
|
// comparing objectid
|
|
cmpsd
|
|
jne CompareKeys_end
|
|
cmpsd
|
|
jne CompareKeys_end
|
|
// comparing type
|
|
lea si, [si+12]
|
|
lea di, [di+12]
|
|
|
|
cmpsb
|
|
jne CompareKeys_end
|
|
// comparing offset
|
|
lea si, [si+1+1+4]
|
|
lea di, [di+1+1+4]
|
|
|
|
cmpsd
|
|
jne CompareKeys_end
|
|
cmpsd
|
|
CompareKeys_end:
|
|
cld
|
|
pop di
|
|
pop es
|
|
pop si
|
|
pop ds
|
|
ret
|
|
|
|
|
|
|
|
btrfsSignature:
|
|
.ascii "_BHRfS_M"
|
|
|
|
//.org 1022
|
|
// .word HEX(aa55)
|
|
|
|
|
|
wrongSignatureError:
|
|
.asciz "BTRFS read error"
|
|
MaxItemsError:
|
|
.asciz "Max items error"
|
|
filenameCrc:
|
|
.long HEX(68cba33d) // computed hashsum of "freeldr.sys"
|
|
freeldrFilename:
|
|
.ascii "freeldr.sys"
|
|
notFoundError:
|
|
.asciz "NFE"
|
|
.org 1534
|
|
.word HEX(aa55)
|
|
.endcode16
|
|
|
|
END
|