Install grubinst as grub-ntldr-img.
[grub-extras.git] / ntfsbs.S
blob88b9180f93b08e733769a7461ee2f46e1f83fc6e
1 /*
2  *  GRUB Utilities --  Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
3  *  Copyright (C) 2007 Bean (bean123@126.com)
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
20 /* NTFS boot sector for loading GRLDR , written by bean
21  *
22  * This file can be compiled as standaolne boot sector, or it can be embeded in
23  * GRLDR.MBR at 0xA00 , right after the ext2 boot sector
24  *
25  * To compile the standalone ntfsbs.bin:
26  *     gcc -c -o ntfsbs.o ntfsbs.S
27  *     gcc -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00 -o ntfsbs_exec ntfsbs.o
28  *     objcopy -O binary ntfsbs_exec ntfsbs.bin
29  *
30  * To install the standalone ntfsbs.bin:
31  *     grubinst --restore=ntfsbs.bin DEVICE_OR_FILE
32  *
33  * Where DEVICE_OR_FILE specify a NTFS partition
34  *
35  * Limitations:
36  *  1. Don't support >1K MFT record size, >4K INDEX record size
37  *  2. Don't support encrypted file
38  *  3. Don't support >4K non-resident attribute list and $BITMAP
39  *
40  */
42 #ifndef INSIDE_GRLDR
44         .text
46         .code16
47 #endif
49 #define AT_STANDARD_INFORMATION 0x10
50 #define AT_ATTRIBUTE_LIST       0x20
51 #define AT_FILENAME             0x30
52 #define AT_OBJECT_ID            0x40
53 #define AT_SECURITY_DESCRIPTOR  0x50
54 #define AT_VOLUME_NAME          0x60
55 #define AT_VOLUME_INFORMATION   0x70
56 #define AT_DATA                 0x80
57 #define AT_INDEX_ROOT           0x90
58 #define AT_INDEX_ALLOCATION     0xA0
59 #define AT_BITMAP               0xB0
60 #define AT_SYMLINK              0xC0
61 #define AT_EA_INFORMATION       0xD0
62 #define AT_EA                   0xE0
64 #define MAX_MFT_SIZE    1               // 1<<(1+9) = 1024
65 #define MAX_IDX_SIZE    3               // 1<<(3+9) = 4096
67 #define LOADSEG_NT      0x2000
69 #define MMFT_BASE       0x2000
70 #define MMFT_EMFT       (MMFT_BASE +1024)
71 #define MMFT_EBUF       (MMFT_BASE + 2048)
73 #define CMFT_BASE       (MMFT_BASE + 6144)
74 #define CMFT_EMFT       (CMFT_BASE + 1024)
75 #define CMFT_EBUF       (CMFT_BASE + 2048)
77 #define INDX_BASE       (CMFT_BASE + 6144)
79 #define SBUF_BASE       (INDX_BASE + 4096)
81 #define NTFS_Large_Structure_Error_Code 1
82 #define NTFS_Corrupt_Error_Code         2
83 #define NTFS_Run_Overflow_Error_Code    3
84 #define NTFS_No_Data_Error_Code         4
85 #define NTFS_Decompress_Error_Code      5
87 #define NT_FG_COMP      1
88 #define NT_FG_MMFT      2
89 #define NT_FG_ALST      4
90 #define NT_FG_GPOS      8
92 #define nt_boot_drive   -2(%bp)
93 #define nt_blocksize    -4(%bp)
94 #define nt_spc          -5(%bp)
95 #define nt_mft_size     -6(%bp)
96 #define nt_idx_size     -7(%bp)
97 #define nt_mft_start    -12(%bp)
98 #define nt_remain_len   -16(%bp)
99 //#define nt_file_count -18(%bp)
101 #define nt_flag         (%di)
102 #define nt_attr_cur     2(%di)
103 #define nt_attr_nxt     4(%di)
104 #define nt_attr_end     6(%di)
105 #define nt_curr_vcn     8(%di)
106 #define nt_curr_lcn     0x10(%di)
107 #define nt_attr_ofs     0x14(%di)
108 #define nt_target_vcn   0x18(%di)
109 #define nt_read_count   0x1C(%di)
110 #define nt_vcn_offset   0x20(%di)
112 #define nt_emft_buf     1024(%di)
113 #define nt_edat_buf     2048(%di)
115         .arch   i586
117 Entry_nt:
118         jmp     1f
120         . = Entry_nt + 0x02
122         .byte   0x90    /* for CHS. Another possible value is 0x0e for LBA */
124         .ascii  "NTFS    "
126         .word   0       /* 0B - Bytes per sector */
127         .byte   0       /* 0D - Sectors per cluster */
128         .word   0       /* 0E - reserved sectors, unused */
129         .byte   0       /* 10 - number of FATs, unused */
130         .word   0       /* 11 - Max dir entries for FAT12/FAT16, unused */
131         .word   0       /* 13 - total sectors for FAT12/FAT16, unused */
132         .byte   0xF8    /* 15 - Media descriptor */
133         .word   0       /* 16 - sectors per FAT for FAT12/FAT16, unused */
134         .word   255     /* 18 - Sectors per track */
135         .word   63      /* 1A - Number of heads */
136 nt_part_ofs:
137         .long   0       /* 1C - hidden sectors */
138         .long   0       /* 20 - total sectors for FAT32, unused */
139         .long   0x800080
140                         /* 24 - Usually 80 00 80 00, A value of 80 00 00 00 has
141                          * been seen on a USB thumb drive which is formatted
142                          * with NTFS under Windows XP. Note this is removable
143                          * media and is not partitioned, the drive as a whole
144                          * is NTFS formatted.
145                          */
146         .long   0,0     /* 28 - Number of sectors in the volume */
147         .long   0,0     /* 30 - LCN of VCN 0 of the $MFT */
148         .long   0,0     /* 38 - LCN of VCN 0 of the $MFTMirr */
149         .long   0       /* 40 - Clusters per MFT Record */
150         .long   4       /* 44 - Clusters per Index Record */
151         .long   0,0     /* 48 - Volume serial number */
152         .long   0       /* 50 - Checksum, usually 0 */
156         . = Entry_nt + 0x54
158         cli
159         cld
161         . = Entry_nt + 0x56
163         /* the byte at offset 0x57 stores the real partition number for read.
164          * the format program or the caller should set it to a correct value.
165          * For floppies, it should be 0xff, which stands for whole drive.
166          */
168         movb    $0xff, %dh      /* boot partition number */
170         xorw    %ax, %ax
171         movw    %ax, %ds
172         movw    $0x7c00, %bp
173         movw    %ax, %es
175         movw    %ax, %ss        /* stack and BP-relative moves up, too */
176         leaw    -0x20(%bp), %sp
177         sti
179         movw    %dx, nt_boot_drive
181         /* Test if your BIOS support LBA mode */
182         movb    $0x41, %ah
183         movw    $0x55AA, %bx
184         int     $0x13
185         jc      1f              /* No EBIOS */
186         cmpw    $0xAA55, %bx
187         jne     1f              /* No EBIOS */
188         testb   $1, %cl
189         jz      1f              /* No EBIOS */
190         /* EBIOS supported */
191         movb    $0x42, (ebios_nt - 1 - Entry_nt)(%bp)
194         cmpl    $0x42555247, (nt_sector_mark - Entry_nt)(%bp)
195         jz      1f                      // Must be called from GRLDR.MBR
197         movw    $0x7E00, %bx
198         movl    (nt_part_ofs - Entry_nt)(%bp), %eax
199         incl    %eax
200         call    readDisk_nt             // Load the second sector from disk
201         call    readDisk_nt             // Load the third sector from disk
202         call    readDisk_nt
205         xorl    %eax, %eax
206         movw    0xb(%bp), %ax           // Bytes per sector (blocksize)
207         movw    %ax, nt_blocksize
209         call    convert_to_power_2
210         movb    %cl, %bl
211         movb    0xd(%bp), %al           // Sectors per cluster
212         call    convert_to_power_2
213         movb    %cl, %ch
214         addb    %bl, %ch
215         subb    $9, %ch                 // 1<<ch = sectors per cluster
216         movb    %ch, nt_spc
217         movb    0x44(%bp), %al          // Index record size (high bits of eax is 0)
218         call    convert_size
220         cmpb    $MAX_IDX_SIZE, %cl
221         jbe     1f
223 NTFS_Large_Structure_Error:
224         movb    $NTFS_Large_Structure_Error_Code, %al
225         jmp     NTFS_Error
228         movb    %cl, nt_idx_size
230         movb    0x40(%bp), %al          // MFT record size
231         call    convert_size
233         cmpb    $MAX_MFT_SIZE, %cl
234         jnz     NTFS_Large_Structure_Error
236         movb    %cl, nt_mft_size
238         movl    0x30(%bp), %eax
239         movl    0x34(%bp), %edx
241         movb    %ch, %cl                // ch still contains nt_spc
243         shldl   %cl, %eax, %edx
244         orl     %edx, %edx
245         jnz     NTFS_Large_Structure_Error
247         shll    %cl, %eax
248         addl    (nt_part_ofs - Entry_nt)(%bp), %eax
249         movl    %eax, nt_mft_start
251         movw    $1, %dx
252         movb    nt_mft_size, %cl
253         shlw    %cl, %dx
254         movw    %dx, %cx
256         movw    $MMFT_BASE, %bx
257         pushw   %bx
259         call    readDisk_nt
260         loop    1b
262         popw    %bx
263         cmpw    $0x4946, (%bx)          // "FI"
264         jnz     NTFS_Corrupt_Error
266         // dx should still contain the number of sectors in the MFT record
267         movw    %dx, %cx
268         call    ntfs_fixup
270         movw    %bx, %di
271         movb    $AT_DATA, %al           // find $DATA
273         call    ntfs_locate_attr
274         jc      NTFS_Corrupt_Error
276         movw    $CMFT_BASE, %bx
277         xorl    %eax, %eax
278         movb    $0x5, %al
279         call    ntfs_read_mft
280         movw    %bx, %di
282         jmp     ntfs_search
284 // Convert the size of MFT and IDX block
285 // Input:
286 //     eax: size
287 //     ch: spc
288 // Output:
289 //     cl: convert value
290 convert_size:
291         orb     %al, %al
292         js      1f
293         movb    %ch, %cl
294         jmp     2f                      // Jump to 2 in convert_to_power_2
296         negb    %al
297         subb    $9, %al
298         movb    %al, %cl
299         ret
301 // Convert number to a power of 2
302 // Input:
303 //     eax
304 // Output:
305 //     cl: 1<<cl = eax
306 //     eax: 0
308 convert_to_power_2:
309         xorb    %cl, %cl
311         incb    %cl
312         shrl    $1, %eax
313         jnc     2b
314         decb    %cl
315         ret
317 // Fixup the "FILE" and "INDX" record
318 // Input:
319 //     DS:BX - data buffer
320 //     CX - buffer length in sectors
323 ntfs_fixup:
324         push    %bx
325         push    %di
326         movw    %bx, %di
328         movw    6(%bx), %ax             // Size of Update Sequence
329         decw    %ax
330         movw    %ax, %bx
332         mulw    nt_blocksize
333         shlw    $9, %cx
334         cmpw    %ax, %cx
335         jnz     NTFS_Corrupt_Error      // blocksize * count != size
337         movw    %bx, %cx                // cx = count
339         movw    %di, %bx
340         addw    4(%bx), %bx             // Offset to the update sequence
341         movw    (%bx), %ax              // Update Sequence Number
342         subw    $2, %di
345         addw    nt_blocksize, %di
346         addw    $2, %bx
347         cmpw    (%di), %ax
348         jnz     NTFS_Corrupt_Error
349         movw    (%bx), %dx
350         movw    %dx, (%di)
351         loop    1b
353         popw    %di
354         popw    %bx
355         ret
357 NTFS_Corrupt_Error:
358         movb    $NTFS_Corrupt_Error_Code, %al
359         jmp     NTFS_Error
361 /* Read a sector from disk, using LBA or CHS
362  * input:       EAX - 32-bit DOS sector number
363  *              ES:BX - destination buffer
364  *              (will be filled with 1 sector of data)
365  * output:      ES:BX points one byte after the last byte read.
366  *              EAX - next sector
367  */
369 readDisk_nt:
371         pushal
372         xorl    %edx, %edx      /* EDX:EAX = LBA */
373         pushl   %edx            /* hi 32bit of sector number */
374         pushl   %eax            /* lo 32bit of sector number */
375         pushw   %es             /* buffer segment */
376         pushw   %bx             /* buffer offset */
377         pushw   $1              /* 1 sector to read */
378         pushw   $16             /* size of this parameter block */
380         xorl    %ecx, %ecx
381         pushl   0x18(%bp)       /* lo:sectors per track, hi:number of heads */
382         popw    %cx             /* ECX = sectors per track */
383         divl    %ecx            /* residue is in EDX */
384                                 /* quotient is in EAX */
385         incw    %dx             /* sector number in DL */
386         popw    %cx             /* ECX = number of heads */
387         pushw   %dx             /* push sector number into stack */
388         xorw    %dx, %dx        /* EDX:EAX = cylinder * TotalHeads + head */
389         divl    %ecx            /* residue is in EDX, head number */
390                                 /* quotient is in EAX, cylinder number */
391         xchgb   %dl, %dh        /* head number should be in DH */
392                                 /* DL = 0 */
393         popw    %cx             /* pop sector number from stack */
394         xchgb   %al, %ch        /* lo 8bit cylinder should be in CH */
395                                 /* AL = 0 */
396         shlb    $6, %ah         /* hi 2bit cylinder ... */
397         orb     %ah, %cl        /* ... should be in CL */
399         movw    $0x201, %ax     /* read 1 sector */
400 ebios_nt: /* ebios_nt - 1 points to 0x02 that can be changed to 0x42 */
402 //      cmpb    $0x0e, 2(%bp)   /* force LBA? */
403 //      jnz     1f              /* no, continue */
404 //      movb    $0x42, %ah      /* yes, use extended disk read */
405 //1:
406         movw    %sp, %si        /* DS:SI points to disk address packet */
407         movb    nt_boot_drive, %dl      /* hard disk drive number */
409         int     $0x13
411         popaw                   /* remove parameter block from stack */
412         popal
413         jc      disk_error_nt   /* disk read error, jc 1f if caller handles */
414         incl    %eax            /* next sector */
415         addw    0x0b(%bp), %bx  /* bytes per sector */
416         jnc     1f              /* 64K bound check */
417         pushw   %dx
418         movw    %es, %dx
419         addb    $0x10, %dh      /* add 1000h to ES */
420                                 /* here, carry is cleared */
421         movw    %dx, %es
422         popw    %dx
424         /* carry stored on disk read error */
425         ret
427 msg_DiskReadError_nt:
429         .ascii  "0\0"
431 msg_NTFS_Not_Found_Error:
432         .ascii "No "
434 nt_boot_image:
435         .ascii "grldr\0"
437         . = nt_boot_image + 8
439 nt_boot_image_end:
441 NTFS_Error:
442         addb    %al, (msg_DiskReadError_nt - Entry_nt)(%bp)
443         jmp     disk_error_nt
445 // Kernel load address, located at 0x1E8
446         . = Entry_nt + 0x1e8
448 nt_loadseg_off:
449         .word   0
450         .word   LOADSEG_NT
452 // Boot image offset and length, located at 0x1EE
453 // Lower 11 bit is offset, higher 5 bit is length
454         . = Entry_nt + 0x1ec
456 nt_boot_image_ofs:
457         .word (nt_boot_image - Entry_nt)+(nt_boot_image_end - nt_boot_image-1)*2048
459         . = Entry_nt + 0x1ee
461 disk_error_nt:
463         movw    $(msg_DiskReadError_nt - Entry_nt + 0x7c00), %si
465 boot_error_nt:
467 /* prints string DS:SI (modifies AX BX SI) */
469 //print_32:
471         lodsb   (%si), %al      /* get token */
472         //xorw  %bx, %bx        /* video page 0 */
473         movb    $0x0e, %ah      /* print it */
474         int     $0x10           /* via TTY mode */
475         cmpb    $0, %al         /* end of string? */
476         jne     1b              /* until done */
478         /* The caller will change this to
479          *      ljmp    $0x9400, $(try_next_partition - _start1)
480          */
482 1:      jmp     1b
484         . = Entry_nt + 0x1fc
486         .word   0, 0xAA55
488 // Here starts sector #2
490 // Input:
491 //     DI - current mft
492 ntfs_search:
493         //movw  $0, nt_file_count
494         call    ntfs_init_attr
495         movb    $AT_INDEX_ROOT, %al
498         call    ntfs_find_attr
499         jc      NTFS_Not_Found_Error
501         cmpl    $0x180400,  8(%si)      // resident
502                                         // namelen = 4
503                                         // name offset = 0x18
504         jnz     1b
505         //cmpl  $0x490024, 0x18(%si)    // "$I"
506         //jnz   1b
507         //cmpl  $0x300033, 0x1C(%si)
508         //jnz   1b                      // "30"
509         //testw $0xC001, 12(%si)        // not compressed, encrypted or sparse
510         //jnz   1b
512         addw    0x14(%si), %si          // jump to attribute
513         cmpb    $0x30, (%si)
514         jnz     1b                      // test if it index filenames
516         addw    $0x10, %si              // skip the index root
517         addw    (%si), %si
519         call    ntfs_find_grldr
520         jnc     ntfs_final
522         call    ntfs_init_attr
523         movb    $AT_BITMAP, %al
525         call    ntfs_find_attr
526         jc      NTFS_Not_Found_Error
527         movw    9(%si), %bx
528         cmpb    $4, %bl
529         jnz     1b
530         //shrw  $4, %bx
531         //cmpl  $0x490024, (%bx, %si)   // "$I"
532         //jnz   1b
533         cmpb    $0, 8(%si)
534         jnz     1f
535         pushw   0x10(%si)
536         addw    0x14(%si), %si
537         pushw   %si
538         jmp     2f
540         pushw   0x30(%si)
541         xorl    %edx, %edx
542         movl    0x28(%si), %ecx
543         cmpw    $4096, %cx
544         ja      NTFS_Not_Found_Error
545         shrl    $9, %ecx
546         movw    $SBUF_BASE, %bx
547         pushw   %bx
548         call    ntfs_read_data
551         movb    $AT_INDEX_ALLOCATION, %al
554         call    ntfs_locate_attr
555         jc      NTFS_Not_Found_Error
557         cmpl    $0x400401, 8(%si)       // non-resident
558                                         // namelen = 4
559                                         // name offset = 0x40
560         jnz     1b
561         //cmpl  $0x490024, 0x40(%si)    // "$I"
562         //jnz   1b
563         //cmpl  $0x300033, 0x44(%si)
564         //jnz   1b                      // "30"
565         //testw $0xC001, 12(%si)        // not compressed, encrypted or sparse
566         //jnz   1b
568         movb    nt_idx_size, %cl
569         xorl    %ebx, %ebx
570         movb    $1, %bl
571         shll    %cl, %ebx               // ebx - index size
572         xorl    %edx, %edx              // edx - index offset
575         popw    %si
576         popw    %cx
579         pushw   %cx
580         lodsb   (%si), %al
582         movw    $8, %cx
584         pushw   %cx
585         pushw   %ax
586         testb   $1, %al
587         jz      3f
588         pushw   %si
589         pushl   %edx
590         pushl   %ebx
592         movl    %ebx, %ecx
593         movw    $INDX_BASE, %bx
594         call    ntfs_read_attr
595         jc      NTFS_Not_Found_Error
596         cmpw    $0x4E49, (%bx)          // "IN"
597         jnz     NTFS_Not_Found_Error
598         call    ntfs_fixup
599         movw    %bx, %si
600         addw    $0x18, %si
601         addw    (%si), %si
603         call    ntfs_find_grldr
604         jnc     ntfs_final_0
606         popl    %ebx
607         popl    %edx
608         popw    %si
611         addl    %ebx, %edx
613         popw    %ax
614         shrb    $1, %al
615         popw    %cx
616         loop    2b
618         popw    %cx
619         loop    1b
621         //pushw nt_file_count
622         //call  hex_out
624 NTFS_Not_Found_Error:
625         leaw    (msg_NTFS_Not_Found_Error - Entry_nt)(%bp), %si
626         jmp     boot_error_nt
628 ntfs_final_0:
629         //addw  $16, %sp
631 // Input:
632 //     DI - current mft
633 //     SI - index entry
634 ntfs_final:
635         cmpw    $0, 4(%si)
636         jnz     NTFS_Large_Structure_Error
638         movl    (%si), %eax
639         movw    %di, %bx
640         call    ntfs_read_mft
642         movb    $AT_DATA, %al
643         call    ntfs_locate_attr
644         jc      NTFS_No_Data_Error
646         cmpb    $1, 8(%si)              // non-resident / resident
647         jz      1f
649         movw    0x10(%si), %cx          // Resident
650         lesw    (nt_loadseg_off - Entry_nt)(%bp), %di
651         addw    0x14(%si), %si
652         rep     movsb   (%si), %es:(%di)
653         jmp     2f
657         xorl    %edx, %edx
658         movl    0x28(%si), %ecx         // Use allocate size instead of real size
659         shrl    $9, %ecx
661         lesw    (nt_loadseg_off - Entry_nt)(%bp), %bx
662         call    ntfs_read_data
667         //movb  $1, (do_pause - Entry_nt)(%bp)
668         //call  pause
670         movw    nt_boot_drive, %dx
671         ljmp    *(nt_loadseg_off - Entry_nt)(%bp)
673 NTFS_No_Data_Error:
674         movb    $NTFS_No_Data_Error_Code, %al
675         jmp     NTFS_Error
677 // Try to find GRLDR in the index
678 // Input:
679 //     DS:SI - points to index entry
680 // Output:
681 //     CF - status
683 ntfs_find_grldr:
684         movw    %si, %bx
685         testb   $2, 0xC(%bx)
686         jz      1f
687         stc
688         ret
690         //incw  nt_file_count
692         xorb    %ch, %ch
694         pushw   %si
695         leaw    (nt_boot_image - Entry_nt)(%bp), %si
696         addw    $0x52, %bx              // The value at 0xA(%bx) is wrong sometimes (0x4C)
697         movb    -2(%bx), %cl
699         lodsb   (%si), %al
700         movb    (%bx), %ah
701         cmpb    $'A', %ah
702         jb      2f
703         cmpb    $'Z', %ah
704         ja      2f
705         addb    $('a'-'A'), %ah         // Convert to lowercase
708         cmpb    %ah, %al
709         jnz     3f                      // Not match
711         incw    %bx
712         incw    %bx
713         loop    1b
715         cmpb    $0,(%si)
716         jnz     3f
718         popw    %si
719         clc
720         ret                             // Match found
724         popw    %si
725         addw    8(%si), %si
727         jmp     ntfs_find_grldr
729 // Locate an attribute
730 // Input:
731 //     DI - pointer to buffer
732 //     AL - attribute
733 ntfs_locate_attr:
734         call    ntfs_init_attr
735         call    ntfs_find_attr
736         jc      1f
738         testb   $NT_FG_ALST, nt_flag
739         jnz     2f
740         call    ntfs_find_attr
741         jnc     2b
742         call    ntfs_init_attr
743         call    ntfs_find_attr
745         clc
747         ret
749 // Prepare to find attribute
750 // Input:
751 //     DI - pointer to buffer
752 ntfs_init_attr:
753         pushw   %ax
754         xorw    %ax, %ax
755         movw    %ax, nt_flag
756         movw    %ax, nt_attr_end
757         movw    nt_attr_ofs, %ax
758         addw    %di, %ax
759         movw    %ax, nt_attr_nxt
760         popw    %ax
761         cmpw    $MMFT_BASE, %di
762         jnz     1f
763         orb     $NT_FG_MMFT, nt_flag
765         ret
767 // Find an attribute
768 // Input:
769 //     DI - pointer to buffer
770 //     AL - attribute
771 // Output:
772 //     SI - current item
773 //     CF - status
774 ntfs_find_attr:
775         movw    nt_attr_nxt, %bx
776         testb   $NT_FG_ALST, nt_flag
777         jnz     6f
779         movw    %bx, %si
780         cmpb    $0xFF, (%si)
781         jz      3f
783         cmpb    $AT_ATTRIBUTE_LIST, (%si)
784         jnz     2f
785         movw    %si, nt_attr_end
787         addw    4(%bx), %bx
788         cmpb    %al, (%si)
789         jnz     1b
790         movw    %bx, nt_attr_nxt
791         movw    %si, nt_attr_cur
793         ret
795         cmpw    $1, nt_attr_end
796         jb      2b
797         movw    nt_attr_end, %si
798         cmpb    $0, 8(%si)
799         jnz     4f
800         movw    %si, %bx
801         addw    0x14(%bx), %bx
802         addw    4(%si), %si
803         jmp     5f
805         movl    0x28(%si), %ecx
806         shrl    $9, %ecx
807         cmpw    $8, %cx
808         ja      NTFS_Corrupt_Error
809         leaw    nt_edat_buf, %bx
810         pushw   %ax
811         xorl    %edx, %edx
812         call    ntfs_read_data
813         popw    %ax
814         jc      2b
815         movw    0x30(%si), %si
816         addw    %bx, %si
818         movw    %si, nt_attr_end
819         orb     $NT_FG_ALST, nt_flag
820         testb   $NT_FG_MMFT, nt_flag
821         jz      6f
822         cmpb    $AT_DATA, %al
823         jnz     6f
824         call    ntfs_fix_mmft
826         movw    %bx, %si
827         cmpw    nt_attr_end, %bx
828         jb      1f
830         stc
831         ret
833         addw    4(%bx), %bx
834         cmpb    %al, (%si)
835         jnz     6b
837         pushw   %ax
838         pushw   %es
839         pushw   %ds
840         popw    %es
841         movw    %si, nt_attr_cur
842         movw    %bx, nt_attr_nxt
843         movl    0x10(%si), %eax
844         leaw    nt_emft_buf, %bx
845         testb   $NT_FG_MMFT, nt_flag
846         jnz     2f
847         call    ntfs_read_mft
848         jmp     3f
850         pushw   %bx
851         call    readDisk_nt
852         movl    0x14(%si), %eax
853         call    readDisk_nt
854         popw    %bx
855         cmpw    $0x4946, (%bx)                  // "FI"
856         jnz     NTFS_Corrupt_Error
857         movw    $2, %cx
858         call    ntfs_fixup
860         popw    %es
861         popw    %ax
862         addw    0x14(%bx), %bx
864         cmpb    $0xFF, (%bx)
865         jz      7b
866         cmpb    %al, (%bx)
867         jz      5f
868         addw    4(%bx), %bx
869         jmp     4b
871         movw    %bx, %si
872         ret
874 // Fix $MFT
875 // Input:
876 //     DI - pointer to buffer
877 //     BX - attr cur
878 ntfs_fix_mmft:
879         pushw   %ax
880         orb     $NT_FG_GPOS, nt_flag
883         cmpw    nt_attr_end, %bx
884         jae     NTFS_Corrupt_Error
885         cmpb    %al, (%bx)
886         jz      2f
887         addw    4(%bx), %bx
888         jmp     1b
891         movw    %bx, nt_attr_cur
893         movl    nt_mft_start, %eax
894         movl    %eax, 0x10(%bx)
895         incl    %eax
896         movl    %eax, 0x14(%bx)
898         addw    4(%bx), %bx
900         cmpw    nt_attr_end, %bx
901         jae     2f
902         cmpb    $AT_DATA, (%bx)
903         jnz     2f
905         movl    0x10(%bx), %edx
906         movb    nt_mft_size, %cl
907         shll    %cl, %edx
909         call    ntfs_read_attr
911         orl     %eax, %eax
912         jz      NTFS_Corrupt_Error
913         movl    %eax, 0x10(%bx)
914         movl    %edx, 0x14(%bx)
915         jmp     1b
917         movw    nt_attr_cur, %bx
918         andb    $(~NT_FG_GPOS), nt_flag
919         popw    %ax
921         ret
923 // Read MFT record
924 // Input:
925 //     DS:BX - buffer
926 //     EAX - mft number
927 ntfs_read_mft:
928         pushw   %di
929         movw    $MMFT_BASE, %di
930         movb    nt_mft_size, %cl
931         shll    %cl, %eax
932         movl    %eax, %edx
933         movl    $1, %eax
934         shll    %cl, %eax
935         movl    %eax, %ecx
936         call    ntfs_read_attr
937         jc      NTFS_Corrupt_Error
938         cmpw    $0x4946, (%bx)                  // "FI"
939         jnz     NTFS_Corrupt_Error
940         call    ntfs_fixup
941         popw    %di
942         ret
944 // Read attribute
945 // Input:
946 //     DI - pointer to buffer
947 //     ES:BX - buffer
948 //     EDX - start sector
949 //     ECX - sector count
950 // Output:
951 //     CF - status
952 ntfs_read_attr:
953         pushw   nt_attr_cur
954         pushl   %edx
955         pushl   %ecx
956         pushw   %bx
958         movw    nt_attr_cur, %si
959         movb    (%si), %al
961         testb   $NT_FG_ALST, nt_flag
962         jz      2f
963         movw    %si, %bx
964         movb    nt_spc, %cl
965         shrl    %cl, %edx
968         cmpw    nt_attr_end, %bx
969         jae     2f
970         cmpb    %al, (%bx)
971         jnz     2f
972         cmpl    %edx, 8(%bx)
973         ja      2f
974         movw    %bx, %si
975         addw    4(%bx), %bx
976         jmp     1b
979         movw    %si, nt_attr_nxt
980         call    ntfs_find_attr
982         popw    %bx
983         popl    %ecx
984         popl    %edx
985         jc      1f
986         call    ntfs_read_data
987         clc
989         popw    nt_attr_cur
990         ret
992 // Read data
993 // Input:
994 //     DI: pointer to buffer
995 //     SI: current item
996 //     ES:BX: buffer
997 //     EDX: start sector
998 //     ECX: sector count
999 ntfs_read_data:
1000         pushw   %cx
1001         pushw   %bx
1002         testb   $1, 8(%si)
1003         jz      NTFS_Corrupt_Error
1004         movb    0xC(%si), %al
1005         andb    $1, %al
1006         orb     %al, nt_flag
1008         movl    %ecx, nt_read_count
1009         movb    nt_spc, %cl
1011         movl    %edx, %eax
1012         shrl    %cl, %eax
1013         movl    %eax, nt_target_vcn
1014         shll    %cl, %eax
1015         subl    %eax, %edx
1016         movl    %edx, nt_vcn_offset
1018         xorw    %dx, %dx                // edx - next VCN
1019         movl    %edx, nt_curr_lcn
1021         movl    0x10(%si), %edx
1023         addw    0x20(%si), %si
1025         call    ntfs_runlist_read_block
1027         cmpl    nt_target_vcn, %edx
1028         jbe     1b
1030         movb    nt_spc, %cl
1032         orl     %eax, %eax              // sparse
1033         jz      2f
1035         movl    nt_target_vcn, %eax
1036         subl    nt_curr_vcn, %eax
1037         addl    nt_curr_lcn, %eax
1039         shll    %cl, %eax
1040         addl    nt_vcn_offset, %eax
1042         testb   $NT_FG_GPOS, nt_flag
1043         jz      3f
1044         pushl   %eax
1045         incl    %eax
1046         subl    nt_curr_vcn, %edx
1047         addl    nt_curr_lcn, %edx
1048         shll    %cl, %edx
1049         cmpl    %eax, %edx
1050         jnz     4f
1051         pushw   %cx
1052         call    ntfs_runlist_read_block
1053         popw    %cx
1054         movl    nt_curr_lcn, %eax
1055         shll    %cl, %eax
1057         movl    %eax, %edx
1058         popl    %eax
1059         addl    (nt_part_ofs - Entry_nt)(%bp), %edx
1062         addl    (nt_part_ofs - Entry_nt)(%bp), %eax
1065         testb   $NT_FG_GPOS, nt_flag
1066         jnz     1f
1068         pushl   %ebx
1069         movl    %edx, %ebx
1070         subl    nt_target_vcn, %ebx
1071         shll    %cl, %ebx
1072         movl    %ebx, %ecx
1073         popl    %ebx
1075         subl    nt_vcn_offset, %ecx
1076         movl    $0, nt_vcn_offset
1077         cmpl    nt_read_count, %ecx
1078         jbe     2f
1079         movl    nt_read_count, %ecx
1082         pushl   %ecx
1084         orl     %eax, %eax
1085         jnz     3f
1086         call    ntfs_sparse_block
1087         jmp     4f
1090         call    readDisk_nt
1091         loop    3b
1094         popl    %ecx
1095         subl    %ecx, nt_read_count
1096         jbe     1f
1098         movl    %edx, nt_target_vcn
1099         call    ntfs_runlist_read_block
1100         jmp     1b
1103         popw    %bx
1104         popw    %cx
1105         ret
1107 // Read run list data
1108 // Input:
1109 //     CL = number of bytes
1110 // Output:
1111 //     EAX = read bytes
1112 //     SI points to the next unhandled byte
1114 ntfs_runlist_read_data:
1115         pushw   %cx
1116         orb     %cl, %cl
1117         jnz     1f
1118         popw    %cx
1119         xorl    %eax, %eax
1120         ret
1122         lodsb   (%si), %al
1123         rorl    $8, %eax
1124         decb    %cl
1125         jnz     1b
1127         popw    %cx
1128         negb    %cl
1129         add     $4, %cl
1130         shlb    $3, %cl
1131         ret
1133 NTFS_Run_Overflow_Error:
1134         movb    $NTFS_Run_Overflow_Error_Code, %al
1135         jmp     NTFS_Error
1137 // Read run list block
1138 // Output:
1139 //     EDX = Next VCN
1140 //     SI points to the next unhandled byte
1142 ntfs_runlist_read_block:
1143         lodsb   (%si), %al
1144         movb    %al, %cl
1145         movb    %cl, %ch
1146         andb    $0xF, %cl               // cl - Size of length field
1147         jz      1f
1148         shrb    $0x4, %ch               // ch - Size of offset field
1150         call    ntfs_runlist_read_data
1151         shrl    %cl, %eax
1153         movl    %edx, nt_curr_vcn
1154         addl    %eax, %edx
1156         movb    %ch, %cl
1157         call    ntfs_runlist_read_data
1158         sarl    %cl, %eax
1160         addl    %eax, nt_curr_lcn
1162         ret
1165         testb   $NT_FG_ALST, nt_flag
1166         jz      NTFS_Run_Overflow_Error
1168         pushl   %edx
1169         pushw   %bx
1170         movw    nt_attr_cur, %si
1171         movb    (%si), %al
1172         call    ntfs_find_attr
1173         jc      NTFS_Run_Overflow_Error
1174         cmpb    $0, 8(%si)
1175         jz      NTFS_Run_Overflow_Error
1176         movl    $0, nt_curr_lcn
1177         popw    %bx
1178         popl    %edx
1179         addw    0x20(%si), %si
1180         jmp     ntfs_runlist_read_block
1182 // Convert seg:ofs to linear address
1183 // Input:
1184 //     On stack: seg:ofs
1185 // Output:
1186 //     eax:
1187 seg_to_lin:
1188         pushw   %bp
1189         movw    %sp, %bp
1190         xorl    %eax, %eax
1191         xchgw   6(%bp), %ax
1192         shll    $4, %eax
1193         addl    4(%bp), %eax
1194         popw    %bp
1195         ret     $4
1197 // Convert linear address to seg:ofs
1198 // Input:
1199 //     on stack: linear address
1200 // Output:
1201 //     On stack: seg:ofs
1202 lin_to_seg:
1203         pushw   %bp
1204         movw    %sp, %bp
1205         shll    $12, 4(%bp)
1206         shrw    $12, 4(%bp)
1207         popw    %bp
1208         ret
1210 fix_segs:
1211         pushw   %ds
1212         pushw   %si
1213         call    seg_to_lin
1214         pushl   %eax
1215         call    lin_to_seg
1216         popw    %si
1217         popw    %ds
1219 fix_es_di:
1220         pushw   %es
1221         pushw   %di
1222         call    seg_to_lin
1223         pushl   %eax
1224         call    lin_to_seg
1225         popw    %di
1226         popw    %es
1227         ret
1229 // Handle sparse block
1230 //     DI: points to buffer
1231 //     ES:BX: points to buffer
1232 //     ECX: number of sectors
1233 //     EDX: next VCN
1235 ntfs_sparse_block:
1236         pushw   %di
1237         pushl   %edx
1239         shll    $9, %ecx                // ecx - totel number of bytes
1241         testb   $1, nt_flag             // Not compressed
1242         jz      2f
1244         xorl    %edx, %edx
1245         movb    nt_target_vcn, %dl
1246         andb    $0xF, %dl
1247         jz      2f
1249         movw    %bx, %di
1251         pushw   %cx
1253         movb    nt_spc, %cl
1254         addb    $9, %cl
1255         shll    %cl, %edx               // edx: offset from the start of cluster
1257         push    %es
1258         push    %di
1259         call    seg_to_lin
1260         subl    %edx, %eax              // eax: linear address
1262         movl    $16, nt_remain_len
1263         shll    %cl, nt_remain_len
1265         popw    %cx
1267         addl    %edx, %ecx
1268         subl    nt_remain_len, %ecx
1270         pushl   %ecx
1271         call    ntfs_decomp_block
1272         popl    %ecx
1274         addl    nt_remain_len, %ecx
1276         jecxz   1f
1278         movw    %di, %bx
1281         movw    %bx, %di
1282         movl    %ecx, %edx
1283         xorl    %eax, %eax
1284         movl    %eax, %ecx
1285         call    fix_es_di
1288         movw    $0x8000, %cx
1289         cmpl    %edx, %ecx
1290         jbe     4f
1291         movw    %dx, %cx
1293         pushw   %cx
1294         shrw    $2, %cx
1296         rep     stosl   %eax, %es:(%di)
1297         call    fix_es_di
1298         popw    %cx
1299         subl    %ecx, %edx
1300         jnz     3b
1303         movw    %di, %bx
1305         popl    %edx
1306         popw    %di
1308         ret
1310 // Decompress block
1311 // Input:
1312 //     eax: linear address at the beginning of the compressed block
1313 // Output:
1314 //     ES:DI: points to the end of the block
1315 ntfs_decomp_block:
1316         pushw   %ds
1317         pushw   %si
1319         pushl   %eax
1320         call    lin_to_seg
1321         popw    %si
1322         popw    %ds
1323         movl    nt_remain_len, %edx
1324         addl    %edx, %eax
1325         pushl   %eax
1326         call    lin_to_seg
1327         popw    %di
1328         popw    %es
1330         pushw   %es
1331         pushw   %di
1332         pushw   %ds
1333         pushw   %si
1335         xorl    %ecx, %ecx
1338         movw    $0x8000, %cx
1339         cmpl    %edx, %ecx
1340         jbe     2f
1341         movw    %dx, %cx
1343         pushw   %cx
1344         shrw    $2, %cx
1345         rep     movsl   (%si), %es:(%di)
1346         call    fix_segs
1347         popw    %cx
1348         subl    %ecx, %edx
1349         jnz     1b
1351         popw    %di
1352         popw    %es
1353         popw    %si
1354         popw    %ds
1357         xorl    %edx, %edx                      // edx - copied bytes
1359         lodsw   (%si), %ax
1360         testb   $0x80, %ah
1361         jnz     2f
1362         movw    $0x800, %cx
1363         rep     movsw   (%si), %es:(%di)
1364         movw    $0x1000, %dx
1365         jmp     7f                              // The block is not compressed
1368         movw    %ax, %cx
1369         andw    $0xFFF, %cx
1370         incw    %cx                             // ecx = block length
1371         addw    %si, %cx                        // cx: end marker
1372         xorb    %bh, %bh
1375         cmpw    $0x1000, %dx
1376         ja      NTFS_Decompress_Error
1378         orb     %bh, %bh
1379         jnz     4f
1380         lodsb   (%si), %al
1381         movb    %al, %bl                        // bl: tag, bh: count
1382         movb    $8, %bh
1385         testb   $1, %bl
1386         jz      5f
1388         movw    %dx, %ax
1389         decw    %ax
1391         pushw   %cx
1392         pushw   %bx
1394         movb    $12, %cl
1396         cmpw    $0x10, %ax
1397         jb      6f
1398         shrw    $1, %ax
1399         decb    %cl
1400         jmp     6b
1403         lodsw   (%si), %ax
1404         movw    %ax, %bx
1405         shrw    %cl, %bx                        // bx: delta
1407         pushw   %dx
1408         movw    $1, %dx
1409         shlw    %cl, %dx
1410         decw    %dx
1411         andw    %dx, %ax
1412         popw    %dx
1414         addw    $3, %ax
1415         movw    %ax, %cx                        // cx: length
1416         negw    %bx
1417         decw    %bx
1420         movb    %es:(%bx, %di), %al
1421         stosb   %al, %es:(%di)
1422         incw    %dx
1423         loop    6b
1425         popw    %bx
1426         popw    %cx
1427         jmp     4f
1430         movsb   (%si), %es:(%di)
1431         incw    %dx
1433         shrb    $1, %bl
1434         decb    %bh
1436         cmpw    %cx, %si
1437         jb      3b
1440         call    fix_segs
1442         subl    %edx, nt_remain_len     // End of block
1443         jz      1f
1445         cmpw    $0x1000, %dx
1446         je      1b
1450         popw    %si
1451         popw    %ds
1452         ret
1454 NTFS_Decompress_Error:
1455         pushw   %ss
1456         popw    %ds
1457         movb    $NTFS_Decompress_Error_Code, %al
1458         jmp     NTFS_Error
1461 do_pause:
1462         .byte   0
1464 pause:
1465         cmpb    $0, (do_pause - Entry_nt)(%bp)
1466         jnz     1f
1467         ret
1469         xorw    %bp, %bp
1471         jmp     1b
1475 hex_out:
1476         pushw   %bp
1477         movw    %sp, %bp
1478         pushaw
1479         movb    $0xE, %ah
1480         movw    $7, %bx
1481         movw    $4, %cx
1482         movw    4(%bp), %dx
1484         rol     $4, %dx
1485         movb    %dl, %al
1486         andb    $0xF, %al
1487         cmpb    $10, %al
1488         jb      2f
1489         subb    $('0'-'A'+10), %al
1491         addb    $'0', %al
1492         int     $0x10
1493         loop    1b
1494         movb    $' ', %al
1495         int     $0x10
1496         popaw
1497         popw    %bp
1498         ret     $2
1501         . = Entry_nt + 0x7fc
1503 nt_sector_mark:
1504         .long   0x42555247              // "GRUB"