[FREELDR][BTRFS] Implemented BTRFS support in Free Loader. Now it supports case-insensitive path lookup, symlink folowing and reading uncompressed files.

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
This commit is contained in:
Victor Perevertkin 2018-06-19 04:00:52 +03:00 committed by Pierre Schweitzer
parent 07bc92f740
commit 3b69eee7a6
11 changed files with 2541 additions and 9 deletions

View file

@ -6,6 +6,7 @@ if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64")
CreateBootSectorTarget(fat ${CMAKE_CURRENT_SOURCE_DIR}/fat.S ${CMAKE_CURRENT_BINARY_DIR}/fat.bin 7c00)
CreateBootSectorTarget(fat32 ${CMAKE_CURRENT_SOURCE_DIR}/fat32.S ${CMAKE_CURRENT_BINARY_DIR}/fat32.bin 7c00)
CreateBootSectorTarget(btrfsvbr ${CMAKE_CURRENT_SOURCE_DIR}/btrfs.S ${CMAKE_CURRENT_BINARY_DIR}/btrfs.bin 7c00)
## New versions using FATY.S (experimental)
# add_definitions(-DFAT12)
@ -24,6 +25,7 @@ if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64")
add_cd_file(TARGET dosmbr DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/dosmbr.bin FOR bootcd regtest)
add_cd_file(TARGET ext2 DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/ext2.bin FOR bootcd regtest)
add_cd_file(TARGET btrfsvbr DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/btrfs.bin FOR bootcd regtest)
add_cd_file(TARGET fat DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/fat.bin FOR bootcd regtest)
add_cd_file(TARGET fat32 DESTINATION loader NO_CAB FILE ${CMAKE_CURRENT_BINARY_DIR}/fat32.bin FOR bootcd regtest)
add_cd_file(TARGET isoboot DESTINATION loader NO_CAB NOT_IN_HYBRIDCD FILE ${CMAKE_CURRENT_BINARY_DIR}/isoboot.bin FOR all hybridcd)

View file

@ -0,0 +1,773 @@
/*
* 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

View file

@ -37,6 +37,7 @@ list(APPEND FREELDR_BOOTLIB_COMMON_SOURCE
lib/peloader.c
lib/comm/rs232.c
## add KD support
lib/fs/btrfs.c
lib/fs/ext2.c
lib/fs/fat.c
lib/fs/fs.c

View file

@ -188,7 +188,7 @@ DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
if (Position->LowPart & (Context->SectorSize - 1))
return EINVAL;
Context->SectorNumber = (ULONG)(Position->QuadPart / Context->SectorSize);
Context->SectorNumber = Position->QuadPart / Context->SectorSize;
return ESUCCESS;
}

View file

@ -89,6 +89,7 @@
#include <fs/ntfs.h>
#include <fs/iso.h>
#include <fs/pxe.h>
#include <fs/btrfs.h>
/* UI support */
#include <ui/gui.h>

View file

