Subversion Repositories Kolibri OS

Rev

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