Subversion Repositories Kolibri OS

Rev

Rev 1962 | Rev 3598 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2288 clevermous 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  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  ''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  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...