@ -0,0 +1,418 @@
/*
* PROJECT: FreeLoader
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: BTRFS support for FreeLoader
* COPYRIGHT: Copyright 2018 Victor Perevertkin (victor@perevertkin.ru)
*/
/* Structures were taken from u-boot, https://github.com/u-boot/u-boot/tree/master/fs/btrfs */
#pragma once
typedef UCHAR u8;
typedef USHORT u16;
typedef ULONG32 u32;
typedef ULONG64 u64;
/* type that store on disk, but it is same as cpu type for i386 arch */
typedef u8 __u8;
typedef u16 __u16;
typedef u32 __u32;
typedef u64 __u64;
#include <fs/crc32c.h>
#define btrfs_crc32c(name, len) crc32c_le((u32)~1, name, len)
#define BTRFS_SUPER_INFO_OFFSET (64 * 1024)
#define BTRFS_SUPER_INFO_SIZE 4096
#define BTRFS_MAX_LEAF_SIZE 4096
#define BTRFS_BLOCK_SHIFT 12
#define BTRFS_BLOCK_SIZE (1 << BTRFS_BLOCK_SHIFT)
#define BTRFS_SUPER_MIRROR_MAX 3
#define BTRFS_SUPER_MIRROR_SHIFT 12
#define BTRFS_CSUM_SIZE 32
#define BTRFS_FSID_SIZE 16
#define BTRFS_LABEL_SIZE 256
#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048
#define BTRFS_UUID_SIZE 16
#define BTRFS_VOL_NAME_MAX 255
#define BTRFS_NAME_MAX 255
#define BTRFS_MAGIC "_BHRfS_M"
#define BTRFS_MAGIC_L 8
#define BTRFS_MAGIC_N 0x4d5f53665248425fULL
#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
#define BTRFS_DEV_ITEM_KEY 216
#define BTRFS_CHUNK_ITEM_KEY 228
#define BTRFS_ROOT_REF_KEY 156
#define BTRFS_ROOT_ITEM_KEY 132
#define BTRFS_EXTENT_DATA_KEY 108
#define BTRFS_DIR_ITEM_KEY 84
#define BTRFS_DIR_INDEX_KEY 96
#define BTRFS_INODE_ITEM_KEY 1
#define BTRFS_INODE_REF_KEY 12
#define BTRFS_EXTENT_TREE_OBJECTID 2ULL
#define BTRFS_FS_TREE_OBJECTID 5ULL
#define BTRFS_FIRST_FREE_OBJECTID 256ULL
#define BTRFS_LAST_FREE_OBJECTID -256ULL
#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
#define BTRFS_FILE_EXTENT_INLINE 0
#define BTRFS_FILE_EXTENT_REG 1
#define BTRFS_FILE_EXTENT_PREALLOC 2
#define BTRFS_MAX_LEVEL 8
#define BTRFS_MAX_CHUNK_ENTRIES 256
#define BTRFS_DEV_ITEMS_OBJECTID 1ULL
#define BTRFS_FT_REG_FILE 1
#define BTRFS_FT_DIR 2
#define BTRFS_FT_SYMLINK 7
#define BTRFS_FT_XATTR 8
#define BTRFS_FT_MAX 9
#define BTRFS_COMPRESS_NONE 0
#define BTRFS_COMPRESS_ZLIB 1
#define BTRFS_COMPRESS_LZO 2
#define ROOT_DIR_WORD 0x002f
#include <pshpack1.h>
struct btrfs_disk_key {
__u64 objectid;
__u8 type;
__u64 offset;
};
struct btrfs_header {
/* these first four must match the super block */
__u8 csum[BTRFS_CSUM_SIZE];
__u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
__u64 bytenr; /* which block this node is supposed to live in */
__u64 flags;
/* allowed to be different from the super from here on down */
__u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
__u64 generation;
__u64 owner;
__u32 nritems;
__u8 level;
};
struct btrfs_item {
struct btrfs_disk_key key;
__u32 offset;
__u32 size;
};
struct btrfs_leaf {
struct btrfs_header header;
struct btrfs_item items[];
};
struct btrfs_key_ptr {
struct btrfs_disk_key key;
__u64 blockptr;
__u64 generation;
};
struct btrfs_node {
struct btrfs_header header;
struct btrfs_key_ptr ptrs[];
};
struct btrfs_dev_item {
/* the internal btrfs device id */
__u64 devid;
/* size of the device */
__u64 total_bytes;
/* bytes used */
__u64 bytes_used;
/* optimal io alignment for this device */
__u32 io_align;
/* optimal io width for this device */
__u32 io_width;
/* minimal io size for this device */
__u32 sector_size;
/* type and info about this device */
__u64 type;
/* expected generation for this device */
__u64 generation;
/*
* starting byte of this partition on the device,
* to allow for stripe alignment in the future
*/
__u64 start_offset;
/* grouping information for allocation decisions */
__u32 dev_group;
/* seek speed 0-100 where 100 is fastest */
__u8 seek_speed;
/* bandwidth 0-100 where 100 is fastest */
__u8 bandwidth;
/* btrfs generated uuid for this device */
__u8 uuid[BTRFS_UUID_SIZE];
/* uuid of FS who owns this device */
__u8 fsid[BTRFS_UUID_SIZE];
};
struct btrfs_stripe {
__u64 devid;
__u64 offset;
__u8 dev_uuid[BTRFS_UUID_SIZE];
};
struct btrfs_chunk {
/* size of this chunk in bytes */
__u64 length;
/* objectid of the root referencing this chunk */
__u64 owner;
__u64 stripe_len;
__u64 type;
/* optimal io alignment for this chunk */
__u32 io_align;
/* optimal io width for this chunk */
__u32 io_width;
/* minimal io size for this chunk */
__u32 sector_size;
/* 2^16 stripes is quite a lot, a second limit is the size of a single
* item in the btree
*/
__u16 num_stripes;
/* sub stripes only matter for raid10 */
__u16 sub_stripes;
struct btrfs_stripe stripe;
/* additional stripes go here */
};
struct btrfs_inode_ref {
__u64 index;
__u16 name_len;
/* name goes here */
};
struct btrfs_timespec {
__u64 sec;
__u32 nsec;
};
struct btrfs_inode_item {
/* nfs style generation number */
__u64 generation;
/* transid that last touched this inode */
__u64 transid;
__u64 size;
__u64 nbytes;
__u64 block_group;
__u32 nlink;
__u32 uid;
__u32 gid;
__u32 mode;
__u64 rdev;
__u64 flags;
/* modification sequence number for NFS */
__u64 sequence;
/*
* a little future expansion, for more than this we can
* just grow the inode item and version it
*/
__u64 reserved[4];
struct btrfs_timespec atime;
struct btrfs_timespec ctime;
struct btrfs_timespec mtime;
struct btrfs_timespec otime;
};
struct btrfs_dir_item {
struct btrfs_disk_key location;
__u64 transid;
__u16 data_len;
__u16 name_len;
__u8 type;
};
struct btrfs_root_item {
struct btrfs_inode_item inode;
__u64 generation;
__u64 root_dirid;
__u64 bytenr;
__u64 byte_limit;
__u64 bytes_used;
__u64 last_snapshot;
__u64 flags;
__u32 refs;
struct btrfs_disk_key drop_progress;
__u8 drop_level;
__u8 level;
};
struct btrfs_root_ref {
__u64 dirid;
__u64 sequence;
__u16 name_len;
};
struct btrfs_file_extent_item {
/*
* transaction id that created this extent
*/
__u64 generation;
/*
* max number of bytes to hold this extent in ram
* when we split a compressed extent we can't know how big
* each of the resulting pieces will be. So, this is
* an upper limit on the size of the extent in ram instead of
* an exact limit.
*/
__u64 ram_bytes;
/*
* 32 bits for the various ways we might encode the data,
* including compression and encryption. If any of these
* are set to something a given disk format doesn't understand
* it is treated like an incompat flag for reading and writing,
* but not for stat.
*/
__u8 compression;
__u8 encryption;
__u16 other_encoding; /* spare for later use */
/* are we inline data or a real extent? */
__u8 type;
/*
* disk space consumed by the extent, checksum blocks are included
* in these numbers
*
* At this offset in the structure, the inline extent data start.
*/
__u64 disk_bytenr;
__u64 disk_num_bytes;
/*
* the logical offset in file blocks (no csums)
* this extent record is for. This allows a file extent to point
* into the middle of an existing extent on disk, sharing it
* between two snapshots (useful if some bytes in the middle of the
* extent have changed
*/
__u64 offset;
/*
* the logical number of file blocks (no csums included). This
* always reflects the size uncompressed and without encoding.
*/
__u64 num_bytes;
};
struct btrfs_super_block {
__u8 csum[BTRFS_CSUM_SIZE];
/* the first 4 fields must match struct btrfs_header */
__u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
__u64 bytenr; /* this block number */
__u64 flags;
/* allowed to be different from the btrfs_header from here own down */
__u64 magic;
__u64 generation;
__u64 root;
__u64 chunk_root;
__u64 log_root;
/* this will help find the new super based on the log root */
__u64 log_root_transid;
__u64 total_bytes;
__u64 bytes_used;
__u64 root_dir_objectid;
__u64 num_devices;
__u32 sectorsize;
__u32 nodesize;
__u32 __unused_leafsize;
__u32 stripesize;
__u32 sys_chunk_array_size;
__u64 chunk_root_generation;
__u64 compat_flags;
__u64 compat_ro_flags;
__u64 incompat_flags;
__u16 csum_type;
__u8 root_level;
__u8 chunk_root_level;
__u8 log_root_level;
struct btrfs_dev_item dev_item;
char label[BTRFS_LABEL_SIZE];
__u64 cache_generation;
__u64 uuid_tree_generation;
/* future expansion */
__u64 reserved[30];
__u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
};
#include <poppack.h>
union tree_buf {
struct btrfs_header header;
struct btrfs_node node;
struct btrfs_leaf leaf;
};
/* remember how we get to a node/leaf */
struct btrfs_path {
u64 offsets[BTRFS_MAX_LEVEL];
int itemsnr[BTRFS_MAX_LEVEL];
int slots[BTRFS_MAX_LEVEL];
/* remember whole last leaf */
union tree_buf *tree_buf;
};
/* store logical offset to physical offset mapping */
struct btrfs_chunk_map_item {
u64 logical;
u64 length;
u64 devid;
u64 physical;
};
struct btrfs_chunk_map {
struct btrfs_chunk_map_item *map;
u32 map_length;
u32 cur_length;
};
typedef struct {
u64 inr;
u64 position;
struct btrfs_inode_item inode;
} btrfs_file_info, * pbtrfs_file_info;
const DEVVTBL* BtrFsMount(ULONG DeviceId);

