Subversion Repositories Kolibri OS

Rev

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