summaryrefslogtreecommitdiffstats
path: root/debian/grub-extras/ntldr-img/ntfsbs.S
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:52 +0000
commitca67b09c015d4af3ae3cce12aa72e60941dbb8b5 (patch)
treeb7316d7b06c373e08dabb79a2c866c568e08f49e /debian/grub-extras/ntldr-img/ntfsbs.S
parentAdding upstream version 2.06. (diff)
downloadgrub2-debian.tar.xz
grub2-debian.zip
Adding debian version 2.06-13+deb12u1.debian/2.06-13+deb12u1debian
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--debian/grub-extras/ntldr-img/ntfsbs.S1508
1 files changed, 1508 insertions, 0 deletions
diff --git a/debian/grub-extras/ntldr-img/ntfsbs.S b/debian/grub-extras/ntldr-img/ntfsbs.S
new file mode 100644
index 0000000..039caf3
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/ntfsbs.S
@@ -0,0 +1,1508 @@
+/*
+ * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
+ * Copyright (C) 2007 Bean (bean123@126.com)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* NTFS boot sector for loading GRLDR , written by bean
+ *
+ * This file can be compiled as standaolne boot sector, or it can be embeded in
+ * GRLDR.MBR at 0xA00 , right after the ext2 boot sector
+ *
+ * To compile the standalone ntfsbs.bin:
+ * gcc -c -o ntfsbs.o ntfsbs.S
+ * gcc -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00 -o ntfsbs_exec ntfsbs.o
+ * objcopy -O binary ntfsbs_exec ntfsbs.bin
+ *
+ * To install the standalone ntfsbs.bin:
+ * grubinst --restore=ntfsbs.bin DEVICE_OR_FILE
+ *
+ * Where DEVICE_OR_FILE specify a NTFS partition
+ *
+ * Limitations:
+ * 1. Don't support >1K MFT record size, >4K INDEX record size
+ * 2. Don't support encrypted file
+ * 3. Don't support >4K non-resident attribute list and $BITMAP
+ *
+ */
+
+#ifndef INSIDE_GRLDR
+
+ .text
+
+ .code16
+#endif
+
+#define AT_STANDARD_INFORMATION 0x10
+#define AT_ATTRIBUTE_LIST 0x20
+#define AT_FILENAME 0x30
+#define AT_OBJECT_ID 0x40
+#define AT_SECURITY_DESCRIPTOR 0x50
+#define AT_VOLUME_NAME 0x60
+#define AT_VOLUME_INFORMATION 0x70
+#define AT_DATA 0x80
+#define AT_INDEX_ROOT 0x90
+#define AT_INDEX_ALLOCATION 0xA0
+#define AT_BITMAP 0xB0
+#define AT_SYMLINK 0xC0
+#define AT_EA_INFORMATION 0xD0
+#define AT_EA 0xE0
+
+#define MAX_MFT_SIZE 1 // 1<<(1+9) = 1024
+#define MAX_IDX_SIZE 3 // 1<<(3+9) = 4096
+
+#define LOADSEG_NT 0x2000
+
+#define MMFT_BASE 0x2000
+#define MMFT_EMFT (MMFT_BASE +1024)
+#define MMFT_EBUF (MMFT_BASE + 2048)
+
+#define CMFT_BASE (MMFT_BASE + 6144)
+#define CMFT_EMFT (CMFT_BASE + 1024)
+#define CMFT_EBUF (CMFT_BASE + 2048)
+
+#define INDX_BASE (CMFT_BASE + 6144)
+
+#define SBUF_BASE (INDX_BASE + 4096)
+
+#define NTFS_Large_Structure_Error_Code 1
+#define NTFS_Corrupt_Error_Code 2
+#define NTFS_Run_Overflow_Error_Code 3
+#define NTFS_No_Data_Error_Code 4
+#define NTFS_Decompress_Error_Code 5
+
+#define NT_FG_COMP 1
+#define NT_FG_MMFT 2
+#define NT_FG_ALST 4
+#define NT_FG_GPOS 8
+
+#define nt_boot_drive -2(%bp)
+#define nt_blocksize -4(%bp)
+#define nt_spc -5(%bp)
+#define nt_mft_size -6(%bp)
+#define nt_idx_size -7(%bp)
+#define nt_mft_start -12(%bp)
+#define nt_remain_len -16(%bp)
+//#define nt_file_count -18(%bp)
+
+#define nt_flag (%di)
+#define nt_attr_cur 2(%di)
+#define nt_attr_nxt 4(%di)
+#define nt_attr_end 6(%di)
+#define nt_curr_vcn 8(%di)
+#define nt_curr_lcn 0x10(%di)
+#define nt_attr_ofs 0x14(%di)
+#define nt_target_vcn 0x18(%di)
+#define nt_read_count 0x1C(%di)
+#define nt_vcn_offset 0x20(%di)
+
+#define nt_emft_buf 1024(%di)
+#define nt_edat_buf 2048(%di)
+
+ .arch i586
+
+Entry_nt:
+ jmp 1f
+
+ . = Entry_nt + 0x02
+
+ .byte 0x90 /* for CHS. Another possible value is 0x0e for LBA */
+
+ .ascii "NTFS "
+
+ .word 0 /* 0B - Bytes per sector */
+ .byte 0 /* 0D - Sectors per cluster */
+ .word 0 /* 0E - reserved sectors, unused */
+ .byte 0 /* 10 - number of FATs, unused */
+ .word 0 /* 11 - Max dir entries for FAT12/FAT16, unused */
+ .word 0 /* 13 - total sectors for FAT12/FAT16, unused */
+ .byte 0xF8 /* 15 - Media descriptor */
+ .word 0 /* 16 - sectors per FAT for FAT12/FAT16, unused */
+ .word 255 /* 18 - Sectors per track */
+ .word 63 /* 1A - Number of heads */
+nt_part_ofs:
+ .long 0 /* 1C - hidden sectors */
+ .long 0 /* 20 - total sectors for FAT32, unused */
+ .long 0x800080
+ /* 24 - Usually 80 00 80 00, A value of 80 00 00 00 has
+ * been seen on a USB thumb drive which is formatted
+ * with NTFS under Windows XP. Note this is removable
+ * media and is not partitioned, the drive as a whole
+ * is NTFS formatted.
+ */
+ .long 0,0 /* 28 - Number of sectors in the volume */
+ .long 0,0 /* 30 - LCN of VCN 0 of the $MFT */
+ .long 0,0 /* 38 - LCN of VCN 0 of the $MFTMirr */
+ .long 0 /* 40 - Clusters per MFT Record */
+ .long 4 /* 44 - Clusters per Index Record */
+ .long 0,0 /* 48 - Volume serial number */
+ .long 0 /* 50 - Checksum, usually 0 */
+
+1:
+
+ . = Entry_nt + 0x54
+
+ cli
+ cld
+
+ . = Entry_nt + 0x56
+
+ /* the byte at offset 0x57 stores the real partition number for read.
+ * the format program or the caller should set it to a correct value.
+ * For floppies, it should be 0xff, which stands for whole drive.
+ */
+
+ movb $0xff, %dh /* boot partition number */
+
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw $0x7c00, %bp
+ movw %ax, %es
+
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+
+ movw %dx, nt_boot_drive
+
+ /* Test if your BIOS support LBA mode */
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xAA55, %bx
+ jne 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ /* EBIOS supported */
+ movb $0x42, (ebios_nt - 1 - Entry_nt)(%bp)
+1:
+
+ cmpl $0x42555247, (nt_sector_mark - Entry_nt)(%bp)
+ jz 1f // Must be called from GRLDR.MBR
+
+ movw $0x7E00, %bx
+ movl (nt_part_ofs - Entry_nt)(%bp), %eax
+ incl %eax
+ call readDisk_nt // Load the second sector from disk
+ call readDisk_nt // Load the third sector from disk
+ call readDisk_nt
+1:
+
+ xorl %eax, %eax
+ movw 0xb(%bp), %ax // Bytes per sector (blocksize)
+ movw %ax, nt_blocksize
+
+ call convert_to_power_2
+ movb %cl, %bl
+ movb 0xd(%bp), %al // Sectors per cluster
+ call convert_to_power_2
+ movb %cl, %ch
+ addb %bl, %ch
+ subb $9, %ch // 1<<ch = sectors per cluster
+ movb %ch, nt_spc
+ movb 0x44(%bp), %al // Index record size (high bits of eax is 0)
+ call convert_size
+
+ cmpb $MAX_IDX_SIZE, %cl
+ jbe 1f
+
+NTFS_Large_Structure_Error:
+ movb $NTFS_Large_Structure_Error_Code, %al
+ jmp NTFS_Error
+
+1:
+ movb %cl, nt_idx_size
+
+ movb 0x40(%bp), %al // MFT record size
+ call convert_size
+
+ cmpb $MAX_MFT_SIZE, %cl
+ jnz NTFS_Large_Structure_Error
+
+ movb %cl, nt_mft_size
+
+ movl 0x30(%bp), %eax
+ movl 0x34(%bp), %edx
+
+ movb %ch, %cl // ch still contains nt_spc
+
+ shldl %cl, %eax, %edx
+ orl %edx, %edx
+ jnz NTFS_Large_Structure_Error
+
+ shll %cl, %eax
+ addl (nt_part_ofs - Entry_nt)(%bp), %eax
+ movl %eax, nt_mft_start
+
+ movw $1, %dx
+ movb nt_mft_size, %cl
+ shlw %cl, %dx
+ movw %dx, %cx
+
+ movw $MMFT_BASE, %bx
+ pushw %bx
+1:
+ call readDisk_nt
+ loop 1b
+
+ popw %bx
+ cmpw $0x4946, (%bx) // "FI"
+ jnz NTFS_Corrupt_Error
+
+ // dx should still contain the number of sectors in the MFT record
+ movw %dx, %cx
+ call ntfs_fixup
+
+ movw %bx, %di
+ movb $AT_DATA, %al // find $DATA
+
+ call ntfs_locate_attr
+ jc NTFS_Corrupt_Error
+
+ movw $CMFT_BASE, %bx
+ xorl %eax, %eax
+ movb $0x5, %al
+ call ntfs_read_mft
+ movw %bx, %di
+
+ jmp ntfs_search
+
+// Convert the size of MFT and IDX block
+// Input:
+// eax: size
+// ch: spc
+// Output:
+// cl: convert value
+convert_size:
+ orb %al, %al
+ js 1f
+ movb %ch, %cl
+ jmp 2f // Jump to 2 in convert_to_power_2
+1:
+ negb %al
+ subb $9, %al
+ movb %al, %cl
+ ret
+
+// Convert number to a power of 2
+// Input:
+// eax
+// Output:
+// cl: 1<<cl = eax
+// eax: 0
+
+convert_to_power_2:
+ xorb %cl, %cl
+2:
+ incb %cl
+ shrl $1, %eax
+ jnc 2b
+ decb %cl
+ ret
+
+// Fixup the "FILE" and "INDX" record
+// Input:
+// DS:BX - data buffer
+// CX - buffer length in sectors
+//
+
+ntfs_fixup:
+ push %bx
+ push %di
+ movw %bx, %di
+
+ movw 6(%bx), %ax // Size of Update Sequence
+ decw %ax
+ movw %ax, %bx
+
+ mulw nt_blocksize
+ shlw $9, %cx
+ cmpw %ax, %cx
+ jnz NTFS_Corrupt_Error // blocksize * count != size
+
+ movw %bx, %cx // cx = count
+
+ movw %di, %bx
+ addw 4(%bx), %bx // Offset to the update sequence
+ movw (%bx), %ax // Update Sequence Number
+ subw $2, %di
+
+1:
+ addw nt_blocksize, %di
+ addw $2, %bx
+ cmpw (%di), %ax
+ jnz NTFS_Corrupt_Error
+ movw (%bx), %dx
+ movw %dx, (%di)
+ loop 1b
+
+ popw %di
+ popw %bx
+ ret
+
+NTFS_Corrupt_Error:
+ movb $NTFS_Corrupt_Error_Code, %al
+ jmp NTFS_Error
+
+/* Read a sector from disk, using LBA or CHS
+ * input: EAX - 32-bit DOS sector number
+ * ES:BX - destination buffer
+ * (will be filled with 1 sector of data)
+ * output: ES:BX points one byte after the last byte read.
+ * EAX - next sector
+ */
+
+readDisk_nt:
+
+ pushal
+ xorl %edx, %edx /* EDX:EAX = LBA */
+ pushl %edx /* hi 32bit of sector number */
+ pushl %eax /* lo 32bit of sector number */
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ pushw $1 /* 1 sector to read */
+ pushw $16 /* size of this parameter block */
+
+ xorl %ecx, %ecx
+ pushl 0x18(%bp) /* lo:sectors per track, hi:number of heads */
+ popw %cx /* ECX = sectors per track */
+ divl %ecx /* residue is in EDX */
+ /* quotient is in EAX */
+ incw %dx /* sector number in DL */
+ popw %cx /* ECX = number of heads */
+ pushw %dx /* push sector number into stack */
+ xorw %dx, %dx /* EDX:EAX = cylinder * TotalHeads + head */
+ divl %ecx /* residue is in EDX, head number */
+ /* quotient is in EAX, cylinder number */
+ xchgb %dl, %dh /* head number should be in DH */
+ /* DL = 0 */
+ popw %cx /* pop sector number from stack */
+ xchgb %al, %ch /* lo 8bit cylinder should be in CH */
+ /* AL = 0 */
+ shlb $6, %ah /* hi 2bit cylinder ... */
+ orb %ah, %cl /* ... should be in CL */
+
+ movw $0x201, %ax /* read 1 sector */
+ebios_nt: /* ebios_nt - 1 points to 0x02 that can be changed to 0x42 */
+
+// cmpb $0x0e, 2(%bp) /* force LBA? */
+// jnz 1f /* no, continue */
+// movb $0x42, %ah /* yes, use extended disk read */
+//1:
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb nt_boot_drive, %dl /* hard disk drive number */
+
+ int $0x13
+
+ popaw /* remove parameter block from stack */
+ popal
+ jc disk_error_nt /* disk read error, jc 1f if caller handles */
+ incl %eax /* next sector */
+ addw 0x0b(%bp), %bx /* bytes per sector */
+ jnc 1f /* 64K bound check */
+ pushw %dx
+ movw %es, %dx
+ addb $0x10, %dh /* add 1000h to ES */
+ /* here, carry is cleared */
+ movw %dx, %es
+ popw %dx
+1:
+ /* carry stored on disk read error */
+ ret
+
+msg_DiskReadError_nt:
+
+ .ascii "0\0"
+
+msg_NTFS_Not_Found_Error:
+ .ascii "No "
+
+nt_boot_image:
+#ifdef BOOTGRUB2
+ .ascii "g2ldr\0"
+#else
+ .ascii "grldr\0"
+#endif
+
+ . = nt_boot_image + 8
+
+nt_boot_image_end:
+
+NTFS_Error:
+ addb %al, (msg_DiskReadError_nt - Entry_nt)(%bp)
+ jmp disk_error_nt
+
+// Kernel load address, located at 0x1E8
+ . = Entry_nt + 0x1e8
+
+nt_loadseg_off:
+ .word 0
+ .word LOADSEG_NT
+
+// Boot image offset and length, located at 0x1EE
+// Lower 11 bit is offset, higher 5 bit is length
+ . = Entry_nt + 0x1ec
+
+nt_boot_image_ofs:
+ .word (nt_boot_image - Entry_nt)+(nt_boot_image_end - nt_boot_image-1)*2048
+
+ . = Entry_nt + 0x1ee
+
+disk_error_nt:
+
+ movw $(msg_DiskReadError_nt - Entry_nt + 0x7c00), %si
+
+boot_error_nt:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_32:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+ . = Entry_nt + 0x1fc
+
+ .word 0, 0xAA55
+
+// Here starts sector #2
+
+// Input:
+// DI - current mft
+ntfs_search:
+ //movw $0, nt_file_count
+ call ntfs_init_attr
+ movb $AT_INDEX_ROOT, %al
+
+1:
+ call ntfs_find_attr
+ jc NTFS_Not_Found_Error
+
+ cmpl $0x180400, 8(%si) // resident
+ // namelen = 4
+ // name offset = 0x18
+ jnz 1b
+ //cmpl $0x490024, 0x18(%si) // "$I"
+ //jnz 1b
+ //cmpl $0x300033, 0x1C(%si)
+ //jnz 1b // "30"
+ //testw $0xC001, 12(%si) // not compressed, encrypted or sparse
+ //jnz 1b
+
+ addw 0x14(%si), %si // jump to attribute
+ cmpb $0x30, (%si)
+ jnz 1b // test if it index filenames
+
+ addw $0x10, %si // skip the index root
+ addw (%si), %si
+
+ call ntfs_find_grldr
+ jnc ntfs_final
+
+ call ntfs_init_attr
+ movb $AT_BITMAP, %al
+1:
+ call ntfs_find_attr
+ jc NTFS_Not_Found_Error
+ movw 9(%si), %bx
+ cmpb $4, %bl
+ jnz 1b
+ //shrw $4, %bx
+ //cmpl $0x490024, (%bx, %si) // "$I"
+ //jnz 1b
+ cmpb $0, 8(%si)
+ jnz 1f
+ pushw 0x10(%si)
+ addw 0x14(%si), %si
+ pushw %si
+ jmp 2f
+1:
+ pushw 0x30(%si)
+ xorl %edx, %edx
+ movl 0x28(%si), %ecx
+ cmpw $4096, %cx
+ ja NTFS_Not_Found_Error
+ shrl $9, %ecx
+ movw $SBUF_BASE, %bx
+ pushw %bx
+ call ntfs_read_data
+2:
+
+ movb $AT_INDEX_ALLOCATION, %al
+
+1:
+ call ntfs_locate_attr
+ jc NTFS_Not_Found_Error
+
+ cmpl $0x400401, 8(%si) // non-resident
+ // namelen = 4
+ // name offset = 0x40
+ jnz 1b
+ //cmpl $0x490024, 0x40(%si) // "$I"
+ //jnz 1b
+ //cmpl $0x300033, 0x44(%si)
+ //jnz 1b // "30"
+ //testw $0xC001, 12(%si) // not compressed, encrypted or sparse
+ //jnz 1b
+
+ movb nt_idx_size, %cl
+ xorl %ebx, %ebx
+ movb $1, %bl
+ shll %cl, %ebx // ebx - index size
+ xorl %edx, %edx // edx - index offset
+
+
+ popw %si
+ popw %cx
+
+1:
+ pushw %cx
+ lodsb (%si), %al
+
+ movw $8, %cx
+2:
+ pushw %cx
+ pushw %ax
+ testb $1, %al
+ jz 3f
+ pushw %si
+ pushl %edx
+ pushl %ebx
+
+ movl %ebx, %ecx
+ movw $INDX_BASE, %bx
+ call ntfs_read_attr
+ jc NTFS_Not_Found_Error
+ cmpw $0x4E49, (%bx) // "IN"
+ jnz NTFS_Not_Found_Error
+ call ntfs_fixup
+ movw %bx, %si
+ addw $0x18, %si
+ addw (%si), %si
+
+ call ntfs_find_grldr
+ jnc ntfs_final_0
+
+ popl %ebx
+ popl %edx
+ popw %si
+
+3:
+ addl %ebx, %edx
+
+ popw %ax
+ shrb $1, %al
+ popw %cx
+ loop 2b
+
+ popw %cx
+ loop 1b
+
+ //pushw nt_file_count
+ //call hex_out
+
+NTFS_Not_Found_Error:
+ leaw (msg_NTFS_Not_Found_Error - Entry_nt)(%bp), %si
+ jmp boot_error_nt
+
+ntfs_final_0:
+ //addw $16, %sp
+
+// Input:
+// DI - current mft
+// SI - index entry
+ntfs_final:
+ cmpw $0, 4(%si)
+ jnz NTFS_Large_Structure_Error
+
+ movl (%si), %eax
+ movw %di, %bx
+ call ntfs_read_mft
+
+ movb $AT_DATA, %al
+ call ntfs_locate_attr
+ jc NTFS_No_Data_Error
+
+ cmpb $1, 8(%si) // non-resident / resident
+ jz 1f
+
+ movw 0x10(%si), %cx // Resident
+ lesw (nt_loadseg_off - Entry_nt)(%bp), %di
+ addw 0x14(%si), %si
+ rep movsb (%si), %es:(%di)
+ jmp 2f
+
+1:
+
+ xorl %edx, %edx
+ movl 0x28(%si), %ecx // Use allocate size instead of real size
+ shrl $9, %ecx
+
+ lesw (nt_loadseg_off - Entry_nt)(%bp), %bx
+ call ntfs_read_data
+
+
+2:
+
+ //movb $1, (do_pause - Entry_nt)(%bp)
+ //call pause
+
+ movw nt_boot_drive, %dx
+ ljmp *(nt_loadseg_off - Entry_nt)(%bp)
+
+NTFS_No_Data_Error:
+ movb $NTFS_No_Data_Error_Code, %al
+ jmp NTFS_Error
+
+// Try to find GRLDR in the index
+// Input:
+// DS:SI - points to index entry
+// Output:
+// CF - status
+
+ntfs_find_grldr:
+ movw %si, %bx
+ testb $2, 0xC(%bx)
+ jz 1f
+ stc
+ ret
+1:
+ //incw nt_file_count
+
+ xorb %ch, %ch
+
+ pushw %si
+ leaw (nt_boot_image - Entry_nt)(%bp), %si
+ addw $0x52, %bx // The value at 0xA(%bx) is wrong sometimes (0x4C)
+ movb -2(%bx), %cl
+1:
+ lodsb (%si), %al
+ movb (%bx), %ah
+ cmpb $'A', %ah
+ jb 2f
+ cmpb $'Z', %ah
+ ja 2f
+ addb $('a'-'A'), %ah // Convert to lowercase
+2:
+
+ cmpb %ah, %al
+ jnz 3f // Not match
+
+ incw %bx
+ incw %bx
+ loop 1b
+
+ cmpb $0,(%si)
+ jnz 3f
+
+ popw %si
+ clc
+ ret // Match found
+
+3:
+
+ popw %si
+ addw 8(%si), %si
+
+ jmp ntfs_find_grldr
+
+// Locate an attribute
+// Input:
+// DI - pointer to buffer
+// AL - attribute
+ntfs_locate_attr:
+ call ntfs_init_attr
+ call ntfs_find_attr
+ jc 1f
+2:
+ testb $NT_FG_ALST, nt_flag
+ jnz 2f
+ call ntfs_find_attr
+ jnc 2b
+ call ntfs_init_attr
+ call ntfs_find_attr
+2:
+ clc
+1:
+ ret
+
+// Prepare to find attribute
+// Input:
+// DI - pointer to buffer
+ntfs_init_attr:
+ pushw %ax
+ xorw %ax, %ax
+ movw %ax, nt_flag
+ movw %ax, nt_attr_end
+ movw nt_attr_ofs, %ax
+ addw %di, %ax
+ movw %ax, nt_attr_nxt
+ popw %ax
+ cmpw $MMFT_BASE, %di
+ jnz 1f
+ orb $NT_FG_MMFT, nt_flag
+1:
+ ret
+
+// Find an attribute
+// Input:
+// DI - pointer to buffer
+// AL - attribute
+// Output:
+// SI - current item
+// CF - status
+ntfs_find_attr:
+ movw nt_attr_nxt, %bx
+ testb $NT_FG_ALST, nt_flag
+ jnz 6f
+1:
+ movw %bx, %si
+ cmpb $0xFF, (%si)
+ jz 3f
+
+ cmpb $AT_ATTRIBUTE_LIST, (%si)
+ jnz 2f
+ movw %si, nt_attr_end
+2:
+ addw 4(%bx), %bx
+ cmpb %al, (%si)
+ jnz 1b
+ movw %bx, nt_attr_nxt
+ movw %si, nt_attr_cur
+2:
+ ret
+3:
+ cmpw $1, nt_attr_end
+ jb 2b
+ movw nt_attr_end, %si
+ cmpb $0, 8(%si)
+ jnz 4f
+ movw %si, %bx
+ addw 0x14(%bx), %bx
+ addw 4(%si), %si
+ jmp 5f
+4:
+ movl 0x28(%si), %ecx
+ shrl $9, %ecx
+ cmpw $8, %cx
+ ja NTFS_Corrupt_Error
+ leaw nt_edat_buf, %bx
+ pushw %ax
+ xorl %edx, %edx
+ call ntfs_read_data
+ popw %ax
+ jc 2b
+ movw 0x30(%si), %si
+ addw %bx, %si
+5:
+ movw %si, nt_attr_end
+ orb $NT_FG_ALST, nt_flag
+ testb $NT_FG_MMFT, nt_flag
+ jz 6f
+ cmpb $AT_DATA, %al
+ jnz 6f
+ call ntfs_fix_mmft
+6:
+ movw %bx, %si
+ cmpw nt_attr_end, %bx
+ jb 1f
+7:
+ stc
+ ret
+1:
+ addw 4(%bx), %bx
+ cmpb %al, (%si)
+ jnz 6b
+
+ pushw %ax
+ pushw %es
+ pushw %ds
+ popw %es
+ movw %si, nt_attr_cur
+ movw %bx, nt_attr_nxt
+ movl 0x10(%si), %eax
+ leaw nt_emft_buf, %bx
+ testb $NT_FG_MMFT, nt_flag
+ jnz 2f
+ call ntfs_read_mft
+ jmp 3f
+2:
+ pushw %bx
+ call readDisk_nt
+ movl 0x14(%si), %eax
+ call readDisk_nt
+ popw %bx
+ cmpw $0x4946, (%bx) // "FI"
+ jnz NTFS_Corrupt_Error
+ movw $2, %cx
+ call ntfs_fixup
+3:
+ popw %es
+ popw %ax
+ addw 0x14(%bx), %bx
+4:
+ cmpb $0xFF, (%bx)
+ jz 7b
+ cmpb %al, (%bx)
+ jz 5f
+ addw 4(%bx), %bx
+ jmp 4b
+5:
+ movw %bx, %si
+ ret
+
+// Fix $MFT
+// Input:
+// DI - pointer to buffer
+// BX - attr cur
+ntfs_fix_mmft:
+ pushw %ax
+ orb $NT_FG_GPOS, nt_flag
+
+1:
+ cmpw nt_attr_end, %bx
+ jae NTFS_Corrupt_Error
+ cmpb %al, (%bx)
+ jz 2f
+ addw 4(%bx), %bx
+ jmp 1b
+2:
+
+ movw %bx, nt_attr_cur
+
+ movl nt_mft_start, %eax
+ movl %eax, 0x10(%bx)
+ incl %eax
+ movl %eax, 0x14(%bx)
+1:
+ addw 4(%bx), %bx
+
+ cmpw nt_attr_end, %bx
+ jae 2f
+ cmpb $AT_DATA, (%bx)
+ jnz 2f
+
+ movl 0x10(%bx), %edx
+ movb nt_mft_size, %cl
+ shll %cl, %edx
+
+ call ntfs_read_attr
+
+ orl %eax, %eax
+ jz NTFS_Corrupt_Error
+ movl %eax, 0x10(%bx)
+ movl %edx, 0x14(%bx)
+ jmp 1b
+2:
+ movw nt_attr_cur, %bx
+ andb $(~NT_FG_GPOS), nt_flag
+ popw %ax
+
+ ret
+
+// Read MFT record
+// Input:
+// DS:BX - buffer
+// EAX - mft number
+ntfs_read_mft:
+ pushw %di
+ movw $MMFT_BASE, %di
+ movb nt_mft_size, %cl
+ shll %cl, %eax
+ movl %eax, %edx
+ movl $1, %eax
+ shll %cl, %eax
+ movl %eax, %ecx
+ call ntfs_read_attr
+ jc NTFS_Corrupt_Error
+ cmpw $0x4946, (%bx) // "FI"
+ jnz NTFS_Corrupt_Error
+ call ntfs_fixup
+ popw %di
+ ret
+
+// Read attribute
+// Input:
+// DI - pointer to buffer
+// ES:BX - buffer
+// EDX - start sector
+// ECX - sector count
+// Output:
+// CF - status
+ntfs_read_attr:
+ pushw nt_attr_cur
+ pushl %edx
+ pushl %ecx
+ pushw %bx
+
+ movw nt_attr_cur, %si
+ movb (%si), %al
+
+ testb $NT_FG_ALST, nt_flag
+ jz 2f
+ movw %si, %bx
+ movb nt_spc, %cl
+ shrl %cl, %edx
+
+1:
+ cmpw nt_attr_end, %bx
+ jae 2f
+ cmpb %al, (%bx)
+ jnz 2f
+ cmpl %edx, 8(%bx)
+ ja 2f
+ movw %bx, %si
+ addw 4(%bx), %bx
+ jmp 1b
+2:
+
+ movw %si, nt_attr_nxt
+ call ntfs_find_attr
+
+ popw %bx
+ popl %ecx
+ popl %edx
+ jc 1f
+ call ntfs_read_data
+ clc
+1:
+ popw nt_attr_cur
+ ret
+
+// Read data
+// Input:
+// DI: pointer to buffer
+// SI: current item
+// ES:BX: buffer
+// EDX: start sector
+// ECX: sector count
+ntfs_read_data:
+ pushw %cx
+ pushw %bx
+ testb $1, 8(%si)
+ jz NTFS_Corrupt_Error
+ movb 0xC(%si), %al
+ andb $1, %al
+ orb %al, nt_flag
+
+ movl %ecx, nt_read_count
+ movb nt_spc, %cl
+
+ movl %edx, %eax
+ shrl %cl, %eax
+ movl %eax, nt_target_vcn
+ shll %cl, %eax
+ subl %eax, %edx
+ movl %edx, nt_vcn_offset
+
+ xorw %dx, %dx // edx - next VCN
+ movl %edx, nt_curr_lcn
+
+ movl 0x10(%si), %edx
+
+ addw 0x20(%si), %si
+1:
+ call ntfs_runlist_read_block
+
+ cmpl nt_target_vcn, %edx
+ jbe 1b
+1:
+ movb nt_spc, %cl
+
+ orl %eax, %eax // sparse
+ jz 2f
+
+ movl nt_target_vcn, %eax
+ subl nt_curr_vcn, %eax
+ addl nt_curr_lcn, %eax
+
+ shll %cl, %eax
+ addl nt_vcn_offset, %eax
+
+ testb $NT_FG_GPOS, nt_flag
+ jz 3f
+ pushl %eax
+ incl %eax
+ subl nt_curr_vcn, %edx
+ addl nt_curr_lcn, %edx
+ shll %cl, %edx
+ cmpl %eax, %edx
+ jnz 4f
+ pushw %cx
+ call ntfs_runlist_read_block
+ popw %cx
+ movl nt_curr_lcn, %eax
+ shll %cl, %eax
+4:
+ movl %eax, %edx
+ popl %eax
+ addl (nt_part_ofs - Entry_nt)(%bp), %edx
+3:
+
+ addl (nt_part_ofs - Entry_nt)(%bp), %eax
+
+2:
+ testb $NT_FG_GPOS, nt_flag
+ jnz 1f
+
+ pushl %ebx
+ movl %edx, %ebx
+ subl nt_target_vcn, %ebx
+ shll %cl, %ebx
+ movl %ebx, %ecx
+ popl %ebx
+
+ subl nt_vcn_offset, %ecx
+ movl $0, nt_vcn_offset
+ cmpl nt_read_count, %ecx
+ jbe 2f
+ movl nt_read_count, %ecx
+2:
+
+ pushl %ecx
+
+ orl %eax, %eax
+ jnz 3f
+ call ntfs_sparse_block
+ jmp 4f
+
+3:
+ call readDisk_nt
+ loop 3b
+
+4:
+ popl %ecx
+ subl %ecx, nt_read_count
+ jbe 1f
+
+ movl %edx, nt_target_vcn
+ call ntfs_runlist_read_block
+ jmp 1b
+
+1:
+ popw %bx
+ popw %cx
+ ret
+
+// Read run list data
+// Input:
+// CL = number of bytes
+// Output:
+// EAX = read bytes
+// SI points to the next unhandled byte
+
+ntfs_runlist_read_data:
+ pushw %cx
+ orb %cl, %cl
+ jnz 1f
+ popw %cx
+ xorl %eax, %eax
+ ret
+1:
+ lodsb (%si), %al
+ rorl $8, %eax
+ decb %cl
+ jnz 1b
+
+ popw %cx
+ negb %cl
+ add $4, %cl
+ shlb $3, %cl
+ ret
+
+NTFS_Run_Overflow_Error:
+ movb $NTFS_Run_Overflow_Error_Code, %al
+ jmp NTFS_Error
+
+// Read run list block
+// Output:
+// EDX = Next VCN
+// SI points to the next unhandled byte
+
+ntfs_runlist_read_block:
+ lodsb (%si), %al
+ movb %al, %cl
+ movb %cl, %ch
+ andb $0xF, %cl // cl - Size of length field
+ jz 1f
+ shrb $0x4, %ch // ch - Size of offset field
+
+ call ntfs_runlist_read_data
+ shrl %cl, %eax
+
+ movl %edx, nt_curr_vcn
+ addl %eax, %edx
+
+ movb %ch, %cl
+ call ntfs_runlist_read_data
+ sarl %cl, %eax
+
+ addl %eax, nt_curr_lcn
+
+ ret
+
+1:
+ testb $NT_FG_ALST, nt_flag
+ jz NTFS_Run_Overflow_Error
+
+ pushl %edx
+ pushw %bx
+ movw nt_attr_cur, %si
+ movb (%si), %al
+ call ntfs_find_attr
+ jc NTFS_Run_Overflow_Error
+ cmpb $0, 8(%si)
+ jz NTFS_Run_Overflow_Error
+ movl $0, nt_curr_lcn
+ popw %bx
+ popl %edx
+ addw 0x20(%si), %si
+ jmp ntfs_runlist_read_block
+
+// Convert seg:ofs to linear address
+// Input:
+// On stack: seg:ofs
+// Output:
+// eax:
+seg_to_lin:
+ pushw %bp
+ movw %sp, %bp
+ xorl %eax, %eax
+ xchgw 6(%bp), %ax
+ shll $4, %eax
+ addl 4(%bp), %eax
+ popw %bp
+ ret $4
+
+// Convert linear address to seg:ofs
+// Input:
+// on stack: linear address
+// Output:
+// On stack: seg:ofs
+lin_to_seg:
+ pushw %bp
+ movw %sp, %bp
+ shll $12, 4(%bp)
+ shrw $12, 4(%bp)
+ popw %bp
+ ret
+
+fix_segs:
+ pushw %ds
+ pushw %si
+ call seg_to_lin
+ pushl %eax
+ call lin_to_seg
+ popw %si
+ popw %ds
+
+fix_es_di:
+ pushw %es
+ pushw %di
+ call seg_to_lin
+ pushl %eax
+ call lin_to_seg
+ popw %di
+ popw %es
+ ret
+
+// Handle sparse block
+// DI: points to buffer
+// ES:BX: points to buffer
+// ECX: number of sectors
+// EDX: next VCN
+
+ntfs_sparse_block:
+ pushw %di
+ pushl %edx
+
+ shll $9, %ecx // ecx - totel number of bytes
+
+ testb $1, nt_flag // Not compressed
+ jz 2f
+
+ xorl %edx, %edx
+ movb nt_target_vcn, %dl
+ andb $0xF, %dl
+ jz 2f
+
+ movw %bx, %di
+
+ pushw %cx
+
+ movb nt_spc, %cl
+ addb $9, %cl
+ shll %cl, %edx // edx: offset from the start of cluster
+
+ push %es
+ push %di
+ call seg_to_lin
+ subl %edx, %eax // eax: linear address
+
+ movl $16, nt_remain_len
+ shll %cl, nt_remain_len
+
+ popw %cx
+
+ addl %edx, %ecx
+ subl nt_remain_len, %ecx
+
+ pushl %ecx
+ call ntfs_decomp_block
+ popl %ecx
+
+ addl nt_remain_len, %ecx
+
+ jecxz 1f
+
+ movw %di, %bx
+
+2:
+ movw %bx, %di
+ movl %ecx, %edx
+ xorl %eax, %eax
+ movl %eax, %ecx
+ call fix_es_di
+
+3:
+ movw $0x8000, %cx
+ cmpl %edx, %ecx
+ jbe 4f
+ movw %dx, %cx
+4:
+ pushw %cx
+ shrw $2, %cx
+
+ rep stosl %eax, %es:(%di)
+ call fix_es_di
+ popw %cx
+ subl %ecx, %edx
+ jnz 3b
+
+1:
+ movw %di, %bx
+
+ popl %edx
+ popw %di
+
+ ret
+
+// Decompress block
+// Input:
+// eax: linear address at the beginning of the compressed block
+// Output:
+// ES:DI: points to the end of the block
+ntfs_decomp_block:
+ pushw %ds
+ pushw %si
+
+ pushl %eax
+ call lin_to_seg
+ popw %si
+ popw %ds
+ movl nt_remain_len, %edx
+ addl %edx, %eax
+ pushl %eax
+ call lin_to_seg
+ popw %di
+ popw %es
+
+ pushw %es
+ pushw %di
+ pushw %ds
+ pushw %si
+
+ xorl %ecx, %ecx
+
+1:
+ movw $0x8000, %cx
+ cmpl %edx, %ecx
+ jbe 2f
+ movw %dx, %cx
+2:
+ pushw %cx
+ shrw $2, %cx
+ rep movsl (%si), %es:(%di)
+ call fix_segs
+ popw %cx
+ subl %ecx, %edx
+ jnz 1b
+
+ popw %di
+ popw %es
+ popw %si
+ popw %ds
+
+1:
+ xorl %edx, %edx // edx - copied bytes
+
+ lodsw (%si), %ax
+ testb $0x80, %ah
+ jnz 2f
+ movw $0x800, %cx
+ rep movsw (%si), %es:(%di)
+ movw $0x1000, %dx
+ jmp 7f // The block is not compressed
+
+2:
+ movw %ax, %cx
+ andw $0xFFF, %cx
+ incw %cx // ecx = block length
+ addw %si, %cx // cx: end marker
+ xorb %bh, %bh
+
+3:
+ cmpw $0x1000, %dx
+ ja NTFS_Decompress_Error
+
+ orb %bh, %bh
+ jnz 4f
+ lodsb (%si), %al
+ movb %al, %bl // bl: tag, bh: count
+ movb $8, %bh
+4:
+
+ testb $1, %bl
+ jz 5f
+
+ movw %dx, %ax
+ decw %ax
+
+ pushw %cx
+ pushw %bx
+
+ movb $12, %cl
+6:
+ cmpw $0x10, %ax
+ jb 6f
+ shrw $1, %ax
+ decb %cl
+ jmp 6b
+6:
+
+ lodsw (%si), %ax
+ movw %ax, %bx
+ shrw %cl, %bx // bx: delta
+
+ pushw %dx
+ movw $1, %dx
+ shlw %cl, %dx
+ decw %dx
+ andw %dx, %ax
+ popw %dx
+
+ addw $3, %ax
+ movw %ax, %cx // cx: length
+ negw %bx
+ decw %bx
+
+6:
+ movb %es:(%bx, %di), %al
+ stosb %al, %es:(%di)
+ incw %dx
+ loop 6b
+
+ popw %bx
+ popw %cx
+ jmp 4f
+
+5:
+ movsb (%si), %es:(%di)
+ incw %dx
+4:
+ shrb $1, %bl
+ decb %bh
+
+ cmpw %cx, %si
+ jb 3b
+
+7:
+ call fix_segs
+
+ subl %edx, nt_remain_len // End of block
+ jz 1f
+
+ cmpw $0x1000, %dx
+ je 1b
+
+1:
+
+ popw %si
+ popw %ds
+ ret
+
+NTFS_Decompress_Error:
+ pushw %ss
+ popw %ds
+ movb $NTFS_Decompress_Error_Code, %al
+ jmp NTFS_Error
+
+/*
+do_pause:
+ .byte 0
+
+pause:
+ cmpb $0, (do_pause - Entry_nt)(%bp)
+ jnz 1f
+ ret
+1:
+ xorw %bp, %bp
+1:
+ jmp 1b
+*/
+
+/*
+hex_out:
+ pushw %bp
+ movw %sp, %bp
+ pushaw
+ movb $0xE, %ah
+ movw $7, %bx
+ movw $4, %cx
+ movw 4(%bp), %dx
+1:
+ rol $4, %dx
+ movb %dl, %al
+ andb $0xF, %al
+ cmpb $10, %al
+ jb 2f
+ subb $('0'-'A'+10), %al
+2:
+ addb $'0', %al
+ int $0x10
+ loop 1b
+ movb $' ', %al
+ int $0x10
+ popaw
+ popw %bp
+ ret $2
+*/
+
+ . = Entry_nt + 0x7fc
+
+nt_sector_mark:
+ .long 0x42555247 // "GRUB"