View file

@ -0,0 +1,52 @@
/*
* Copied from Linux kernel crypto/crc32c.c
* Copyright (c) 2004 Cisco Systems, Inc.
* Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#pragma once
/*
* This is the CRC-32C table
* Generated with:
* width = 32 bits
* poly = 0x1EDC6F41
* reflect input bytes = true
* reflect output bytes = true
*/
static u32 crc32c_table[256];
/*
* Steps through buffer one byte at at time, calculates reflected
* crc using table.
*/
static inline u32 crc32c_le(u32 crc, const char *data, size_t length)
{
while (length--)
crc = crc32c_table[(u8)(crc ^ *data++)] ^ (crc >> 8);
return crc;
}
static inline void btrfs_init_crc32c(void)
{
int i, j;
u32 v;
const u32 poly = 0x82F63B78; /* Bit-reflected CRC32C polynomial */
for (i = 0; i < 256; i++) {
v = i;
for (j = 0; j < 8; j++) {
v = (v >> 1) ^ ((v & 1) ? poly : 0);
}
crc32c_table[i] = v;
}
}

File diff suppressed because it is too large Load diff

View file

@ -152,6 +152,8 @@ ARC_STATUS ArcOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
if (!FileData[DeviceId].FileFuncTable)
#endif
FileData[DeviceId].FileFuncTable = FatMount(DeviceId);
if (!FileData[DeviceId].FileFuncTable)
FileData[DeviceId].FileFuncTable = BtrFsMount(DeviceId);
#ifndef _M_ARM
if (!FileData[DeviceId].FileFuncTable)
FileData[DeviceId].FileFuncTable = NtfsMount(DeviceId);

