forked from gardners/c65gs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kickstart_dos.a65
2425 lines (2057 loc) · 54.1 KB
/
kickstart_dos.a65
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; XXX - Track down why 2nd and subsequent LFN blocks are not used.
.alias os_version $0101
.alias dos_version $0101
.alias constant_partition_type_fat32_chs $0b
.alias constant_partition_type_fat32_lba $0c
; DOS error codes
.alias dos_errorcode_partition_not_interesting $01
.alias dos_errorcode_bad_signature $02
.alias dos_errorcode_is_small_fat $03
.alias dos_errorcode_too_many_reserved_clusters $04
.alias dos_errorcode_not_two_fats $05
.alias dos_errorcode_too_few_clusters $06
.alias dos_errorcode_read_timeout $07
.alias dos_errorcode_partition_error $08
.alias dos_errorcode_invalid_address $10
.alias dos_errorcode_illegal_value $11
.alias dos_errorcode_no_such_disk $80
.alias dos_errorcode_name_too_long $81
.alias dos_errorcode_not_implemented $82
.alias dos_errorcode_file_too_long $83
.alias dos_errorcode_too_many_open_files $84
.alias dos_errorcode_invalid_cluster $85
.alias dos_errorcode_is_a_directory $86
.alias dos_errorcode_not_a_directory $87
.alias dos_errorcode_file_not_found $88
.alias dos_errorcode_invalid_file_descriptor $89
.alias dos_errorcode_image_wrong_length $8A
.alias dos_errorcode_image_fragmented $8B
.alias dos_errorcode_eof $FF
; FAT directory entry constants
.alias fs_fat32_dirent_offset_attributes 11
.alias fs_fat32_dirent_offset_shortname 0
.alias fs_fat32_dirent_offset_create_tenthsofseconds 13
.alias fs_fat32_dirent_offset_create_time 14
.alias fs_fat32_dirent_offset_create_date 16
.alias fs_fat32_dirent_offset_access_date 18
.alias fs_fat32_dirent_offset_clusters_high 20
.alias fs_fat32_dirent_offset_modify_time 22
.alias fs_fat32_dirent_offset_modify_date 24
.alias fs_fat32_dirent_offset_clusters_low 26
.alias fs_fat32_dirent_offset_file_length 28
; VFAT long file name entry constants
.alias fs_fat32_dirent_offset_lfn_part_number 0
.alias fs_fat32_dirent_offset_lfn_type 12
.alias fs_fat32_dirent_offset_lfn_checksum 13
.alias fs_fat32_dirent_offset_lfn_part1_chars 5
.alias fs_fat32_dirent_offset_lfn_part1_start 1
.alias fs_fat32_dirent_offset_lfn_part2_chars 6
.alias fs_fat32_dirent_offset_lfn_part2_start 14
.alias fs_fat32_dirent_offset_lfn_part3_chars 2
.alias fs_fat32_dirent_offset_lfn_part3_start 28
.alias fs_fat32_attribute_isreadonly $01
.alias fs_fat32_attribute_ishidden $02
.alias fs_fat32_attribute_issystem $04
.alias fs_fat32_attribute_isvolumelabel $08
.alias fs_fat32_attribute_isdirectory $10
.alias fs_fat32_attribute_archiveset $20
; Possible file modes
.alias dos_filemode_directoryaccess $80
.alias dos_filemode_end_of_directory $81
.alias dos_filemode_readonly 0
.alias dos_filemode_readwrite 1
; 256-byte fixed size records for REL emulaton
.alias dos_filemode_relative 2
dos_and_process_trap:
; XXX - Machine is being updated to automatically disable IRQs on trapping
; to hypervisor, but for now, we need to do this explicitly.
; Should be able to be removed after 20160103
sei
; Sub-function is selected by A.
; Bits 6-1 are the only ones used.
; Mask out bit 0 so that indirect jmp's are valid.
and #$FE
; to save memory we only allow this table to be 128 bytes long,
; thus we have to check that bit 7 is clear.
bmi invalid_subfunction
tax
jmp (dos_and_process_trap_table,x)
dos_and_process_trap_table:
; $00 - $0E
.word trap_dos_getversion
.word trap_dos_getdefaultdrive
.word trap_dos_getcurrentdrive
.word trap_dos_selectdrive
.word trap_dos_getdisksize
.word trap_dos_getcwd
.word trap_dos_chdir
.word trap_dos_mkdir
; $10 - $1E
.word trap_dos_rmdir
.word trap_dos_opendir
.word trap_dos_readdir
.word trap_dos_closedir
.word trap_dos_openfile
.word trap_dos_readfile
.word trap_dos_writefile
.word trap_dos_mkfile
; $20 - $2E
.word trap_dos_closefile
.word trap_dos_closeall
.word trap_dos_seekfile
.word trap_dos_rmfile
.word trap_dos_fstat
.word trap_dos_rename
.word trap_dos_filedate
.word trap_dos_setname
; $30 - $3E
.word trap_dos_findfirst
.word trap_dos_findnext
.word trap_dos_findfile
.word trap_dos_loadfile
.word trap_dos_geterrorcode
.word invalid_subfunction
.word invalid_subfunction
.word invalid_subfunction
; $40 - $4E
.word trap_dos_d81attach
.word trap_dos_d81detach
.word trap_dos_d81writeen
.word invalid_subfunction
.word invalid_subfunction
.word invalid_subfunction
.word invalid_subfunction
.word invalid_subfunction
; $50 - $5E
.word trap_dos_gettasklist
.word trap_dos_sendmessage
.word trap_dos_receivemessage
.word trap_dos_writeintotask
.word trap_dos_readoutoftask
.word invalid_subfunction
.word invalid_subfunction
.word invalid_subfunction
; $70 - $7E
.word trap_dos_terminateothertask
.word trap_dos_create_task_native
.word trap_dos_load_into_task
.word trap_dos_create_task_c64
.word trap_dos_create_task_c65
.word trap_dos_exit_and_switch_to_task
.word trap_dos_switch_to_task
.word trap_dos_exit_task
; Return OS and DOS version.
; A/X = OS Version major/minor
; Z/Y = DOS Version major/minor
trap_dos_getversion:
lda #<os_version
sta hypervisor_x
lda #>os_version
sta hypervisor_a
lda #<dos_version
sta hypervisor_z
lda #>dos_version
sta hypervisor_y
jmp return_from_trap_with_success
trap_dos_getdefaultdrive:
lda dos_default_disk
sta hypervisor_a
jmp return_from_trap_with_success
trap_dos_selectdrive:
jsr dos_set_current_disk
return_from_trap_with_carry_flag:
bcs return_from_trap_with_success
bcc return_from_trap_with_failure
trap_dos_closeall:
jsr dos_clear_filedescriptors
jmp return_from_trap_with_success
trap_dos_loadfile:
; Only allow loading into lower 16MB to avoid possibility of writing
; over hypervisor
lda hypervisor_x
sta dos_file_loadaddress
lda hypervisor_y
sta dos_file_loadaddress+1
lda hypervisor_z
sta dos_file_loadaddress+2
lda #$00
sta dos_file_loadaddress+3
jsr dos_readfileintomemory
jmp return_from_trap_with_carry_flag
trap_dos_setname:
; read file name from any where in bottom 32KB of RAM, as mapped on entry
; to the hypervisor (this prevents the user from setting the filename to some
; piece of the hypervisor, and thus leaking hypervisor data to user-land if the
; user were to later query the filename).
jsr checkpoint
.byte 0,"trap_dos_setname",0
jsr hypervisor_setup_copy_region
bcc tdsnfailure
ldy #$3f
tdsn1: lda (<hypervisor_userspace_copy_vector),y
sta dos_requested_filename,y
dey
bpl tdsn1
; now set length
lda hypervisor_z
cmp #$3f
bcc tdsn2
lda #dos_errorcode_name_too_long
sta dos_error_code
jmp return_from_trap_with_failure
tdsn2:
; setname succeeded
stz dos_requested_filename_len
; upper case the filename for comparison
jsr dos_requested_filename_to_uppercase
; clear out checkpoint message to make sure there are no $00 chars hiding
; to cause grief.
lda #$20
ldy #39
tdsn6:
sta setnamemsg,y
dey
cpy #11
bne tdsn6
tdsn5:
; display name length in checkpoint message
tza
tax
jsr checkpoint_bytetohex
sty setnamemsglen+0
stx setnamemsglen+1
; Display filename in checkpoint message
cpz #24
bcc tdsn3
ldz #24
tdsn3:
tza
tay
dey
tdsn4: lda dos_requested_filename,y
bne tdsn7
lda #$3f ; ? mark in place of $00 chars
tdsn7:
sta setnamemsgname,y
dey
bpl tdsn4
tza
tay
lda #'\)
sta setnamemsgname,y
jsr checkpoint
.byte 0
setnamemsg:
.byte "setname($"
setnamemsglen:
.byte "%%,"
setnamemsgname:
.byte " "
.byte 0
jmp return_from_trap_with_success
tdsnfailure:
lda dos_error_code
jmp return_from_trap_with_failure
illegalvalue:
; tya
; tax
; jsr checkpoint_bytetohex
; sty iv1+0
; stx iv1+1
;
; jsr checkpoint
; .byte 0,"Filename contains $00 @ position $"
;iv1: .byte "%%",0
lda #dos_errorcode_illegal_value
sta dos_error_code
jmp return_from_trap_with_failure
trap_dos_getcurrentdrive:
lda dos_disk_current_disk
sta hypervisor_a
jmp return_from_trap_with_success
trap_dos_opendir:
; Open the current working directory for iteration.
jsr dos_opendir
bcs tdod1
; Something has gone wrong. Assume dos_opendir will
; have set error code
lda dos_error_code
jmp return_from_trap_with_failure
tdod1:
; Directory opened ok.
lda dos_current_file_descriptor
sta hypervisor_a
jmp return_from_trap_with_success
trap_dos_readdir:
; Read next directory entry from file descriptor $XX
; Return dirent structure to $YY00
; in first 32KB of mapped address space
jsr checkpoint
.byte 0,"trap_dos_readdir",0
jsr sd_map_sectorbuffer
; Get offset to current file descriptor
; (we can't use X register, as has been clobbered in the jump
; table dispatch code)
ldx hypervisor_x
stx dos_current_file_descriptor
jsr dos_get_file_descriptor_offset
bcc tdrd1
sta dos_current_file_descriptor_offset
jsr dos_readdir
bcc tdrd1
; Read the directory entry, now copy it to userland
jsr hypervisor_setup_copy_region
bcc tdrd1
; We can now copy the bytes of the dirent to user-space
ldy #dos_dirent_structure_length-1
tdrd2:
lda dos_dirent_longfilename,y
sta (<hypervisor_userspace_copy_vector),y
dey
bpl tdrd2
jsr checkpoint
.byte 0,"trap_dos_readdir <success>",0
jmp return_from_trap_with_success
tdrd1:
jsr checkpoint
.byte 0,"trap_dos_readdir <failure>",0
lda dos_error_code
jmp return_from_trap_with_failure
trap_dos_closedir:
jmp trap_dos_closefile
trap_dos_openfile:
; Opens file in current dirent structure
; XXX - This means we must preserve the dirent struct when
; context-switching to avoid a race-condition
jsr dos_openfile
bcc tdof1
jsr checkpoint
.byte 0,"trap_dos_openfile <success>",0
jmp return_from_trap_with_success
tdof1:
jsr checkpoint
.byte 0,"trap_dos_openfile <failure>",0
lda dos_error_code
jmp return_from_trap_with_failure
trap_dos_closefile:
ldx hypervisor_x
stx dos_current_file_descriptor
jsr dos_get_file_descriptor_offset
bcc tdcf1
jsr dos_closefile
bcc tdcf1
jsr checkpoint
.byte 0,"trap_dos_closefile <success>",0
jmp return_from_trap_with_success
tdcf1:
jsr checkpoint
.byte 0,"trap_dos_closefile <failure>",0
lda dos_error_code
jmp return_from_trap_with_failure
trap_dos_findfile:
jsr dos_findfile
jmp return_from_trap_with_carry_flag
trap_dos_findfirst:
jsr dos_findfirst
jmp return_from_trap_with_carry_flag
trap_dos_findnext:
jsr dos_findnext
jmp return_from_trap_with_carry_flag
trap_dos_geterrorcode:
lda dos_error_code
sta hypervisor_a
tax
jsr checkpoint_bytetohex
sty tdgec1+0
stx tdgec1+1
jsr checkpoint
.byte 0,"dos_geterrorcode <=$"
tdgec1: .byte "%%>",0
jmp return_from_trap_with_success
trap_dos_d81attach:
jsr checkpoint
.byte 0,"trap_dos_d81attach",0
lda #$00
sta $d68b
jsr dos_d81attach
jmp return_from_trap_with_carry_flag
trap_dos_d81detach:
lda #$00
sta $d68b
jmp return_from_trap_with_success
trap_dos_d81writeen:
lda $d68b
and #$03
cmp #$03
bne td81we1
ora #$04
sta $d68b
jmp return_from_trap_with_success
td81we1:
; No disk image mounted
lda #dos_errorcode_no_such_disk
sta dos_error_code
jmp return_from_trap_with_failure
trap_dos_readfile:
trap_dos_getdisksize:
trap_dos_getcwd:
trap_dos_chdir:
trap_dos_mkdir:
trap_dos_rmdir:
trap_dos_mkfile:
trap_dos_writefile:
trap_dos_seekfile:
trap_dos_rmfile:
trap_dos_fstat:
trap_dos_rename:
trap_dos_filedate:
trap_dos_gettasklist:
trap_dos_sendmessage:
trap_dos_receivemessage:
trap_dos_writeintotask:
trap_dos_readoutoftask:
trap_dos_terminateothertask:
trap_dos_create_task_native:
trap_dos_load_into_task:
trap_dos_create_task_c64:
trap_dos_create_task_c65:
trap_dos_exit_and_switch_to_task:
trap_dos_switch_to_task:
trap_dos_exit_task:
jmp invalid_subfunction;
; Clear all file descriptors.
; This just consists of setting the drive number to $ff,
; which indicates "no such drive"
; Drive number field is first byte of file descriptor for convenience
dos_clear_filedescriptors:
; XXX - This doesn't close the underlying file descriptors!
lda #$ff
sta currenttask_filedescriptor0
sta currenttask_filedescriptor1
sta currenttask_filedescriptor2
sta currenttask_filedescriptor3
sec
rts
; Read partition table from SD card.
; Add all FAT32 partitions to our list of known disks.
; This routine assumes that the SD card has been reset and is ready to
; service requests.
; XXX - We don't support extended partition tables! Only the old-fashion
; 4 DOS partitions. We might get excited and add support for them later,
; but
dos_read_partitiontable:
; clear error code
lda #0
sta dos_error_code
; Clear the list of known disks
jsr dos_initialise_disklist
jsr dos_read_mbr
bcc drpt_fail
; Make the sector buffer visible
jsr sd_map_sectorbuffer
lda #dos_errorcode_bad_signature
sta dos_error_code
; check for $55AA MBR signature
lda [sd_sectorbuffer+$1FE]
cmp #$55
bne drpt_fail
lda [sd_sectorbuffer+$1FF]
cmp #$AA
bne drpt_fail
; Partitions start at offsets $1BE, $1CE, $1DE, $1EE
; so consider each in turn. Opening the partition causes other sectors to
; be read, so we must re-read the MBR between each
; get pointer to second half of sector buffer so that we can access the
; partition entries as we see fit.
lda #<[sd_sectorbuffer+$1BE]
sta dos_scratch_vector
lda #>[sd_sectorbuffer+$1BE]
sta dos_scratch_vector+1
jsr dos_consider_partition_entry
jsr dos_read_mbr
bcc drpt_fail
lda #<[sd_sectorbuffer+$1CE]
sta dos_scratch_vector
jsr dos_consider_partition_entry
jsr dos_read_mbr
bcc drpt_fail
lda #<[sd_sectorbuffer+$1DE]
sta dos_scratch_vector
jsr dos_consider_partition_entry
jsr dos_read_mbr
bcc drpt_fail
lda #<[sd_sectorbuffer+$1EE]
sta dos_scratch_vector
jsr dos_consider_partition_entry
lda #0
sta dos_error_code
sec
rts
dos_read_mbr:
; Offset zero on disk
lda #0
sta sd_address_byte0
sta sd_address_byte1
sta sd_address_byte2
sta sd_address_byte3
; Read sector
jsr sd_readsector
bcc drpt_fail
rts
dos_initialise_disklist:
lda #0
sta dos_disk_count
rts
dos_consider_partition_entry:
lda #$00
sta dos_error_code
; Offset within partition table entry of partition type
ldy #$04
; Get partition type byte
lda (<dos_scratch_vector),y
; We like FAT32 partitions, whether LBA or CHS addressed, although we actually
; use LBA addressing. XXX - Can this cause problems for CHS partitions?
; (SD cards which must really use LBA, can still show up with CHS partitions!
; this is really annoying.)
cmp #constant_partition_type_fat32_lba
beq partitionisinteresting
cmp #constant_partition_type_fat32_chs
beq partitionisinteresting
lda #dos_errorcode_partition_not_interesting
sta dos_error_code
jmp partitionisnotinteresting
partitionisinteresting:
; Partition is FAT32, so add it to the list
; Disk structures in dos_disk_table are 32 bytes long, so shift count left
; 5 times to get offset in dos disk list table
lda dos_disk_count
asl
asl
asl
asl
asl
tax
; Copy relevant fields into place
; These are start of partition and length of partition (both in sectors)
; XXX - This requires that our dos_disk_table has these two fields together
; at the start of the structure.
ldy #$08
dcpe1: lda (<dos_scratch_vector),y
sta dos_disk_table,x
inx
iny
cpy #$10
bne dcpe1
; Examine the internals of the partition to get the remaining fields.
; At this point we no longer use the contents of the MBR
lda dos_disk_count
jsr dos_disk_openpartition
bcc partitionerror
; Check if partition is bootable (or the only partition)
; If so, make the partition the default disk
lda dos_disk_count
beq makethispartitionthedefault
ldy #$00
lda (<dos_scratch_vector),y
bpl dontmakethispartitionthedefault
makethispartitionthedefault:
lda dos_disk_count
sta dos_default_disk
dontmakethispartitionthedefault:
partitionisnotinteresting:
; return OK
sec
rts
drpt_fail:
; error code will already be set
partitionerror:
; return ERROR
clc
rts
; Examine a partition to see if we can mount it.
; This routine fills in the missing fields for the disk entry as required.
; It assumes that fs_start_sector and fs_sector_count have been correctly set.
; Each disk entry consists of;
; Offset $00 - starting sector (4 bytes)
.alias fs_start_sector $00
; Offset $04 - sector count (4 bytes)
.alias fs_sector_count $04
; Offset $08 - Filesystem type & media source ($0x = FAT32, $xF = SD card, others reserved for now)
.alias fs_type_and_source $08
; Remaining bytes are filesystem dependent:
; For FAT32:
; Offset $09 - length of fat (4 bytes) (FAT starts at fs_fat32_system_sectors)
.alias fs_fat32_length_of_fat $09
; Offset $0D - system sectors (2 bytes)
.alias fs_fat32_system_sectors $0D
; Offset $0F - reserved clusters (1 byte)
.alias fs_fat32_reserved_clusters $0F
; Offset $10 - root dir cluster (2 bytes)
.alias fs_fat32_root_dir_cluster $10
; Offset $12 - cluster count (4 bytes)
.alias fs_fat32_cluster_count $12
; Offset $16 - sectors per cluster
.alias fs_fat32_sectors_per_cluster $16
; Offset $17 - copies of FAT
.alias fs_fat32_fat_copies $17
; Offset $18 - first sector of cluster zero (4 bytes)
.alias fs_fat32_cluster0_sector $18
; Offset $1C - Four spare bytes.
dos_disk_openpartition:
; A contains the disk number we are trying to open.
lda #$00
sta dos_error_code
; Load first sector of file system and parse.
; This is the Volume Boot Record
; Get offset of disk entry in our disk table structure
asl
asl
asl
asl
asl
sta dos_disk_table_offset
; Now pull the start sector from the structure and get ready to request
; that structure from the SD card.
ora #fs_start_sector
tay
ldx #$00
ddop1: lda dos_disk_table,y
sta sd_address_byte0,x
iny
inx
cpx #$04
bne ddop1
; Convert sector number to byte offset for non-HC SD cards
jsr sd_fix_sectornumber
jsr sd_readsector
bcc partitionerror
; We now have the sector, so parse.
jsr sd_map_sectorbuffer
; Check for 55/AA singature
lda #dos_errorcode_bad_signature
sta dos_error_code
lda [sd_sectorbuffer+$1FE]
cmp #$55
bne partitionerror
lda [sd_sectorbuffer+$1FF]
cmp #$AA
bne partitionerror
; Start populating fields
; Filter out obviously FAT16/FAT12 file systems
lda #dos_errorcode_is_small_fat
sta dos_error_code
lda [sd_sectorbuffer+$11]
bne partitionerror
; get # copies of fat
lda dos_disk_table_offset
ora #fs_fat32_fat_copies
tay
lda [sd_sectorbuffer+$10]
sta dos_disk_table,y
; With root directory entries = 0, the reserved sector count
; is the number of reserved sectors, plus (copies of fat) *
; (sectors in one copy of the fat).
; the first FAT begins immediately after the reserved sectors
; Determine system sector count
; (= reserved sectors + fat_count * fat_sectors)
; $20 + $EE5 + $EE5 = $1DEA
; plus partition offset = $81 = $1E6B
; partition length = $3BAF7F
; $08 sectors / cluster
; so data sectors in partition = $3BAF7F - $1DEA = $3B9195
; = $77232 clusters
; Reserved sector field on disk is only 2 bytes!
lda dos_disk_table_offset
ora #fs_fat32_system_sectors
tay
ldx #$00
ddop10: lda [sd_sectorbuffer+$0E],x
sta dos_disk_table,y
iny
inx
cpx #$02
bne ddop10
; Store length of one copy of the FAT
lda dos_disk_table_offset
ora #fs_fat32_length_of_fat
tay
ldx #$00
ddop11: lda [sd_sectorbuffer+$24],x
sta dos_disk_table,y
iny
inx
cpx #$04
bne ddop11
; Get number of reserved clusters. We only allow upto 255 reserved
; clusters, so report an error if the upper two bytes are not both zero
lda #dos_errorcode_too_many_reserved_clusters
sta dos_error_code
lda [sd_sectorbuffer+$2C+1]
ora [sd_sectorbuffer+$2C+2]
ora [sd_sectorbuffer+$2C+3]
; XXX - 16 bit BNE should be fine here! Why doesn't it work?
; bne partitionerror
beq ddop11ok
jmp partitionerror
ddop11ok:
; <64K reserved clusters, so file system passes this test -- just copy number
ldy dos_disk_table_offset
lda [sd_sectorbuffer+$2C]
sta [dos_disk_table+fs_fat32_reserved_clusters],y
; Now work out the sector of cluster 0, by adding the length of
; each FAT to fs_fat32_system_sectors to start of partition.
; For efficiency, we pull the fields we need out of the sector buffer,
; instead of working out their offsets in the disk entry structure.
; Start with fs_fat32_system_sectors (which is 16 bits)
lda dos_disk_table_offset
ora #fs_fat32_system_sectors
tay
lda dos_disk_table_offset
ora #fs_fat32_cluster0_sector
tax
ldz #$02
ddop2: lda dos_disk_table,y
sta dos_disk_table,x
iny
inx
dez
bne ddop2
; clear top 16 bits of cluster0_sector
tza
sta [dos_disk_table+0],x
sta [dos_disk_table+1],x
; Now add length of fat for each copy of the fat
lda #dos_errorcode_not_two_fats
sta dos_error_code
ldz [sd_sectorbuffer+$10] ; # of FAT copies
beq partitionerror ; There must be at least one copy of the FAT!
cpz #2
bne partitionerror
ddop_addnextfatsectors:
lda dos_disk_table_offset
ora #fs_fat32_cluster0_sector
tay
ldx #$00
clc
php
ddop12: plp
lda dos_disk_table,y ; cluster0_sector
adc [sd_sectorbuffer+$24],x ; sectors per fat
sta dos_disk_table,y ; cluster0_sector
php
iny
inx
cpx #$04
bne ddop12
plp
dez
bne ddop_addnextfatsectors
; Next, we temporarily need the number of data sectors, so that we can work
; out the number of clusters in the file system.
; This is the total number of sectors in the partition, minus the number of
; reserved sectors.
; Subtract (cluster 0 sector = 32 bits) from
; (length of filesystem in sectors = 32 bits)
lda dos_disk_table_offset
ora #fs_fat32_cluster0_sector
tax
lda dos_disk_table_offset
ora #fs_fat32_cluster_count
tay
sec
lda [sd_sectorbuffer+$20+0]
sbc [dos_disk_table+0],x
sta [dos_disk_table+0],y
lda [sd_sectorbuffer+$20+1]
sbc [dos_disk_table+1],x
sta [dos_disk_table+1],y
lda [sd_sectorbuffer+$20+2]
sbc [dos_disk_table+2],x
sta [dos_disk_table+2],y
lda [sd_sectorbuffer+$20+3]
sbc [dos_disk_table+3],x
sta [dos_disk_table+3],y
; Get sectors per cluster (and store in dos_disk_table entry)
; (this gets destoryed below, so we have to re-read it again after)
lda dos_disk_table_offset
ora #fs_fat32_sectors_per_cluster
tay
lda [sd_sectorbuffer+$0D]
sta dos_disk_table,y
; Now divide number of sectors available for clusters by the number of
; sectors per cluster to obtain the number of actual clusters in the file
; system. Since clusters must contain a power-of-two number of sectors,
; we can implement the division using a simple shift.
; copy number of sectors into number of sectors ready for shifting down
; Put number of sectors per cluster into Z, and don't shift if there is only
; one sector per cluster.
taz
and #$fe
beq ddop_gotclustercount
ddop14:
; Divide cluster count by two. This is a 32-bit value, so we have to use
; ROR to do the shift, and propagate the carry bits between the bytes.
; This also entails doing it from the last byte, backwards.
; Get offset of start of (sectors_per_cluster) field
lda dos_disk_table_offset
ora #fs_fat32_cluster_count
; get offset of last byte in this field
clc
adc #$03
tay
ldx #$03
clc
ddop15: lda dos_disk_table,y
ror
sta dos_disk_table,y
dey
dex
bpl ddop15
tza
lsr
taz
and #$fe
bne ddop14
ddop_gotclustercount:
; Re-get sectors per cluster (and store in dos_disk_table entry)
; (this was destroyed in the calculation above)
lda dos_disk_table_offset
ora #fs_fat32_sectors_per_cluster
tay
lda [sd_sectorbuffer+$0D]
sta dos_disk_table,y
; filter out non-FAT32 filesystems
; NOTE: FAT32 can have as few as 65525 clusters, but we do not support
; such file systems, which should be rare, anyway.
lda dos_disk_table_offset
ora #fs_fat32_sectors_per_cluster
tay
lda #dos_errorcode_too_few_clusters
sta dos_error_code
lda dos_disk_table+3,y
ora dos_disk_table+2,y
beq partitionerror
; Now get cluster of root directory.
lda dos_disk_table_offset
ora #fs_fat32_root_dir_cluster
tay
ldx #$03
ddop16: lda [sd_sectorbuffer+$2C],x
sta dos_disk_table,y
dex
bpl ddop16
; We have now set the following fields:
; fs_fat32_length_of_fat
; fs_fat32_system_sectors
; fs_fat32_reserved_clusters
; fs_fat32_root_dir_cluster
; fs_fat32_sectors_per_cluster
; fs_fat32_fat_copies
; fs_fat32_cluster0_sector
; Our caller has set:
; fs_start_sector
; fs_sector_count
; So all that is left for us is to set fs_type_and_source to $0F
; to indicate FAT32 filesystem on the SD card ...
lda dos_disk_table_offset
ora #fs_type_and_source
tay
lda #$0f
sta dos_disk_table,y
; ... and increment the number of disks we know
inc dos_disk_count
dos_return_success:
; Return success
lda #$00
sta dos_error_code