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.         org     0x7E00
  28. ; the KordOS FAT12/FAT16 bootsector loads first cluster of this file to 0:7E00 and transfers control to here
  29. ; ss:bp = 0:7C00
  30. virtual at bp
  31.                 rb      3               ; BS_jmpBoot
  32.                 rb      8               ; BS_OEMName, ignored
  33.                 dw      ?               ; BPB_BytsPerSec
  34. BPB_SecsPerClus db      ?
  35. BPB_RsvdSecCnt  dw      ?
  36. BPB_NumFATs     db      ?
  37. BPB_RootEntCnt  dw      ?
  38. BPB_TotSec16    dw      ?
  39.                 db      ?               ; BPB_Media
  40. BPB_FATSz16     dw      ?
  41. BPB_SecPerTrk   dw      ?
  42. BPB_NumHeads    dw      ?
  43. BPB_HiddSec     dd      ?
  44. BPB_TotSec32    dd      ?
  45. BS_DrvNum       db      ?
  46. fat_type        db      ?               ; this is BS_Reserved1,
  47.                                 ; we use it to save FS type: 0=FAT12, 1=FAT16
  48.                 db      ?               ; BS_BootSig
  49. num_sectors     dd      ?               ; BS_VolID
  50. ;               rb      11              ; BS_VolLab
  51. ;               rb      3               ; BS_FilSysType, first 3 bytes
  52. read_sectors    dw      ?
  53. read_sectors2   dw      ?
  54. lookup_in_root_dir dw   ?
  55. scan_for_filename dw    ?
  56. err_             dw      ?
  57. noloader        dw      ?
  58. cachelimit      dw      ?
  59. filesize:       ; will be used to save file size
  60.                 rb      5               ; BS_FilSysType, last 5 bytes
  61. ; following variables are located in the place of starting code;
  62. ; starting code is no more used at this point
  63. sect_per_clus   dw      ?
  64. cur_cluster     dw      ?
  65. next_cluster    dw      ?
  66. flags           dw      ?
  67. cur_delta       dd      ?
  68. end virtual
  69.  
  70. ; procedures from boot sector
  71. ; LBA version
  72. lba_read_sectors = 7CE2h
  73. lba_read_sectors2 = 7CDCh
  74. lba_lookup_in_root_dir = 7D4Fh
  75. lba_scan_for_filename = 7D2Dh
  76. lba_err = 7CB5h
  77. lba_noloader = 7CB2h
  78. ; CHS version
  79. chs_read_sectors = 7CDEh
  80. chs_read_sectors2 = 7CD8h
  81. chs_lookup_in_root_dir = 7D70h
  82. chs_scan_for_filename = 7D4Eh
  83. chs_err = 7CB1h
  84. chs_noloader = 7CAEh
  85.  
  86.         push    ax cx           ; save our position on disk
  87.         push    ss
  88.         pop     es
  89. ; determine version of bootsector (LBA vs CHS)
  90. ;       mov     [read_sectors], chs_read_sectors
  91. ;       mov     [read_sectors2], chs_read_sectors2
  92. ;       mov     [lookup_in_root_dir], chs_lookup_in_root_dir
  93. ;       mov     [scan_for_filename], chs_scan_for_filename
  94. ;       mov     [err], chs_err
  95. ;       mov     [noloader], chs_noloader
  96.         lea     di, [read_sectors]
  97.         mov     si, chs_proc_addresses
  98.         mov     cx, 6*2
  99.         cmp     word [chs_scan_for_filename], 0xFF31    ; 'xor di,di'
  100.         jz      @f
  101.         add     si, cx
  102. ;       mov     [read_sectors], lba_read_sectors
  103. ;       mov     [read_sectors2], lba_read_sectors2
  104. ;       mov     [lookup_in_root_dir], lba_lookup_in_root_dir
  105. ;       mov     [scan_for_filename], lba_scan_for_filename
  106. ;       mov     [err], lba_err
  107. ;       mov     [noloader], lba_noloader
  108. @@:
  109.         rep movsb
  110.         mov     cl, [BPB_SecsPerClus]
  111.         mov     [sect_per_clus], cx
  112.         xor     bx, bx
  113. ; determine size of cache for folders
  114.         int     12h             ; ax = size of available base memory in Kb
  115.         sub     ax, 94000h / 1024
  116.         jae     @f
  117. nomem:
  118.         mov     si, nomem_str
  119.         jmp     [err_]
  120. @@:
  121.         shr     ax, 3
  122.         mov     [cachelimit], ax        ; size of cache - 1
  123. ; get type of file system - FAT12 or FAT16?
  124. ; calculate number of clusters
  125.         mov     ax, [BPB_TotSec16]
  126.         xor     dx, dx
  127.         test    ax, ax
  128.         jnz     @f
  129.         mov     ax, word [BPB_TotSec32]
  130.         mov     dx, word [BPB_TotSec32+2]
  131. @@:
  132.         sub     ax, [bp-8]      ; dword [bp-8] = first data sector
  133.         sbb     dx, [bp-6]
  134.         jb      j_noloader
  135.         div     [sect_per_clus]
  136. ; ax = number of clusters
  137. ; note: this is loader for FAT12/FAT16, so 'div' does not overflow on correct volumes
  138.         mov     [fat_type], ch
  139.         cmp     ax, 0xFF5
  140.         jb      init_fat12
  141.         inc     [fat_type]
  142. init_fat16:
  143. ; no sectors loaded
  144.         mov     di, 0x8200
  145.         xor     ax, ax
  146.         mov     cx, 0x100/2
  147.         rep stosw
  148.         jmp     init_fat_done
  149. init_fat12:
  150. ; read FAT
  151.         push    0x6000
  152.         pop     es
  153.         mov     ax, [BPB_RsvdSecCnt]
  154.         mov     cx, [BPB_FATSz16]
  155.         cmp     cx, 12
  156.         jb      @f
  157.         mov     cx, 12
  158. @@:
  159.         xor     dx, dx
  160.         call    [read_sectors]
  161. init_fat_done:
  162. ; if cluster = sector, we need to read second part of our file
  163. ; (bootsector loads only first cluster of kordldr.f1x)
  164.         pop     cx ax           ; restore our position on disk
  165.         cmp     cx, 1
  166.         ja      kordldr_full
  167.         sub     ax, [bp-8]
  168.         inc     ax
  169.         inc     ax              ; ax = first cluster of kordldr.f12
  170.         call    get_next_cluster
  171.         jc      @f
  172. j_noloader:
  173.         jmp     [noloader]
  174. @@:
  175.         dec     ax
  176.         dec     ax
  177.         push    0x800
  178.         pop     es
  179.         call    [read_sectors2]
  180. kordldr_full:
  181. ; ...continue loading...
  182.         mov     di, secondary_loader_info
  183.         call    load_file
  184.         test    bx, bx
  185.         mov     bx, [err_]
  186.         jz      @f
  187.         mov     si, aKernelNotFound
  188.         jmp     bx
  189. @@:
  190. ; for subsequent calls to callback function, hook error handler
  191. ;       mov     byte [bx], 0xE9         ; 'jmp' opcode
  192. ;       mov     ax, hooked_err - 3
  193. ;       sub     ax, bx
  194. ;       mov     word [bx+1], ax
  195. ; push hooked_err / ret
  196.         mov     word [bx], 0x68 + ((hooked_err and 0xFF) shl 8)
  197.         mov     word [bx+2], (hooked_err shr 8) + (0xC3 shl 8)
  198. ; set registers for secondary loader
  199.         mov     ah, [BS_DrvNum]
  200.         mov     al, 'f'
  201.         test    ah, ah
  202.         jns     @f
  203.         sub     ah, 80h
  204.         mov     al, 'h'
  205. @@:
  206.         mov     bx, '12'
  207.         cmp     [fat_type], 0
  208.         jz      @f
  209.         mov     bh, '6'
  210. @@:
  211.         mov     si, callback    ; ds:si = far pointer to callback procedure
  212.         jmp     far [si-callback+secondary_loader_info] ; jump to 1000:0000
  213.  
  214. nomem_str       db      'No memory',0
  215.  
  216. chs_proc_addresses:
  217.         dw      chs_read_sectors
  218.         dw      chs_read_sectors2
  219.         dw      chs_lookup_in_root_dir
  220.         dw      chs_scan_for_filename
  221.         dw      chs_err
  222.         dw      chs_noloader
  223. lba_proc_addresses:
  224.         dw      lba_read_sectors
  225.         dw      lba_read_sectors2
  226.         dw      lba_lookup_in_root_dir
  227.         dw      lba_scan_for_filename
  228.         dw      lba_err
  229.         dw      lba_noloader
  230.  
  231. get_next_cluster:
  232. ; in: ax = cluster
  233. ; out: if there is next cluster: CF=1, ax = next cluster
  234. ; out: if there is no next cluster: CF=0
  235.         push    si
  236.         cmp     [fat_type], 0
  237.         jnz     gnc16
  238. ; for FAT12
  239.         push    ds
  240.         push    0x6000
  241.         pop     ds
  242.         mov     si, ax
  243.         shr     si, 1
  244.         add     si, ax
  245.         test    al, 1
  246.         lodsw
  247.         jz      @f
  248.         shr     ax, 4
  249. @@:
  250.         and     ax, 0xFFF
  251.         cmp     ax, 0xFF7
  252.         pop     ds si
  253.         ret
  254. ; for FAT16
  255. gnc16:
  256. ; each sector contains 200h bytes = 100h FAT entries
  257. ; so ah = # of sector, al = offset in sector
  258.         mov     si, ax
  259.         mov     ah, 0
  260.         shr     si, 8
  261. ; calculate segment for this sector of FAT table
  262. ; base for FAT table is 6000:0000, so the sector #si has to be loaded to (60000 + 200*si)
  263. ; segment = 6000 + 20*si, offset = 0
  264.         push    es
  265.         push    si
  266.         shl     si, 5
  267.         add     si, 0x6000
  268.         mov     es, si
  269.         pop     si
  270.         cmp     byte [ss:0x8200+si], ah ; sector already loaded?
  271.         jnz     @f
  272. ; load corresponding sector
  273.         pusha
  274.         push    es
  275.         xor     bx, bx
  276.         mov     ax, [BPB_RsvdSecCnt]
  277.         xor     dx, dx
  278.         add     ax, si
  279.         adc     dx, bx
  280.         mov     cx, 1   ; read 1 sector
  281.         call    [read_sectors]
  282.         pop     es
  283.         popa
  284. @@:
  285.         mov     si, ax
  286.         add     si, si
  287. ;       mov     ax, [es:si]
  288.         lods    word [es:si]
  289.         pop     es
  290.         cmp     ax, 0xFFF7
  291.         pop     si
  292.         ret
  293.  
  294. if $ > 0x8000
  295. error 'get_next_cluster must fit in first sector of kordldr.f1x!'
  296. end if
  297.  
  298. load_file:
  299. ; in: ss:bp = 0:7C00
  300. ; in: ds:di -> information structure
  301. ;       dw:dw   address
  302. ;       dw      limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
  303. ;       ASCIIZ  name
  304. ; out: bx = status: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found
  305. ; out: dx:ax = file size (0xFFFFFFFF if file not found)
  306.         xor     ax, ax  ; start from root directory
  307.         mov     dx, -1
  308.         mov     word [filesize], dx
  309.         mov     word [filesize+2], dx   ; initialize file size with invalid value
  310.         lea     si, [di+6]
  311. parse_dir_loop:
  312. ; convert name to FAT name
  313.         push    di
  314.         push    ax
  315.         push    ss
  316.         pop     es
  317. ; convert ASCIIZ filename to FAT name
  318.         mov     di, filename
  319.         push    di
  320.         mov     cx, 8+3
  321.         mov     al, ' '
  322.         rep stosb
  323.         pop     di
  324.         mov     cl, 8   ; 8 symbols per name
  325.         mov     bl, 1
  326. nameloop:
  327.         lodsb
  328.         test    al, al
  329.         jz      namedone
  330.         cmp     al, '/'
  331.         jz      namedone
  332.         cmp     al, '.'
  333.         jz      namedot
  334.         dec     cx
  335.         js      badname
  336.         cmp     al, 'a'
  337.         jb      @f
  338.         cmp     al, 'z'
  339.         ja      @f
  340.         sub     al, 'a'-'A'
  341. @@:
  342.         stosb
  343.         jmp     nameloop
  344. namedot:
  345.         inc     bx
  346.         jp      badname
  347.         add     di, cx
  348.         mov     cl, 3
  349.         jmp     nameloop
  350. badname:        ; do not make direct js/jp to notfound_pop:
  351.                 ; this generates long forms of conditional jumps and results in longer code
  352.         jmp     notfound_pop
  353. namedone:
  354. ; scan directory
  355.         pop     ax      ; ax = cluster of directory or 0 for root
  356.         push    ds
  357.         push    si
  358.         push    es
  359.         pop     ds
  360.         mov     si, filename    ; ds:si -> filename in FAT style
  361.         test    ax, ax
  362.         jnz     lookup_in_notroot_dir
  363. ; for root directory, use the subroutine from bootsector
  364.         call    [lookup_in_root_dir]
  365.         jmp     lookup_done
  366. lookup_in_notroot_dir:
  367. ; for other directories, read a folder sector-by-sector and scan
  368. ; first, try to use the cache
  369.         push    ds
  370.         push    cs
  371.         pop     ds
  372.         mov     bx, [cachelimit]
  373.         add     bx, bx
  374.         mov     di, foldcache_mark
  375. @@:
  376.         mov     dx, [foldcache_clus+di-foldcache_mark+bx]
  377.         cmp     dx, ax
  378.         jz      cacheok
  379.         test    dx, dx
  380.         jz      cacheadd        ; the cache has place for new entry
  381.         dec     bx
  382.         dec     bx
  383.         jns     @b
  384. ; the folder is not present in the cache, so add it
  385. ; the cache is full; find the oldest entry and replace it with the new one
  386.         mov     dx, [cachelimit]
  387. @@:
  388.         inc     bx
  389.         inc     bx
  390.         cmp     word [di+bx], dx        ; marks have values 0 through [cachelimit]
  391.         jnz     @b
  392. cacheadd:
  393.         or      word [di+bx], 0xFFFF    ; very big value, it will be changed soon
  394.         mov     [foldcache_clus+di-foldcache_mark+bx], ax
  395.         and     [foldcache_size+di-foldcache_mark+bx], 0        ; no folder items yet
  396. cacheok:
  397. ; update cache marks
  398.         mov     dx, [di+bx]
  399.         mov     cx, [foldcache_size+di-foldcache_mark+bx]
  400.         mov     di, [cachelimit]
  401.         add     di, di
  402. cacheupdate:
  403.         cmp     [foldcache_mark+di], dx
  404.         adc     [foldcache_mark+di], 0
  405.         dec     di
  406.         dec     di
  407.         jns     cacheupdate
  408.         and     [foldcache_mark+bx], 0
  409. ; done, bx contains (position in cache)*2
  410.         pop     ds
  411. ;       mov     dx, bx
  412. ;       shl     dx, 8           ; dx = (position in cache)*0x2000/0x10
  413. ;       add     dx, 0x9200
  414.         lea     dx, [bx+0x92]
  415.         xchg    dl, dh
  416.         mov     es, dx
  417.         jcxz    not_in_cache
  418.         call    [scan_for_filename]
  419.         jz      lookup_done
  420. not_in_cache:
  421. ; cache miss, read folder data from disk
  422.         mov     bx, cx
  423.         shr     bx, 4
  424.         shl     cx, 5
  425.         mov     di, cx          ; es:di -> free space in cache entry
  426. ; external loop: scan clusters
  427. folder_next_cluster:
  428. ; internal loop: scan sectors in cluster
  429.         mov     cx, [sect_per_clus]
  430.         push    ax
  431.         dec     ax
  432.         dec     ax
  433.         mul     cx
  434.         add     ax, [bp-8]
  435.         adc     dx, [bp-6]      ; dx:ax = absolute sector
  436. folder_next_sector:
  437. ; skip first bx sectors
  438.         dec     bx
  439.         jns     folder_skip_sector
  440.         push    cx
  441.         push    es di
  442.         push    0x8000
  443.         pop     es
  444.         xor     bx, bx
  445.         mov     cx, 1
  446.         push    es
  447.         call    [read_sectors]
  448. ; copy data to the cache...
  449.         pop     ds
  450.         pop     di es
  451.         cmp     di, 0x2000      ; ...if there is free space, of course
  452.         jae     @f
  453.         push    si di
  454.         mov     cx, 0x100
  455.         xor     si, si
  456.         rep movsw
  457.         mov     di, es
  458.         shr     di, 8
  459.         add     [ss:foldcache_size+di-0x92], 0x10       ; 0x10 new entries in the cache
  460.         pop     di si
  461. @@:
  462.         push    es
  463.         push    0x8000
  464.         pop     es
  465.         push    cs
  466.         pop     ds
  467.         mov     cx, 0x10
  468.         call    [scan_for_filename]
  469.         pop     es
  470.         pop     cx
  471.         jz      lookup_done_pop
  472. folder_skip_sector:
  473.         inc     ax
  474.         jnz     @f
  475.         inc     dx
  476. @@:
  477.         loop    folder_next_sector
  478.         pop     ax      ; ax = current cluster
  479.         call    get_next_cluster
  480.         jc      folder_next_cluster
  481.         stc
  482.         push    ax
  483. lookup_done_pop:
  484.         pop     ax
  485. lookup_done:
  486.         pop     si
  487.         pop     ds
  488. ; CF=1 <=> failed
  489.         jnc     found
  490. notfound:
  491.         pop     di
  492.         mov     bx, 2   ; file not found
  493.         mov     ax, 0xFFFF
  494.         mov     dx, ax  ; invalid file size
  495.         ret
  496. notfound_pop:
  497.         pop     ax
  498.         jmp     notfound
  499. found:
  500.         mov     ax, [es:di+26]  ; get cluster
  501.         test    byte [es:di+11], 10h    ; directory?
  502.         jz      regular_file
  503.         cmp     byte [si-1], 0
  504.         jz      notfound        ; don't read directories as a regular files
  505. ; ok, we have found a directory and the caller requested a file into it
  506.         pop     di
  507.         jmp     parse_dir_loop  ; restart with new cluster in ax
  508. regular_file:
  509.         cmp     byte [si-1], 0
  510.         jnz     notfound        ; file does not contain another files
  511. ; ok, we have found a regular file and the caller requested it
  512. ; save file size
  513.         mov     dx, [es:di+28]
  514.         mov     [filesize], dx
  515.         mov     dx, [es:di+30]
  516.         mov     [filesize+2], dx
  517.         pop     di
  518.         mov     si, [di+4]
  519.         shl     si, 3
  520.         push    si              ; [ds:di+4] = limit in 4K blocks
  521.         les     bx, [di]        ; es:bx -> buffer
  522. clusloop:
  523. ; ax = first cluster, top of stack contains limit in sectors
  524.         mov     si, ax  ; remember current cluster
  525.         xor     cx, cx  ; cx will contain number of consecutive clusters
  526.         mov     word [cur_delta], cx
  527.         mov     word [cur_delta+2], cx
  528.         mov     di, ax
  529. clusfind:
  530.         inc     di
  531.         inc     cx
  532.         call    get_next_cluster
  533.         jnc     clusread
  534.         cmp     ax, di
  535.         jz      clusfind
  536.         stc
  537. clusread:
  538.         pop     di      ; limit in sectors
  539.         push    ax      ; save next cluster
  540.         pushf           ; save flags
  541. ; read cx clusters, starting from si
  542. ; calculate number of sectors
  543.         xchg    ax, cx
  544.         mul     [sect_per_clus]
  545. ; dx:ax = number of sectors; compare with limit
  546.         mov     word [num_sectors], ax
  547.         mov     word [num_sectors+2], dx
  548.         jmp     @f
  549. continue_load_file:
  550.         les     bx, [di]        ; es:bx -> buffer
  551.         mov     di, [di+4]      ; ds:di = limit in 4K blocks
  552.         shl     di, 3   ; now di = limit in sectors
  553.         mov     ax, word [num_sectors]
  554.         mov     dx, word [num_sectors+2]
  555.         mov     si, [cur_cluster]
  556.         push    [next_cluster]
  557.         push    [flags]
  558.         or      ax, dx
  559.         jz      nextclus
  560. @@:
  561.         test    dx, dx
  562.         jnz     clusdecrease
  563.         push    dx      ; limit was not exceeded
  564.         cmp     ax, di
  565.         jbe     @f
  566.         pop     ax
  567. clusdecrease:
  568.         push    1       ; limit was exceeded
  569.         mov     ax, di
  570. @@:
  571.         sub     di, ax  ; calculate new limit
  572.         sub     word [num_sectors], ax
  573.         sbb     word [num_sectors+2], 0
  574. readloop:
  575.         push    ax
  576. ; buffer should not cross a 64K boundary
  577.         push    bx
  578.         shr     bx, 4
  579.         mov     cx, es
  580.         add     bx, cx
  581.         neg     bx
  582.         and     bh, 0xF
  583.         shr     bx, 5
  584.         jnz     @f
  585.         mov     bl, 0x80
  586. @@:
  587.         cmp     ax, bx
  588.         jbe     @f
  589.         xchg    ax, bx
  590. @@:
  591.         pop     bx
  592.         xchg    ax, cx
  593. ; calculate starting sector
  594.         lea     ax, [si-2]
  595.         mul     [sect_per_clus]
  596.         add     ax, word [cur_delta]
  597.         adc     dx, word [cur_delta+2]
  598.         add     word [cur_delta], cx
  599.         adc     word [cur_delta+2], 0
  600. ; read
  601.         call    [read_sectors2]
  602.         pop     ax
  603.         sub     ax, cx
  604.         jnz     readloop
  605.         pop     dx
  606. ; next cluster?
  607. nextclus:
  608.         popf
  609.         pop     ax
  610.         mov     [cur_cluster], si
  611.         mov     [next_cluster], ax
  612.         pushf
  613.         pop     [flags]
  614.         jnc     @f      ; no next cluster => return
  615.         mov     dl, 1   ; dh=0 in any case
  616.         test    di, di
  617.         jz      @f      ; if there is next cluster but current limit is 0 => return: limit exceeded
  618.         push    di
  619.         jmp     clusloop        ; all is ok, continue
  620. hooked_err:
  621.         mov     sp, 7C00h-12-2  ; restore stack
  622.         mov     dx, 3           ; return: read error
  623. @@:
  624.         mov     bx, dx
  625.         mov     ax, [filesize]
  626.         mov     dx, [filesize+2]
  627.         ret
  628.  
  629. ; Callback function for secondary loader
  630. callback:
  631. ; in: ax = function number; only functions 1 and 2 are defined for now
  632. ; save caller's stack
  633.         mov     dx, ss
  634.         mov     cx, sp
  635. ; set our stack (required because we need ss=0)
  636.         xor     si, si
  637.         mov     ss, si
  638.         mov     sp, 7C00h-8
  639.         mov     bp, 7C00h
  640.         push    dx
  641.         push    cx
  642. ; call our function
  643.         stc     ; unsupported function
  644.         dec     ax
  645.         jz      callback_readfile
  646.         dec     ax
  647.         jnz     callback_ret
  648. ; function 2: continue loading file
  649. ; can be called only after function 1 returned value bx=1 (only part of file was loaded)
  650. ; in: ds:di -> information structure
  651. ;       dw:dw   address
  652. ;       dw      limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
  653. ; out: bx=0 - ok, bx=1 - still only part of file was loaded, bx=3 - read error
  654. ; out: dx:ax = file size
  655.         call    continue_load_file
  656.         jmp     callback_ret_succ
  657. callback_readfile:
  658. ; function 1: read file
  659. ; in: ds:di -> information structure
  660. ;       dw:dw   address
  661. ;       dw      limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
  662. ;       ASCIIZ  name
  663. ; 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
  664. ; out: dx:ax = file size (0xFFFFFFFF if file was not found)
  665.         call    load_file
  666. callback_ret_succ:
  667.         clc     ; function is supported
  668. callback_ret:
  669. ; restore caller's stack
  670.         pop     cx
  671.         pop     ss
  672.         mov     sp, cx
  673. ; return to caller
  674.         retf
  675.  
  676. secondary_loader_info:
  677.         dw      0, 0x1000
  678.         dw      0x30000 / 0x1000
  679.         db      'kernel.mnt',0
  680. aKernelNotFound db      'Fatal error: cannot load the kernel',0
  681.  
  682. foldcache_clus  dw      0,0,0,0,0,0,0   ; start with no folders in cache
  683. foldcache_mark  rw      7
  684. foldcache_size  rw      7
  685. filename        rb      11
  686. if $ > 0x8200
  687. error:
  688.        table overwritten
  689. end if
  690.