Subversion Repositories Kolibri OS

Rev

Rev 2288 | 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.         jmp     far 0:real_start
  28. ; special text
  29. org $+0x7C00
  30. real_start:
  31. ; initialize
  32.         xor     ax, ax
  33.         mov     ss, ax
  34.         mov     sp, 0x7C00
  35.         mov     ds, ax
  36.         mov     es, ax
  37.         cld
  38.         sti
  39.         mov     [bootdrive], dl
  40. ; check LBA support
  41.         mov     ah, 41h
  42.         mov     bx, 55AAh
  43.         int     13h
  44.         mov     si, aNoLBA
  45.         jc      err_
  46.         cmp     bx, 0AA55h
  47.         jnz     err_
  48.         test    cl, 1
  49.         jz      err_
  50. ; get file system information
  51. ; scan for Primary Volume Descriptor
  52.         db      66h
  53.         movi    eax, 10h-1
  54. pvd_scan_loop:
  55.         mov     cx, 1
  56.         inc     eax
  57.         mov     bx, 0x1000
  58.         call    read_sectors
  59.         jnc     @f
  60. fatal_read_err:
  61.         mov     si, aReadError
  62. err_:
  63.         call    out_string
  64.         mov     si, aPressAnyKey
  65.         call    out_string
  66.         xor     ax, ax
  67.         int     16h
  68.         int     18h
  69.         jmp     $
  70. @@:
  71.         push    ds
  72.         pop     es
  73.         cmp     word [bx+1], 'CD'
  74.         jnz     pvd_scan_loop
  75.         cmp     word [bx+3], '00'
  76.         jnz     pvd_scan_loop
  77.         cmp     byte [bx+5], '1'
  78.         jnz     pvd_scan_loop
  79. ; we have found ISO9660 descriptor, look for type
  80.         cmp     byte [bx], 1    ; Primary Volume Descriptor?
  81.         jz      pvd_found
  82.         cmp     byte [bx], 0xFF ; Volume Descriptor Set Terminator?
  83.         jnz     pvd_scan_loop
  84. ; Volume Descriptor Set Terminator reached, no PVD found - fatal error
  85.         mov     si, no_pvd
  86.         jmp     err_
  87. pvd_found:
  88.         add     bx, 80h
  89.         mov     ax, [bx]
  90.         mov     [lb_size], ax
  91. ; calculate number of logical blocks in one sector
  92.         mov     ax, 800h
  93.         cwd
  94.         div     word [bx]
  95.         mov     [lb_per_sec], ax
  96. ; get location of root directory
  97.         mov     di, root_location
  98.         movzx   eax, byte [bx+1Dh]
  99.         add     eax, [bx+1Eh]
  100.         stosd
  101. ; get memory size
  102.         int     12h
  103.         mov     si, nomem_str
  104.         cmp     ax, 71000h / 400h
  105.         jb      err_
  106.         shr     ax, 1
  107.         sub     ax, 60000h / 800h
  108.         mov     [size_rest], ax
  109.         mov     [free_ptr], 60000h / 800h
  110. ; load path table
  111. ; if size > 62K => it's very strange, avoid using it
  112. ; if size > (size of cache)/2 => avoid using it too
  113.         mov     ecx, [bx+4]
  114.         cmp     ecx, 0x10000 - 0x800
  115.         ja      nopathtable
  116.         shr     ax, 1
  117.         cmp     ax, 0x20
  118.         jae     @f
  119.         shl     ax, 11
  120.         cmp     cx, ax
  121.         ja      nopathtable
  122. @@:
  123. ; size is ok, try to load it
  124.         mov     [pathtable_size], cx
  125.         mov     eax, [bx+12]
  126.         xor     edx, edx
  127.         div     dword [lb_per_sec]
  128.         imul    dx, [bx]
  129.         mov     [pathtable_start], dx
  130.         add     cx, dx
  131.         call    cx_to_sectors
  132.         xor     bx, bx
  133.         push    6000h
  134.         pop     es
  135.         call    read_sectors
  136.         jc      nopathtable
  137. ; path table has been loaded
  138.         inc     [use_path_table]
  139.         sub     [size_rest], cx
  140.         add     [free_ptr], cx
  141. nopathtable:
  142. ; init cache
  143.         mov     ax, [size_rest]
  144.         mov     [cache_size], ax
  145.         mov     ax, [free_ptr]
  146.         mov     [cache_start], ax
  147. ; load secondary loader
  148.         mov     di, secondary_loader_info
  149.         call    load_file
  150.         test    bx, bx
  151.         jnz     noloader
  152. ; set registers for secondary loader
  153.         mov     ah, [bootdrive]
  154.         mov     al, 'c'
  155.         mov     bx, 'is'
  156.         mov     si, callback
  157.         jmp     far [si-callback+secondary_loader_info] ; jump to 1000:0000
  158.  
  159. noloader:
  160.         mov     si, aKernelNotFound
  161.         jmp     err_
  162.  
  163. read_sectors:
  164. ; es:bx = pointer to data
  165. ; eax = first sector
  166. ; cx = number of sectors
  167.         pushad
  168.         push    ds
  169. do_read_sectors:
  170.         push    ax
  171.         push    cx
  172.         cmp     cx, 0x7F
  173.         jbe     @f
  174.         mov     cx, 0x7F
  175. @@:
  176. ; create disk address packet on the stack
  177. ; dq starting LBA
  178.         db      66h
  179.         push    0
  180.         push    eax
  181. ; dd buffer
  182.         push    es
  183.         push    bx
  184. ; dw number of blocks to transfer (no more than 0x7F)
  185.         push    cx
  186. ; dw packet size in bytes
  187.         push    10h
  188. ; issue BIOS call
  189.         push    ss
  190.         pop     ds
  191.         mov     si, sp
  192.         mov     dl, [cs:bootdrive]
  193.         mov     ah, 42h
  194.         int     13h
  195.         jc      diskreaderr
  196. ; restore stack
  197.         add     sp, 10h
  198. ; increase current sector & buffer; decrease number of sectors
  199.         movzx   esi, cx
  200.         mov     ax, es
  201.         shl     cx, 7
  202.         add     ax, cx
  203.         mov     es, ax
  204.         pop     cx
  205.         pop     ax
  206.         add     eax, esi
  207.         sub     cx, si
  208.         jnz     do_read_sectors
  209.         pop     ds
  210.         popad
  211.         ret
  212. diskreaderr:
  213.         add     sp, 10h + 2*2
  214.         pop     ds
  215.         popad
  216.         stc
  217. out_string.ret:
  218.         ret
  219.  
  220. out_string:
  221. ; in: ds:si -> ASCIIZ string
  222.         lodsb
  223.         test    al, al
  224.         jz      .ret
  225.         mov     ah, 0Eh
  226.         mov     bx, 7
  227.         int     10h
  228.         jmp     out_string
  229.  
  230. aNoLBA          db      'The drive does not support LBA!',0
  231. aReadError      db      'Read error',0
  232. no_pvd          db      'Primary Volume Descriptor not found!',0
  233. nomem_str       db      'No memory',0
  234. aPressAnyKey    db      13,10,'Press any key...',13,10,0
  235.  
  236. load_file:
  237. ; in: ds:di -> information structure
  238. ;       dw:dw   address
  239. ;       dw      limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
  240. ;       ASCIIZ  name
  241. ; out: bx = status: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found
  242. ; out: dx:ax = file size (0xFFFFFFFF if file not found)
  243. ; parse path to the file
  244.         lea     si, [di+6]
  245.         mov     eax, [cs:root_location]
  246.         cmp     [cs:use_path_table], 0
  247.         jz      parse_dir
  248. ; scan for path in path table
  249.         push    di
  250.         push    6000h
  251.         pop     es
  252.         mov     di, [cs:pathtable_start]        ; es:di = pointer to current entry in path table
  253.         mov     dx, 1   ; dx = number of current entry in path table, start from 1
  254.         mov     cx, [cs:pathtable_size]
  255. pathtable_newparent:
  256.         mov     bx, dx  ; bx = number of current parent in path table: root = 1
  257. scan_path_table_e:
  258.         call    is_last_component
  259.         jnc     path_table_scanned
  260. scan_path_table_i:
  261.         cmp     word [es:di+6], bx
  262.         jb      .next
  263.         ja      path_table_notfound
  264.         call    test_filename1
  265.         jc      .next
  266. @@:
  267.         lodsb
  268.         cmp     al, '/'
  269.         jnz     @b
  270.         jmp     pathtable_newparent
  271. .next:
  272. ; go to next entry
  273.         inc     dx
  274.         movzx   ax, byte [es:di]
  275.         add     ax, 8+1
  276.         and     al, not 1
  277.         add     di, ax
  278.         sub     cx, ax
  279.         ja      scan_path_table_i
  280. path_table_notfound:
  281.         pop     di
  282.         mov     ax, -1
  283.         mov     dx, ax
  284.         mov     bx, 2   ; file not found
  285.         ret
  286. path_table_scanned:
  287.         movzx   eax, byte [es:di+1]
  288.         add     eax, [es:di+2]
  289.         pop     di
  290. parse_dir:
  291. ; eax = logical block, ds:di -> information structure, ds:si -> file name
  292. ; was the folder already read?
  293.         push    di ds
  294.         push    cs
  295.         pop     ds
  296.         mov     [cur_desc_end], 2000h
  297.         mov     bx, cachelist
  298. .scan1:
  299.         mov     bx, [bx+2]
  300.         cmp     bx, cachelist
  301.         jz      .notfound
  302.         cmp     [bx+4], eax
  303.         jnz     .scan1
  304. .found:
  305. ; yes; delete this item from the list (the following code will append this item to the tail)
  306.         mov     di, [bx]
  307.         push    word [bx+2]
  308.         pop     word [di+2]
  309.         mov     di, [bx+2]
  310.         push    word [bx]
  311.         pop     word [di]
  312.         mov     di, bx
  313.         jmp     .scan
  314. .notfound:
  315. ; no; load first sector of the folder to get its size
  316.         push    eax
  317.         push    si
  318.         mov     si, 1
  319.         call    load_phys_sector_for_lb_force
  320.         mov     bx, si
  321.         pop     si
  322.         pop     eax
  323.         jnc     @f
  324. ; read error - return
  325. .readerr:
  326.         pop     ds
  327. .readerr2:
  328.         pop     di
  329.         mov     ax, -1
  330.         mov     dx, ax
  331.         mov     bx, 3
  332.         ret
  333. @@:
  334. ; first item of the folder describes the folder itself
  335. ; do not cache too big folders: size < 64K and size <= (total cache size)/2
  336.         cmp     word [bx+12], 0
  337.         jnz     .nocache
  338.         mov     cx, [cache_size]        ; cx = cache size in sectors
  339.         shr     cx, 1                   ; cx = (cache size)/2
  340.         cmp     cx, 0x20
  341.         jae     @f
  342.         shl     cx, 11
  343.         cmp     [bx+10], cx
  344.         ja      .nocache
  345. @@:
  346. ; we want to cache this folder; get space for it
  347.         mov     cx, [bx+10]
  348.         call    cx_to_sectors
  349.         jnz     .yescache
  350. .nocache:
  351.         push    dword [bx+10]
  352.         pop     dword [cur_nocache_len]
  353.         call    lb_to_sector
  354.         push    ds
  355.         pop     es
  356.         pop     ds
  357. .nocache_loop:
  358.         push    eax
  359.         mov     dx, 1800h
  360.         call    scan_for_filename_in_sector
  361.         mov     cx, dx
  362.         pop     eax
  363.         jnc     .j_scandone
  364.         sub     cx, bx
  365.         sub     word [es:cur_nocache_len], cx
  366.         sbb     word [es:cur_nocache_len+2], 0
  367.         jb      .j_scandone
  368.         ja      @f
  369.         cmp     word [es:cur_nocache_len], 0
  370.         jz      .j_scandone
  371. @@:
  372.         mov     cx, 1
  373.         inc     eax
  374.         push    es
  375.         mov     bx, 1000h
  376.         call    read_sectors
  377.         pop     es
  378.         jc      .readerr2
  379.         jmp     .nocache_loop
  380. .j_scandone:
  381.         jmp     .scandone
  382. .yescache:
  383.         push    bx
  384.         mov     bx, [cachelist.head]
  385. .freeloop:
  386.         cmp     cx, [size_rest]
  387.         jbe     .sizeok
  388. @@:
  389. ; if we are here: there is not enough free space, so we must delete old folders' data
  390. ; N.B. We know that after deleting some folders the space will be available (size <= (total cache size)/2).
  391. ; one loop iteration: delete data of one folder
  392.         pusha
  393.         mov     dx, [bx+10]
  394.         mov     es, dx          ; es = segment of folder data to be deleted
  395.         xor     di, di
  396.         mov     ax, [bx+8]
  397.         add     ax, 0x7FF
  398.         rcr     ax, 1
  399.         shr     ax, 10
  400.         push    ax
  401.         shl     ax, 11-4        ; get number of paragraphs in folder data to be deleted
  402.         mov     cx, [cache_size]
  403.         add     cx, [cache_start]
  404.         push    ds
  405.         push    ax
  406.         add     ax, dx
  407.         mov     ds, ax
  408.         pop     ax
  409.         shl     cx, 11-4
  410.         sub     cx, dx          ; cx = number of paragraphs to be moved
  411.         push    si
  412.         xor     si, si
  413. ; move cx paragraphs from ds:si to es:di to get free space in the end of cache
  414. @@:
  415.         sub     cx, 1000h
  416.         jbe     @f
  417.         push    cx
  418.         mov     cx, 8000h
  419.         rep movsw
  420.         mov     cx, ds
  421.         add     cx, 1000h
  422.         mov     ds, cx
  423.         mov     cx, es
  424.         add     cx, 1000h
  425.         mov     es, cx
  426.         pop     cx
  427.         jmp     @b
  428. @@:
  429.         add     cx, 1000h
  430.         shl     cx, 3
  431.         rep movsw
  432.         pop     si
  433.         pop     ds
  434. ; correct positions in cache for existing items
  435.         mov     cx, 80h
  436.         mov     di, 8400h
  437. .correct:
  438.         cmp     [di+10], dx
  439.         jbe     @f
  440.         sub     [di+10], ax
  441. @@:
  442.         add     di, 12
  443.         loop    .correct
  444. ; some additional space is free now
  445.         pop     ax
  446.         add     [size_rest], ax
  447.         sub     [free_ptr], ax
  448. ; add cache item to the list of free items
  449.         mov     dx, [bx]
  450.         mov     ax, [free_cache_item]
  451.         mov     [bx], ax
  452.         mov     [free_cache_item], bx
  453.         mov     bx, dx
  454. ; current iteration done
  455.         popa
  456.         jmp     .freeloop
  457. .sizeok:
  458.         mov     [cachelist.head], bx
  459.         mov     word [bx+2], cachelist
  460. ; allocate new item in cache
  461.         mov     di, [free_cache_item]
  462.         test    di, di
  463.         jz      .nofree
  464.         push    word [di]
  465.         pop     [free_cache_item]
  466.         jmp     @f
  467. .nofree:
  468.         mov     di, [last_cache_item]
  469.         add     [last_cache_item], 12
  470. @@:
  471.         pop     bx
  472.         push    si di
  473. ;       mov     [di+4], eax     ; start of folder
  474.         scasd
  475.         stosd
  476.         push    ax
  477.         mov     ax, [free_ptr]
  478.         shl     ax, 11-4
  479.         mov     [di+10-8], ax
  480.         mov     es, ax
  481.         pop     ax
  482.         add     [free_ptr], cx
  483.         sub     [size_rest], cx
  484. ; read folder data
  485. ; first sector is already in memory, 0000:bx
  486.         pusha
  487.         mov     cx, [bx+10]
  488.         mov     [di+8-8], cx    ; folder size in bytes
  489.         mov     si, bx
  490.         xor     di, di
  491.         mov     cx, 0x1800
  492.         sub     cx, si
  493.         rep movsb
  494.         pop     ax
  495.         push    di
  496.         popa
  497. ; read rest of folder
  498.         mov     esi, dword [lb_per_sec]
  499.         add     eax, esi
  500.         dec     si
  501.         not     si
  502.         and     ax, si
  503.         mov     si, word [bx+10]
  504.         mov     bx, di
  505.         pop     di
  506.         sub     si, bx
  507.         jbe     @f
  508.         mov     [cur_limit], esi
  509.         call    read_many_bytes
  510.         pop     si
  511.         jnc     .scan
  512.         jmp     .readerr
  513. @@:
  514.         pop     si
  515. .scan:
  516. ; now we have required cache item; append it to the end of list
  517.         mov     bx, [cachelist.tail]
  518.         mov     [cachelist.tail], di
  519.         mov     [di+2], bx
  520.         mov     word [di], cachelist
  521.         mov     [bx], di
  522. ; scan for given filename
  523.         mov     es, [di+10]
  524.         mov     dx, [di+8]
  525.         pop     ds
  526.         xor     bx, bx
  527.         call    scan_for_filename_in_sector
  528. .scandone:
  529.         push    cs
  530.         pop     es
  531.         mov     bx, 2000h
  532.         cmp     bx, [es:cur_desc_end]
  533.         jnz     filefound
  534. j_notfound:
  535.         jmp     path_table_notfound
  536. filefound:
  537. @@:
  538.         lodsb
  539.         test    al, al
  540.         jz      @f
  541.         cmp     al, '/'
  542.         jnz     @b
  543. @@:
  544.         mov     cl, [es:bx+8]
  545.         test    al, al
  546.         jz      @f
  547. ; parse next component of file name
  548.         test    cl, 2   ; directory?
  549.         jz      j_notfound
  550.         mov     eax, [es:bx]
  551.         pop     di
  552.         jmp     parse_dir
  553. @@:
  554.         test    cl, 2   ; directory?
  555.         jnz     j_notfound      ; do not allow read directories as regular files
  556. ; ok, now load the file
  557.         pop     di
  558.         les     bx, [di]
  559.         call    normalize
  560.         movzx   esi, word [di+4]        ; esi = limit in 4K blocks
  561.         shl     esi, 12         ; esi = limit in bytes
  562.         push    cs
  563.         pop     ds
  564.         mov     [cur_limit], esi
  565.         mov     di, 2000h
  566. loadloop:
  567.         and     [cur_start], 0
  568. .loadnew:
  569.         mov     esi, [cur_limit]
  570.         mov     eax, [cur_start]
  571.         add     esi, eax
  572.         mov     [overflow], 1
  573.         sub     esi, [di+4]
  574.         jb      @f
  575.         xor     esi, esi
  576.         dec     [overflow]
  577. @@:
  578.         add     esi, [di+4]     ; esi = number of bytes to read
  579.         mov     [cur_start], esi
  580.         sub     esi, eax
  581.         jz      .loadcontinue
  582.         xor     edx, edx
  583.         div     dword [lb_size] ; eax = number of logical blocks to skip,
  584.         mov     [first_byte], dx; [first_byte] = number of bytes to skip in 1st block
  585.         cmp     byte [di+10], 0
  586.         jnz     .interleaved
  587.         add     eax, [di]
  588. ; read esi bytes from logical block eax to buffer es:bx
  589.         call    read_many_bytes.with_first
  590.         jc      .readerr3
  591. .loadcontinue:
  592.         mov     [cur_chunk], di
  593.         add     di, 11
  594.         cmp     di, [cur_desc_end]
  595.         jae     @f
  596.         cmp     [cur_limit], 0
  597.         jnz     loadloop
  598. @@:
  599.         mov     bx, [overflow]
  600. .calclen:
  601. ; calculate length of file
  602.         xor     ax, ax
  603.         xor     dx, dx
  604.         mov     di, 2000h
  605. @@:
  606.         add     ax, [di+4]
  607.         adc     dx, [di+6]
  608.         add     di, 11
  609.         cmp     di, [cur_desc_end]
  610.         jb      @b
  611.         ret
  612. .interleaved:
  613.         mov     [cur_unit_limit], esi
  614.         push    esi
  615. ; skip first blocks
  616.         movzx   ecx, byte [di+9]        ; Unit Size
  617.         movzx   esi, byte [di+10]       ; Interleave Gap
  618.         add     si, cx
  619.         mov     edx, [di]
  620. @@:
  621.         sub     eax, ecx
  622.         jb      @f
  623.         add     edx, esi
  624.         jmp     @b
  625. @@:
  626.         add     ecx, eax        ; ecx = number of logical blocks to skip
  627.         lea     eax, [ecx+edx]  ; eax = first logical block
  628.         pop     esi
  629. .interleaved_loop:
  630. ; get number of bytes in current file unit
  631.         push    eax
  632.         movzx   eax, byte [di+9]
  633.         sub     ax, cx
  634.         imul    eax, dword [lb_size]
  635.         cmp     eax, esi
  636.         ja      .i2
  637. .i1:
  638.         xchg    esi, eax
  639. .i2:
  640.         pop     eax
  641.         sub     [cur_unit_limit], esi
  642.         push    eax
  643. ; read esi bytes from logical block eax to buffer es:bx
  644.         call    read_many_bytes.with_first
  645.         pop     eax
  646.         jnc     @f
  647. .readerr3:
  648.         mov     bx, 3
  649.         jmp     .calclen
  650. @@:
  651.         mov     esi, [cur_unit_limit]
  652.         test    esi, esi
  653.         jz      .loadcontinue
  654.         movzx   ecx, byte [di+9]        ; add Unit Size
  655.         add     cl, byte [di+10]        ; add Interleave Gap
  656.         adc     ch, 0
  657.         add     eax, ecx
  658.         xor     cx, cx
  659.         mov     [first_byte], cx
  660.         jmp     .interleaved_loop
  661.  
  662. cx_to_sectors:
  663.         add     cx, 7FFh
  664.         rcr     cx, 1
  665.         shr     cx, 10
  666.         ret
  667.  
  668. is_last_component:
  669. ; in: ds:si -> name
  670. ; out: CF set <=> current component is not last (=> folder)
  671.         push    si
  672. @@:
  673.         lodsb
  674.         test    al, al
  675.         jz      @f
  676.         cmp     al, '/'
  677.         jnz     @b
  678.         stc
  679. @@:
  680.         pop     si
  681.         ret
  682.  
  683. test_filename1:
  684. ; in: ds:si -> filename, es:di -> path table item
  685. ; out: CF set <=> no match
  686.         pusha
  687.         mov     cl, [es:di]
  688.         add     di, 8
  689.         jmp     test_filename2.start
  690. test_filename2:
  691. ; in: ds:si -> filename, es:bx -> directory item
  692. ; out: CF set <=> no match
  693.         pusha
  694.         mov     cl, [es:bx+32]
  695.         lea     di, [bx+33]
  696. .start:
  697.         mov     ch, 0
  698. @@:
  699.         lodsb
  700.         test    al, al
  701.         jz      .test1
  702.         cmp     al, '/'
  703.         jz      .test1
  704.         call    toupper
  705.         mov     ah, al
  706.         mov     al, [es:di]
  707.         call    toupper
  708.         inc     di
  709.         cmp     al, ah
  710.         loopz   @b
  711.         jnz     .next1
  712. ; if we have reached this point: current name is done
  713.         lodsb
  714.         test    al, al
  715.         jz      .ret
  716.         cmp     al, '/'
  717.         jz      .ret
  718. ; if we have reached this point: current name is done, but input name continues
  719. ; so they do not match
  720.         jmp     .next1
  721. .test1:
  722. ; if we have reached this point: input name is done, but current name continues
  723. ; "filename.ext;version" in ISO-9660 represents file "filename.ext"
  724. ; "filename." and "filename.;version" are also possible for "filename"
  725.         cmp     byte [es:di], '.'
  726.         jnz     @f
  727.         inc     di
  728.         dec     cx
  729.         jz      .ret
  730. @@:
  731.         cmp     byte [es:di], ';'
  732.         jnz     .next1
  733.         jmp     .ret
  734. .next1:
  735.         stc
  736. .ret:
  737.         popa
  738.         ret
  739.  
  740. toupper:
  741. ; in: al=symbol
  742. ; out: al=symbol in uppercase
  743.         cmp     al, 'a'
  744.         jb      .ret
  745.         cmp     al, 'z'
  746.         ja      .ret
  747.         sub     al, 'a'-'A'
  748. .ret:
  749.         ret
  750.  
  751. scan_for_filename_in_sector:
  752. ; in: ds:si->filename, es:bx->folder data, dx=limit
  753. ; out: CF=0 if found
  754.         push    bx
  755. .loope:
  756.         push    bx
  757. .loop:
  758.         cmp     bx, dx
  759.         jae     .notfound
  760.         cmp     byte [es:bx], 0
  761.         jz      .loopd
  762.         test    byte [es:bx+25], 4      ; ignore files with Associated bit
  763.         jnz     .next
  764.         call    test_filename2
  765.         jc      .next
  766.         push    ds es di
  767.         push    es
  768.         pop     ds
  769.         push    cs
  770.         pop     es
  771.         mov     di, [es:cur_desc_end]
  772.         movzx   eax, byte [bx+1]
  773.         add     eax, [bx+2]
  774.         stosd   ; first logical block
  775.         mov     eax, [bx+10]
  776.         stosd   ; length
  777.         mov     al, [bx+25]
  778.         stosb   ; flags
  779.         mov     ax, [bx+26]
  780.         stosw   ; File Unit size, Interleave Gap size
  781.         mov     [es:cur_desc_end], di
  782.         cmp     di, 3000h
  783.         pop     di es ds
  784.         jae     .done
  785.         test    byte [es:bx+25], 80h
  786.         jz      .done
  787. .next:
  788.         add     bl, [es:bx]
  789.         adc     bh, 0
  790.         jmp     .loop
  791. .loopd:
  792.         mov     ax, bx
  793.         pop     bx
  794. @@:
  795.         add     bx, [cs:lb_size]
  796.         jz      .done2
  797.         cmp     bx, ax
  798.         jb      @b
  799.         jmp     .loope
  800. .notfound:
  801.         stc
  802. .done:
  803.         pop     bx
  804. .done2:
  805.         pop     bx
  806.         ret
  807.  
  808. lb_to_sector:
  809.         xor     edx, edx
  810.         div     dword [lb_per_sec]
  811.         ret
  812.  
  813. load_phys_sector_for_lb_force:
  814. ; in: eax = logical block, ds=0
  815. ; in: si=0 - accept 0 logical blocks, otherwise force read at least 1
  816. ; out: 0000:1000 = physical sector data; si -> logical block
  817. ; out: eax = next physical sector
  818. ; out: CF=1 if read error
  819. ; destroys cx
  820. ; this procedure reads 0-3 or 1-4 logical blocks, up to the end of physical sector
  821.         call    lb_to_sector
  822.         or      si, dx
  823.         jnz     @f
  824.         mov     si, 1800h
  825.         jmp     .done
  826. @@:
  827.         mov     si, 1000h
  828.         imul    dx, [lb_size]
  829.         add     si, dx
  830.         mov     cx, 1
  831.         push    es bx
  832.         push    ds
  833.         pop     es
  834.         mov     bx, 1000h
  835.         call    read_sectors
  836.         pop     bx es
  837.         inc     eax
  838. .done:
  839.         ret
  840.  
  841. normalize:
  842. ; in: es:bx = far pointer
  843. ; out: es:bx = normalized pointer (i.e. 0 <= bx < 0x10)
  844.         push    ax bx
  845.         mov     ax, es
  846.         shr     bx, 4
  847.         add     ax, bx
  848.         mov     es, ax
  849.         pop     bx ax
  850.         and     bx, 0x0F
  851.         ret
  852.  
  853. read_many_bytes:
  854.         and     [first_byte], 0
  855. read_many_bytes.with_first:
  856. ; read esi bytes from logical block dx:ax to buffer es:bx
  857. ; out: CF=1 <=> disk error
  858.         push    di
  859. ; load first physical sector
  860.         push    bx si
  861.         mov     si, [first_byte]
  862.         call    load_phys_sector_for_lb_force
  863.         jnc     @f
  864.         pop     si bx
  865. .ret:
  866.         pop     di
  867.         ret
  868. @@:
  869.         add     si, [first_byte]
  870.         mov     ecx, 1800h
  871.         sub     cx, si
  872.         mov     ebx, esi
  873.         pop     bx
  874.         sub     ebx, ecx
  875.         jnc     @f
  876.         add     cx, bx
  877.         xor     ebx, ebx
  878. @@:
  879.         pop     di
  880.         sub     [cur_limit], ecx
  881.         rep movsb
  882.         mov     esi, ebx
  883.         mov     bx, di
  884.         call    normalize
  885. ; load other physical sectors
  886. ; read esi bytes from physical sector eax to buffer es:bx
  887.         test    esi, esi
  888.         jz      .ret
  889.         push    esi
  890.         add     esi, 0x7FF
  891.         and     si, not 0x7FF
  892.         cmp     esi, [cur_limit]
  893.         jbe     .okplace
  894. .noplace:
  895.         sub     esi, 800h
  896. .okplace:
  897.         shr     esi, 11 ; si = number of sectors
  898.         mov     cx, si
  899.         jz      @f
  900.         call    read_sectors
  901. @@:
  902.         pop     esi
  903.         jc      .ret
  904.         movzx   ecx, cx
  905.         add     eax, ecx
  906.         shl     ecx, 11
  907.         sub     [cur_limit], ecx
  908.         sub     esi, ecx
  909.         jc      .big
  910.         jz      .nopost
  911.         push    bx es
  912.         push    ds
  913.         pop     es
  914.         mov     bx, 1000h
  915.         mov     cx, 1
  916.         call    read_sectors
  917.         pop     es di
  918.         jc      .ret2
  919.         mov     cx, si
  920.         mov     si, 1000h
  921.         sub     word [cur_limit], cx
  922.         sbb     word [cur_limit+2], 0
  923.         rep movsb
  924.         mov     bx, di
  925.         call    normalize
  926. .nopost:
  927.         clc
  928. .ret2:
  929.         pop     di
  930.         ret
  931. .big:
  932.         mov     ax, es
  933.         sub     ax, 80h
  934.         mov     es, ax
  935.         add     bx, 800h
  936.         add     bx, si
  937.         call    normalize
  938.         sub     [cur_limit], esi
  939.         jmp     .nopost
  940.  
  941. ; Callback function for secondary loader
  942. callback:
  943. ; in: ax = function number; only function 1 is defined for now
  944.         dec     ax
  945.         jz      callback_readfile
  946.         dec     ax
  947.         jz      callback_continueread
  948.         stc     ; unsupported function
  949.         retf
  950.  
  951. callback_readfile:
  952. ; function 1: read file
  953. ; in: ds:di -> information structure
  954. ;       dw:dw   address
  955. ;       dw      limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
  956. ;       ASCIIZ  name
  957. ; 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
  958. ; out: dx:ax = file size (0xFFFFFFFF if file was not found)
  959.         call    load_file
  960.         clc     ; function is supported
  961.         retf
  962.  
  963. callback_continueread:
  964. ; function 2: continue to read file
  965. ; in: ds:di -> information structure
  966. ;       dw:dw   address
  967. ;       dw      limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
  968. ; out: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=3 - read error
  969. ; out: dx:ax = file size
  970.         les     bx, [di]
  971.         call    normalize
  972.         movzx   esi, word [di+4]        ; si = limit in 4K blocks
  973.         shl     esi, 12                 ; bp:si = limit in bytes
  974.         push    cs
  975.         pop     ds
  976.         mov     [cur_limit], esi
  977.         mov     di, [cur_chunk]
  978.         call    loadloop.loadnew
  979.         clc     ; function is supported
  980.         retf
  981.  
  982. secondary_loader_info:
  983.         dw      0, 0x1000
  984.         dw      0x30000 / 0x1000
  985.         db      'kernel.mnt',0
  986. aKernelNotFound db      'Fatal error: cannot load the kernel',0
  987.  
  988. align 2
  989. cachelist:
  990. .head           dw      cachelist
  991. .tail           dw      cachelist
  992. free_cache_item dw      0
  993. last_cache_item dw      0x8400
  994.  
  995. use_path_table  db      0
  996. bootdrive       db      ?
  997. align 2
  998. lb_size         dw      ?       ; Logical Block size in bytes
  999.                 dw      0       ; to allow access dword [lb_size]
  1000. lb_per_sec      dw      ?       ; Logical Blocks per physical sector
  1001.                 dw      0       ; to allow access dword [lb_per_sec]
  1002. free_ptr        dw      ?       ; first free block in cache (cache block = sector = 0x800 bytes)
  1003. size_rest       dw      ?       ; free space in cache (in blocks)
  1004. cache_size      dw      ?
  1005. cache_start     dw      ?
  1006. pathtable_size  dw      ?
  1007. pathtable_start dw      ?
  1008. root_location   dd      ?
  1009. cur_desc_end    dw      ?
  1010. cur_nocache_len dd      ?
  1011. cur_limit       dd      ?
  1012. cur_unit_limit  dd      ?
  1013. overflow        dw      ?
  1014. cur_chunk       dw      ?
  1015. first_byte      dw      ?
  1016. cur_start       dd      ?
  1017.  
  1018. times 83FCh-$  db      0
  1019.         db      43h
  1020. ; just to make file 2048 bytes long :)
  1021.         db      'd' xor 'i' xor 'a' xor 'm' xor 'o' xor 'n' xor 'd'
  1022.  
  1023.         dw      0xAA55          ; this is not required for CD, but to be consistent...
  1024.