View file

@ -488,15 +488,15 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion,
/* Initialize SystemRoot\System32 path */
strcpy(DirPath, BootPath);
strcat(DirPath, "SYSTEM32\\");
strcat(DirPath, "system32\\");
//
// TODO: Parse also the separate INI values "Kernel=" and "Hal="
//
/* Default KERNEL and HAL file names */
strcpy(KernelFileName, "NTOSKRNL.EXE");
strcpy(HalFileName , "HAL.DLL");
strcpy(KernelFileName, "ntoskrnl.exe");
strcpy(HalFileName , "hal.dll");
/* Find any /KERNEL= or /HAL= switch in the boot options */
Options = BootOptions;
@ -544,10 +544,10 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion,
TRACE("Kernel file = '%s' ; HAL file = '%s'\n", KernelFileName, HalFileName);
/* Load the Kernel */
LoadModule(LoaderBlock, DirPath, KernelFileName, "NTOSKRNL.EXE", LoaderSystemCode, KernelDTE, 30);
LoadModule(LoaderBlock, DirPath, KernelFileName, "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
/* Load the HAL */
LoadModule(LoaderBlock, DirPath, HalFileName, "HAL.DLL", LoaderHalCode, &HalDTE, 45);
LoadModule(LoaderBlock, DirPath, HalFileName, "hal.dll", LoaderHalCode, &HalDTE, 45);
/* Load the Kernel Debugger Transport DLL */
if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
@ -630,7 +630,7 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion,
* Load the transport DLL. Override the base DLL name of the
* loaded transport DLL to the default "KDCOM.DLL" name.
*/
LoadModule(LoaderBlock, DirPath, KdTransportDllName, "KDCOM.DLL", LoaderSystemCode, &KdComDTE, 60);
LoadModule(LoaderBlock, DirPath, KdTransportDllName, "kdcom.dll", LoaderSystemCode, &KdComDTE, 60);
}
}

View file

@ -126,7 +126,7 @@ BOOLEAN WinLdrInitSystemHive(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
// FIXME: For now we only try system
strcpy(SearchPath, DirectoryPath);
strcat(SearchPath, "SYSTEM32\\CONFIG\\");
strcat(SearchPath, "system32\\config\\");
Success = WinLdrLoadSystemHive(LoaderBlock, SearchPath, "SYSTEM");
// Fail if failed...
@ -173,7 +173,7 @@ BOOLEAN WinLdrScanSystemHive(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
// Load NLS data
strcpy(SearchPath, DirectoryPath);
strcat(SearchPath, "SYSTEM32\\");
strcat(SearchPath, "system32\\");
Success = WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
TRACE("NLS data loading %s\n", Success ? "successful" : "failed");