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