Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ; Copyright (c) 2008-2009, diamond
  2. ; All rights reserved.
  3. ;
  4. ; Redistribution and use in source and binary forms, with or without
  5. ; modification, are permitted provided that the following conditions are met:
  6. ;       * Redistributions of source code must retain the above copyright
  7. ;       notice, this list of conditions and the following disclaimer.
  8. ;       * Redistributions in binary form must reproduce the above copyright
  9. ;       notice, this list of conditions and the following disclaimer in the
  10. ;       documentation and/or other materials provided with the distribution.
  11. ;       * Neither the name of the <organization> nor the
  12. ;       names of its contributors may be used to endorse or promote products
  13. ;       derived from this software without specific prior written permission.
  14. ;
  15. ; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
  16. ; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. ; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  19. ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22. ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. ;*****************************************************************************
  26.  
  27. ; KordOS bootloader, based on mtldr, KolibriOS bootloader, by diamond
  28. ; It is used when main bootloader is Windows loader.
  29.  
  30. ; this code is loaded:
  31. ; NT/2k/XP: by ntldr to 0D00:0000
  32. ; 9x: by io.sys from config.sys to xxxx:0100
  33. ; Vista: by bootmgr to 0000:7C00
  34.         format binary
  35.         use16
  36.  
  37. ; in any case, we relocate this code to 0000:0600
  38.         org 0x600
  39. ; entry point for 9x and Vista booting
  40.         call    @f
  41.         db      'NTFS'
  42. @@:
  43.         pop     si
  44.         sub     si, 3
  45.         cmp     si, 100h
  46.         jnz     boot_vista
  47.         mov     si, load_question + 100h - 600h
  48.         call    out_string
  49. ;       mov     si, answer + 100h - 0600h               ; already is
  50. xxy:
  51.         mov     ah, 0
  52.         int     16h
  53.         or      al, 20h
  54.         mov     [si], al
  55.         cmp     al, 'y'
  56.         jz      xxz
  57.         cmp     al, 'n'
  58.         jnz     xxy
  59. ; continue load Windows
  60. ;       call    out_string
  61. ;       ret
  62. out_string:
  63.         push    bx
  64. @@:
  65.         lodsb
  66.         test    al, al
  67.         jz      @f
  68.         mov     ah, 0Eh
  69.         mov     bx, 7
  70.         int     10h
  71.         jmp     @b
  72. @@:
  73.         pop     bx
  74.         ret
  75. xxz:
  76. ; boot KordOS
  77.         call    out_string
  78. ; 9x bootloader has already hooked some interrupts; to correctly remove all DOS handlers,
  79. ; issue int 19h (reboot interrupt) and trace its DOS handler until original BIOS handler is reached
  80.         xor     di, di
  81.         mov     ds, di
  82.         mov     word [di+4], new01handler + 100h - 600h
  83.         mov     [di+6], cs
  84.         pushf
  85.         pop     ax
  86.         or      ah, 1
  87.         push    ax
  88.         popf
  89. ; we cannot issue INT 19h directly, because INT command clears TF
  90. ;       int     19h     ; don't issue it directly, because INT command clears TF
  91. ; so instead we use direct call
  92. ;       pushf           ; there will be no IRET
  93.         call    far [di + 19h*4]
  94. xxt:
  95.         xor     di, di
  96.         mov     ds, di
  97.         cmp     word [di + 8*4+2], 0F000h
  98.         jz      @f
  99.         les     bx, [di + 8*4]
  100.         mov     eax, [es:bx+1]
  101.         mov     [di + 8*4], eax
  102. @@:
  103.         mov     si, 100h
  104. boot_vista:
  105. ; relocate cs:si -> 0000:0600
  106.         push    cs
  107.         pop     ds
  108.         xor     ax, ax
  109.         mov     es, ax
  110.         mov     di, 0x600
  111.         mov     cx, 2000h/2
  112.         rep movsw
  113.         jmp     0:real_entry
  114.  
  115. load_question   db      'Load KordOS? [y/n]: ',0
  116. answer  db      ?
  117.         db      13,10,0
  118.  
  119. new01handler:
  120. ; [sp]=ip, [sp+2]=cs, [sp+4]=flags
  121.         push    bp
  122.         mov     bp, sp
  123.         push    ds
  124.         lds     bp, [bp+2]
  125.         cmp     word [ds:bp], 19cdh
  126.         jz      xxt
  127.         pop     ds
  128.         pop     bp
  129.         iret
  130.  
  131. ; read from hard disk
  132. ; in: eax = absolute sector
  133. ;     cx = number of sectors
  134. ;     es:bx -> buffer
  135. ; out: CF=1 if error
  136. read:
  137.         pushad
  138.         add     eax, [bp + partition_start - dat]
  139.         cmp     [bp + use_lba - dat], 0
  140.         jz      .chs
  141. ; LBA read
  142.         push    ds
  143. .lbado:
  144.         push    ax
  145.         push    cx
  146.         cmp     cx, 0x7F
  147.         jbe     @f
  148.         mov     cx, 0x7F
  149. @@:
  150. ; create disk address packet on the stack
  151. ; dq starting LBA
  152.         push    0
  153.         push    0
  154.         push    eax
  155. ; dd buffer
  156.         push    es
  157.         push    bx
  158. ; dw number of blocks to transfer (no more than 0x7F)
  159.         push    cx
  160. ; dw packet size in bytes
  161.         push    10h
  162. ; issue BIOS call
  163.         push    ss
  164.         pop     ds
  165.         mov     si, sp
  166.         mov     dl, [bp + boot_drive - dat]
  167.         mov     ah, 42h
  168.         int     13h
  169.         jc      .disk_error_lba
  170.         add     sp, 10h         ; restore stack
  171. ; increase current sector & buffer; decrease number of sectors
  172.         movzx   esi, cx
  173.         mov     ax, es
  174.         shl     cx, 5
  175.         add     ax, cx
  176.         mov     es, ax
  177.         pop     cx
  178.         pop     ax
  179.         add     eax, esi
  180.         sub     cx, si
  181.         jnz     .lbado
  182.         pop     ds
  183.         popad
  184.         ret
  185. .disk_error_lba:
  186.         add     sp, 14h
  187.         pop     ds
  188.         popad
  189.         stc
  190.         ret
  191.  
  192. .chs:
  193.         pusha
  194.         pop     edi             ; loword(edi) = di, hiword(edi) = si
  195.         push    bx
  196.  
  197. ; eax / (SectorsPerTrack) -> eax, remainder bx
  198.         movzx   esi, [bp + sectors - dat]
  199.         xor     edx, edx
  200.         div     esi
  201.         mov     bx, dx          ; bx = sector-1
  202.  
  203. ; eax -> dx:ax
  204.         push    eax
  205.         pop     ax
  206.         pop     dx
  207. ; (dword in dx:ax) / (NumHeads) -> (word in ax), remainder dx
  208.         div     [bp + heads - dat]
  209.  
  210. ; number of sectors: read no more than to end of track
  211.         sub     si, bx
  212.         cmp     cx, si
  213.         jbe     @f
  214.         mov     cx, si
  215. @@:
  216.  
  217.         inc     bx
  218. ; now ax=track, dl=head, dh=0, cl=number of sectors, ch=0, bl=sector
  219. ; convert to int13 format
  220.         movzx   edi, cx
  221.         mov     dh, dl
  222.         mov     dl, [bp + boot_drive - dat]
  223.         shl     ah, 6
  224.         mov     ch, al
  225.         mov     al, cl
  226.         mov     cl, bl
  227.         or      cl, ah
  228.         pop     bx
  229.         mov     si, 3
  230.         mov     ah, 2
  231. @@:
  232.         push    ax
  233.         int     13h
  234.         jnc     @f
  235.         xor     ax, ax
  236.         int     13h     ; reset drive
  237.         pop     ax
  238.         dec     si
  239.         jnz     @b
  240.         add     sp, 12
  241.         popad
  242.         stc
  243.         ret
  244. @@:
  245.         pop     ax
  246.         mov     ax, es
  247.         mov     cx, di
  248.         shl     cx, 5
  249.         add     ax, cx
  250.         mov     es, ax
  251.         push    edi
  252.         popa
  253.         add     eax, edi
  254.         sub     cx, di
  255.         jnz     .chs
  256.         popad
  257.         ret
  258.  
  259. disk_error2     db      'Fatal: cannot read partitions info: '
  260. disk_error_msg  db      'disk read error',0
  261. disk_params_msg db      'Fatal: cannot get drive parameters',0
  262. start_msg       db      2,' KordOS bootloader',13,10,0
  263. part_msg        db      'looking at partition '
  264. part_char       db      '0'     ; will be incremented before writing message
  265.                 db      ' ... ',0
  266. errfs_msg       db      'unknown filesystem',13,10,0
  267. fatxx_msg       db      'FATxx'
  268. newline         db      13,10,0
  269. ntfs_msg        db      'NTFS',13,10,0
  270. error_msg       db      'Error'
  271. colon           db      ': ',0
  272. root_string     db      '\',0
  273. nomem_msg       db      'No memory',0
  274. filesys_string  db      '(filesystem)',0
  275. directory_string db     'is a directory',0
  276. notdir_string   db      'not a directory',0
  277.  
  278. ; entry point for NT/2k/XP booting
  279. ; ntldr loads our code to 0D00:0000 and jumps to 0D00:0256
  280.         repeat  600h + 256h - $
  281.                 db      1       ; any data can be here; 1 in ASCII is a nice face :)
  282.         end repeat
  283. ; cs=es=0D00, ds=07C0, ss=0
  284. ; esi=edi=ebp=0, esp=7C00
  285.         xor     si, si
  286.         jmp     boot_vista
  287.  
  288. real_entry:
  289. ; ax = 0
  290.         mov     ds, ax
  291.         mov     es, ax
  292. ; our stack is 4 Kb: memory range 2000-3000
  293.         mov     ss, ax
  294.         mov     sp, 3000h
  295.         mov     bp, dat
  296.         sti     ; just for case
  297. ; say hi to user
  298.         mov     si, start_msg
  299.         call    out_string
  300. ; we are booting from hard disk identified by [boot_drive]
  301.         mov     dl, [bp + boot_drive - dat]
  302. ; is LBA supported?
  303.         mov     [bp + use_lba - dat], 0
  304.         mov     ah, 41h
  305.         mov     bx, 55AAh
  306.         int     13h
  307.         jc      .no_lba
  308.         cmp     bx, 0AA55h
  309.         jnz     .no_lba
  310.         test    cl, 1
  311.         jz      .no_lba
  312.         inc     [bp + use_lba - dat]
  313.         jmp     disk_params_ok
  314. .no_lba:
  315. ; get drive geometry
  316.         mov     ah, 8
  317.         mov     dl, [bp + boot_drive - dat]
  318.         int     13h
  319.         jnc     @f
  320.         mov     si, disk_params_msg
  321.         call    out_string
  322.         jmp     $
  323. @@:
  324.         movzx   ax, dh
  325.         inc     ax
  326.         mov     [bp + heads - dat], ax
  327.         and     cx, 3Fh
  328.         mov     [bp + sectors - dat], cx
  329. disk_params_ok:
  330. ; determine size of cache for folders
  331.         int     12h     ; ax = size of available base memory in Kb
  332.         sub     ax, 94000h / 1024
  333.         jc      nomem
  334.         shr     ax, 3
  335.         mov     [bp + cachelimit - dat], ax     ; size of cache - 1
  336. ; scan all partitions
  337. new_partition_ex:
  338.         xor     eax, eax        ; read first sector of current disk area
  339.         mov     [bp + extended_part_cur - dat], eax     ; no extended partition yet
  340.         mov     [bp + cur_partition_ofs - dat], 31BEh   ; start from first partition
  341.         push    es
  342.         mov     cx, 1
  343.         mov     bx, 3000h
  344.         call    read
  345.         pop     es
  346.         jnc     new_partition
  347.         mov     si, disk_error2
  348.         call    out_string
  349.         jmp     $
  350. new_partition:
  351.         mov     bx, [bp + cur_partition_ofs - dat]
  352.         mov     al, [bx+4]      ; partition type
  353.         test    al, al
  354.         jz      next_partition
  355.         cmp     al, 5
  356.         jz      @f
  357.         cmp     al, 0xF
  358.         jnz     not_extended
  359. @@:
  360. ; extended partition
  361.         mov     eax, [bx+8]     ; partition start
  362.         add     eax, [bp + extended_part_start - dat]
  363.         mov     [bp + extended_part_cur - dat], eax
  364. next_partition:
  365.         add     [bp + cur_partition_ofs - dat], 10h
  366.         cmp     [bp + cur_partition_ofs - dat], 31FEh
  367.         jb      new_partition
  368.         mov     eax, [bp + extended_part_cur - dat]
  369.         test    eax, eax
  370.         jz      partitions_done
  371.         cmp     [bp + extended_part_start - dat], 0
  372.         jnz     @f
  373.         mov     [bp + extended_part_start - dat], eax
  374. @@:
  375.         mov     [bp + extended_parent - dat], eax
  376.         mov     [bp + partition_start - dat], eax
  377.         jmp     new_partition_ex
  378. partitions_done:
  379.         mov     si, total_kaput
  380.         call    out_string
  381.         jmp     $
  382. not_extended:
  383.         mov     eax, [bx+8]
  384.         add     eax, [bp + extended_parent - dat]
  385.         mov     [bp + partition_start - dat], eax
  386. ; try to load from current partition
  387. ; inform user
  388.         mov     si, part_msg
  389.         inc     [si + part_char - part_msg]
  390.         call    out_string
  391. ; read bootsector
  392.         xor     eax, eax
  393.         mov     [bp + cur_obj - dat], filesys_string
  394.         push    es
  395.         mov     cx, 1
  396.         mov     bx, 3200h
  397.         call    read
  398.         pop     es
  399.         mov     si, disk_error_msg
  400.         jc      find_error_si
  401.         movzx   si, byte [bx+13]
  402.         mov     word [bp + sect_per_clust - dat], si
  403.         test    si, si
  404.         jz      unknown_fs
  405.         lea     ax, [si-1]
  406.         test    si, ax
  407.         jnz     unknown_fs
  408. ; determine file system
  409. ; Number of bytes per sector == 0x200 (this loader assumes that physical sector size is 200h)
  410.         cmp     word [bx+11], 0x200
  411.         jnz     unknown_fs
  412. ; is it NTFS?
  413.         cmp     dword [bx+3], 'NTFS'
  414.         jnz     not_ntfs
  415.         cmp     byte [bx+16], bl
  416.         jz      ntfs
  417. not_ntfs:
  418. ; is it FAT? FAT12/FAT16/FAT32?
  419. ; get count of sectors to dword in cx:si
  420.         mov     si, [bx+19]
  421.         xor     cx, cx
  422.         test    si, si
  423.         jnz     @f
  424.         mov     si, [bx+32]
  425.         mov     cx, [bx+34]
  426. @@:
  427.         xor     eax, eax
  428. ; subtract size of system area
  429.         sub     si, [bx+14]     ; BPB_ResvdSecCnt
  430.         sbb     cx, ax
  431.         mov     ax, [bx+17]     ; BPB_RootEntCnt
  432.         add     ax, 0xF
  433.         rcr     ax, 1
  434.         shr     ax, 3
  435.         sub     si, ax
  436.         sbb     cx, 0
  437.         push    cx
  438.         push    si
  439.         mov     ax, word [bx+22]
  440.         test    ax, ax
  441.         jnz     @f
  442.         mov     eax, [bx+36]
  443. @@:
  444.         movzx   ecx, byte [bx+16]
  445.         imul    ecx, eax
  446.         pop     eax
  447.         sub     eax, ecx
  448. ; now eax = count of sectors in the data region
  449.         xor     edx, edx
  450.         div     [bp + sect_per_clust - dat]
  451. ; now eax = count of clusters in the data region
  452.         mov     si, fatxx_msg
  453.         cmp     eax, 0xFFF5
  454.         jae     test_fat32
  455. ; test magic value in FAT bootsector - FAT12/16 bootsector has it at the offset +38
  456.         cmp     byte [bx+38], 0x29
  457.         jnz     not_fat
  458.         cmp     ax, 0xFF5
  459.         jae     fat16
  460. fat12:
  461.         mov     [bp + get_next_cluster_ptr - dat], fat12_get_next_cluster
  462.         mov     di, cx          ; BPB_NumFATs
  463.         mov     ax, '12'
  464.         push    ax              ; save for secondary loader
  465.         mov     word [si+3], ax
  466.         call    out_string
  467.         movzx   ecx, word [bx+22]       ; BPB_FATSz16
  468. ; FAT12: read entire FAT table (it is no more than 0x1000*3/2 = 0x1800 bytes)
  469. .fatloop:
  470. ; if first copy is not readable, try to switch to other copies
  471.         push    0x6000
  472.         pop     es
  473.         xor     bx, bx
  474.         movzx   eax, word [0x320E]      ; BPB_RsvdSecCnt
  475.         push    cx
  476.         cmp     cx, 12
  477.         jb      @f
  478.         mov     cx, 12
  479. @@:
  480.         call    read
  481.         pop     cx
  482.         jnc     fat1x_common
  483.         add     eax, ecx        ; switch to next copy of FAT
  484.         dec     di
  485.         jnz     .fatloop
  486.         mov     si, disk_error_msg
  487.         jmp     find_error_si
  488. fat16:
  489.         mov     [bp + get_next_cluster_ptr - dat], fat16_get_next_cluster
  490.         mov     ax, '16'
  491.         push    ax              ; save for secondary loader
  492.         mov     word [si+3], ax
  493.         call    out_string
  494. ; FAT16: init FAT cache - no sectors loaded
  495.         mov     di, 0x3400
  496.         xor     ax, ax
  497.         mov     cx, 0x100/2
  498.         rep stosw
  499. fat1x_common:
  500.         mov     bx, 0x3200
  501.         movzx   eax, word [bx+22]       ; BPB_FATSz16
  502.         xor     esi, esi        ; no root cluster
  503.         jmp     fat_common
  504. test_fat32:
  505. ; FAT32 bootsector has it at the offset +66
  506.         cmp     byte [bx+66], 0x29
  507.         jnz     not_fat
  508.         mov     [bp + get_next_cluster_ptr - dat], fat32_get_next_cluster
  509.         mov     ax, '32'
  510.         push    ax              ; save for secondary loader
  511.         mov     word [si+3], ax
  512.         call    out_string
  513. ; FAT32 - init cache for FAT table: no sectors loaded
  514.         lea     si, [bp + cache1head - dat]
  515.         mov     [si], si                ; no sectors in cache:
  516.         mov     [si+2], si              ; 'prev' & 'next' links point to self
  517.         mov     [bp + cache1end - dat], 3400h   ; first free item = 3400h
  518.         mov     [bp + cache1limit - dat], 3C00h
  519.         mov     eax, [bx+36]    ; BPB_FATSz32
  520.         mov     esi, [bx+44]    ; BPB_RootClus
  521.         jmp     fat_common
  522. not_fat:
  523. unknown_fs:
  524.         mov     si, errfs_msg
  525.         call    out_string
  526.         jmp     next_partition
  527. fat_common:
  528.         push    ss
  529.         pop     es
  530.         movzx   edx, byte [bx+16]       ; BPB_NumFATs
  531.         mul     edx
  532.         mov     [bp + root_start - dat], eax    ; this is for FAT1x
  533. ; eax = total size of all FAT tables, in sectors
  534.         movzx   ecx, word [bx+17]       ; BPB_RootEntCnt
  535.         add     ecx, 0xF
  536.         shr     ecx, 4
  537.         add     eax, ecx
  538.         mov     cx, word [bx+14]        ; BPB_RsvdSecCnt
  539.         add     [bp + root_start - dat], ecx    ; this is for FAT1x
  540.         add     eax, ecx
  541. ; cluster 2 begins from sector eax
  542.         movzx   ebx, byte [bx+13]       ; BPB_SecPerClus
  543.         sub     eax, ebx
  544.         sub     eax, ebx
  545.         mov     [bp + data_start - dat], eax
  546. ; no clusters in folders cache
  547.         mov     di, foldcache_clus - 2
  548.         xor     ax, ax
  549.         mov     cx, 7*8/2 + 1
  550.         rep stosw
  551.         mov     [bp + root_clus - dat], esi
  552. ; load secondary loader
  553.         mov     [bp + load_file_ptr - dat], load_file_fat
  554. load_secondary:
  555.         push    0x1000
  556.         pop     es
  557.         xor     bx, bx
  558.         mov     si, kernel_name
  559.         mov     cx, 0x30000 / 0x200
  560.         call    [bp + load_file_ptr - dat]
  561. ; say error if needed
  562.         mov     si, error_too_big
  563.         dec     bx
  564.         js      @f
  565.         jz      find_error_si
  566.         mov     si, disk_error_msg
  567.         jmp     find_error_si
  568. @@:
  569. ; fill loader information and jump to secondary loader
  570.         mov     al, 'h'         ; boot device: hard drive
  571.         mov     ah, [bp + boot_drive - dat]
  572.         sub     ah, 80h         ; boot device: identifier
  573.         pop     bx              ; restore file system ID ('12'/'16'/'32'/'nt')
  574.         mov     si, callback
  575.         jmp     1000h:0000h
  576.  
  577. nomem:
  578.         mov     si, nomem_msg
  579.         call    out_string
  580.         jmp     $
  581.  
  582. ntfs:
  583.         push    'nt'            ; save for secondary loader
  584.         mov     si, ntfs_msg
  585.         call    out_string
  586.         xor     eax, eax
  587.         mov     [bp + data_start - dat], eax
  588.         mov     ecx, [bx+40h]   ; frs_size
  589.         cmp     cl, al
  590.         jg      .1
  591.         neg     cl
  592.         inc     ax
  593.         shl     eax, cl
  594.         jmp     .2
  595. .1:
  596.         mov     eax, ecx
  597.         shl     eax, 9
  598. .2:
  599.         mov     [bp + frs_size - dat], ax
  600. ; standard value for frs_size is 0x400 bytes = 1 Kb, and it cannot be set different
  601. ; (at least with standard tools)
  602. ; we allow extra size, but no more than 0x1000 bytes = 4 Kb
  603.         mov     si, invalid_volume_msg
  604.         cmp     eax, 0x1000
  605.         ja      find_error_si
  606. ; must be multiple of sector size
  607.         test    ax, 0x1FF
  608.         jnz     find_error_si
  609.         shr     ax, 9
  610.         xchg    cx, ax
  611. ; initialize cache - no data loaded
  612.         lea     si, [bp + cache1head - dat]
  613.         mov     [si], si
  614.         mov     [si+2], si
  615.         mov     word [si+4], 3400h      ; first free item = 3400h
  616.         mov     word [si+6], 3400h + 8*8        ; 8 items in this cache
  617. ; read first MFT record - description of MFT itself
  618.         mov     [bp + cur_obj - dat], mft_string
  619.         mov     eax, [bx+30h]   ; mft_cluster
  620.         mul     [bp + sect_per_clust - dat]
  621.         push    0x8000
  622.         pop     es
  623.         xor     bx, bx
  624.         push    es
  625.         call    read
  626.         pop     ds
  627.         call    restore_usa
  628. ; scan for unnamed $DATA attribute
  629.         mov     [bp + freeattr - dat], 4000h
  630.         mov     ax, 80h
  631.         call    load_attr
  632.         push    ss
  633.         pop     ds
  634.         mov     si, nodata_string
  635.         jc      find_error_si
  636. ; load secondary loader
  637.         mov     [bp + load_file_ptr - dat], load_file_ntfs
  638.         jmp     load_secondary
  639.  
  640. find_error_si:
  641.         push    si
  642. find_error_sp:
  643.         cmp     [bp + in_callback - dat], 0
  644.         jnz     error_in_callback
  645.         push    ss
  646.         pop     ds
  647.         push    ss
  648.         pop     es
  649.         mov     si, error_msg
  650.         call    out_string
  651.         mov     si, [bp + cur_obj - dat]
  652. @@:
  653.         lodsb
  654.         test    al, al
  655.         jz      @f
  656.         cmp     al, '/'
  657.         jz      @f
  658.         mov     ah, 0Eh
  659.         mov     bx, 7
  660.         int     10h
  661.         jmp     @b
  662. @@:
  663.         mov     si, colon
  664.         call    out_string
  665.         pop     si
  666.         call    out_string
  667.         mov     si, newline
  668.         call    out_string
  669.         mov     sp, 0x3000
  670.         jmp     next_partition
  671. error_in_callback:
  672. ; return status: file not found, except for read errors
  673.         mov     bx, 2
  674.         cmp     si, disk_error_msg
  675.         jnz     @f
  676.         inc     bx
  677. @@:
  678.         mov     ax, 0xFFFF
  679.         mov     dx, ax
  680.         mov     sp, 3000h - 6
  681.         ret
  682.  
  683. callback:
  684. ; in: ax = function number; only functions 1 and 2 are defined for now
  685. ; save caller's stack
  686.         mov     dx, ss
  687.         mov     cx, sp
  688. ; set our stack (required because we need ss=0)
  689.         xor     si, si
  690.         mov     ss, si
  691.         mov     sp, 3000h
  692.         mov     bp, dat
  693.         mov     [bp + in_callback - dat], 1
  694.         push    dx
  695.         push    cx
  696. ; set ds:si -> ASCIIZ name
  697.         lea     si, [di+6]
  698. ; set cx = limit in sectors; 4Kb = 8 sectors
  699.         movzx   ecx, word [di+4]
  700.         shl     cx, 3
  701. ; set es:bx = pointer to buffer
  702.         les     bx, [di]
  703. ; call our function
  704.         stc     ; unsupported function
  705.         dec     ax
  706.         jz      callback_readfile
  707.         dec     ax
  708.         jnz     callback_ret
  709.         call    continue_load_file
  710.         jmp     callback_ret_succ
  711. callback_readfile:
  712. ; function 1: read file
  713. ; in: ds:di -> information structure
  714. ;       dw:dw   address
  715. ;       dw      limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
  716. ;       ASCIIZ  name
  717. ; out: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found, bx=3 - read error
  718. ; out: dx:ax = file size (0xFFFFFFFF if file was not found)
  719.         call    [bp + load_file_ptr - dat]
  720. callback_ret_succ:
  721.         clc
  722. callback_ret:
  723. ; restore caller's stack
  724.         pop     cx
  725.         pop     ss
  726.         mov     sp, cx
  727. ; return to caller
  728.         retf
  729.  
  730. read_file_chunk.resident:
  731. ; auxiliary label for read_file_chunk procedure
  732.         mov     di, bx
  733.         lodsw
  734. read_file_chunk.resident.continue:
  735.         mov     dx, ax
  736.         add     dx, 0x1FF
  737.         shr     dx, 9
  738.         cmp     dx, cx
  739.         jbe     @f
  740.         mov     ax, cx
  741.         shl     ax, 9
  742. @@:
  743.         xchg    ax, cx
  744.         rep movsb
  745.         xchg    ax, cx
  746.         clc     ; no disk error if no disk requests
  747.         mov     word [bp + num_sectors - dat], ax
  748.         ret
  749.  
  750. read_file_chunk:
  751. ; in: ds:si -> file chunk
  752. ; in: es:bx -> buffer for output
  753. ; in: ecx = maximum number of sectors to read (high word must be 0)
  754. ; out: CF=1 <=> disk read error
  755.         lodsb
  756.         mov     [bp + cur_chunk_resident - dat], al
  757.         test    al, al
  758.         jz      .resident
  759. ; normal case: load (non-resident) attribute from disk
  760. .read_block:
  761.         lodsd
  762.         xchg    eax, edx
  763.         test    edx, edx
  764.         jz      .ret
  765.         lodsd
  766. ; eax = start cluster, edx = number of clusters, cx = limit in sectors
  767.         imul    eax, [bp + sect_per_clust - dat]
  768.         add     eax, [bp + data_start - dat]
  769.         mov     [bp + cur_cluster - dat], eax
  770.         imul    edx, [bp + sect_per_clust - dat]
  771.         mov     [bp + num_sectors - dat], edx
  772.         and     [bp + cur_delta - dat], 0
  773. .nonresident.continue:
  774.         cmp     edx, ecx
  775.         jb      @f
  776.         mov     edx, ecx
  777. @@:
  778.         test    dx, dx
  779.         jz      .read_block
  780.         add     [bp + cur_delta - dat], edx
  781.         sub     [bp + num_sectors - dat], edx
  782.         sub     ecx, edx
  783.         push    cx
  784.         mov     cx, dx
  785.         call    read
  786.         pop     cx
  787.         jc      .ret
  788.         test    cx, cx
  789.         jnz     .read_block
  790. .ret:
  791.         ret
  792.  
  793. cache_lookup:
  794. ; in: eax = value to look, si = pointer to cache structure
  795. ; out: di->cache entry; CF=1 <=> the value was not found
  796.         push    ds bx
  797.         push    ss
  798.         pop     ds
  799.         mov     di, [si+2]
  800. .look:
  801.         cmp     di, si
  802.         jz      .not_in_cache
  803.         cmp     eax, [di+4]
  804.         jz      .in_cache
  805.         mov     di, [di+2]
  806.         jmp     .look
  807. .not_in_cache:
  808. ; cache miss
  809. ; cache is full?
  810.         mov     di, [si+4]
  811.         cmp     di, [si+6]
  812.         jnz     .cache_not_full
  813. ; yes, delete the oldest entry
  814.         mov     di, [si]
  815.         mov     bx, [di]
  816.         mov     [si], bx
  817.         push    word [di+2]
  818.         pop     word [bx+2]
  819.         jmp     .cache_append
  820. .cache_not_full:
  821. ; no, allocate new item
  822.         add     word [si+4], 8
  823. .cache_append:
  824.         mov     [di+4], eax
  825.         stc
  826.         jmp     @f
  827. .in_cache:
  828. ; delete this sector from the list
  829.         push    si
  830.         mov     si, [di]
  831.         mov     bx, [di+2]
  832.         mov     [si+2], bx
  833.         mov     [bx], si
  834.         pop     si
  835. @@:
  836. ; add new sector to the end of list
  837.         mov     bx, di
  838.         xchg    bx, [si+2]
  839.         push    word [bx]
  840.         pop     word [di]
  841.         mov     [bx], di
  842.         mov     [di+2], bx
  843.         pop     bx ds
  844.         ret
  845.  
  846. include 'fat.inc'
  847. include 'ntfs.inc'
  848.  
  849. total_kaput     db      13,10,'Fatal error: cannot load the secondary loader',0
  850. error_too_big   db      'file is too big',0
  851. nodata_string   db      '$DATA '
  852. error_not_found db      'not found',0
  853. noindex_string  db      '$INDEX_ROOT not found',0
  854. badname_msg     db      'bad name for FAT',0
  855. invalid_volume_msg db   'invalid volume',0
  856. mft_string      db      '$MFT',0
  857. fragmented_string db    'too fragmented file',0
  858. invalid_read_request_string db 'cannot read attribute',0
  859.  
  860. kernel_name     db      'kernel.mnt',0
  861.  
  862. align 4
  863. dat:
  864.  
  865. extended_part_start     dd      0       ; start sector for main extended partition
  866. extended_part_cur       dd      ?       ; start sector for current extended child
  867. extended_parent         dd      0       ; start sector for current extended parent
  868. partition_start         dd      0       ; start sector for current logical disk
  869. cur_partition_ofs       dw      ?       ; offset in MBR data for current partition
  870. sect_per_clust          dd      0
  871. ; change this variable if you want to boot from other physical drive
  872. boot_drive      db      80h
  873. in_callback     db      0
  874.  
  875. ; uninitialized data
  876. use_lba         db      ?
  877. cur_chunk_resident db   ?
  878. align 2
  879. heads           dw      ?
  880. sectors         dw      ?
  881. cache1head      rw      2
  882. cache1end       dw      ?
  883. cache1limit     dw      ?
  884. data_start      dd      ?
  885. cachelimit      dw      ?
  886. load_file_ptr   dw      ?
  887. cur_obj         dw      ?
  888. missing_slash   dw      ?
  889. root_clus       dd      ?
  890. root_start      dd      ?
  891. get_next_cluster_ptr    dw      ?
  892. frs_size        dw      ?
  893. freeattr        dw      ?
  894. index_root      dw      ?
  895. index_alloc     dw      ?
  896. cur_index_seg   dw      ?
  897. cur_index_cache dw      ?
  898. filesize        dd      ?
  899. filesize_sectors dd     ?
  900. cur_cluster     dd      ?
  901. cur_delta       dd      ?
  902. num_sectors     dd      ?
  903. sectors_read    dd      ?
  904. cur_chunk_ptr   dw      ?
  905.  
  906. rootcache_size  dw      ?       ; must be immediately before foldcache_clus
  907. if $-dat >= 0x80
  908. warning:
  909.          unoptimal data displacement!
  910. end if
  911. foldcache_clus  rd      7
  912. foldcache_mark  rw      7
  913. foldcache_size  rw      7
  914. fat_filename    rb      11
  915.  
  916. if $ > 2000h
  917. error:
  918.        file is too big
  919. end if
  920.  
  921. ; for NT/2k/XP, file must be 16 sectors = 0x2000 bytes long
  922. repeat 0x2600 - $
  923.         db      2       ; any data can be here; 2 is another nice face in ASCII :)
  924. end repeat
  925.