Subversion Repositories Kolibri OS

Rev

Rev 3305 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2644 clevermous 1
; FAT-specific code for tmpdisk.asm.
2
; Formats a disk to FAT16 or FAT32, depending on size.
3
; Note: formatting is adjusted for memory-based disks. Although the resulting
4
; image is a valid FAT32 volume, it has no "spare" sectors, e.g. second copy
5
; of FAT or place for second sector of MS FAT32 bootloader.
6
 
7
; Some constants
8
FAT16_ROOTDIR_SECTORS = 16 ; can be changed, but why not?
9
; FAT16:
10
;     1 bootsector,
11
;     min 0xFF5 sectors for data,
12
;     min (0xFF5*2/512) = 16 sectors per FAT, we use only one copy,
13
;     FAT16_ROOTDIR_SECTORS for root directory
14
MIN_FAT16_SIZE = 1 + 16 + FAT16_ROOTDIR_SECTORS + 0xFF5
15
; FAT32:
16
;     1 bootsector,
17
;     1 sector for fsinfo,
18
;     min 0xFFF5 sectors for data,
19
;     min (0xFFF5*4/512) = 512 sectors per FAT, we use only one copy
20
MIN_FAT32_SIZE = 1 + 1 + 512 + 0xFFF5
21
MAX_SIZE = 1 shl (30 - 9) ; 1G in 512-byte sectors
22
 
23
; Initializes FATxx structures on the disk.
24
; Called with edi = pointer to disk data, esi = size of disk.
25
proc format_disk
26
; Determine FAT type and jump to the corresponding handler.
27
        cmp     esi, MIN_FAT32_SIZE
28
        jae     format_disk_fat32
29
; Fall through to format_disk_fat16.
30
endp
31
 
32
; Structure of FAT16 bootsector. Field names are from MS spec.
33
struc FAT16BOOT
34
{
35
.BS_jmpBoot     rb      3
36
.BS_OEMName     rb      8
37
.BPB_BytsPerSec dw      ?
38
.BPB_SecsPerClus db     ?
39
.BPB_RsvdSecCnt dw      ?
40
.BPB_NumFATs    db      ?
41
.BPB_RootEntCnt dw      ?
42
.BPB_TotSec16   dw      ?
43
.BPB_Media      db      ?
44
.BPB_FATSz16    dw      ?
45
.BPB_SecPerTrk  dw      ?
46
.BPB_NumHeads   dw      ?
47
.BPB_HiddSec    dd      ?
48
.BPB_TotSec32   dd      ?
49
.BS_DrvNum      db      ?
50
.BS_Reserved1   db      ?
51
.BS_BootSig     db      ?
52
.BS_VolID       dd      ?
53
.BS_VolLab      rb      11
54
.BS_FilSysType  rb      8
55
}
56
virtual at 0
57
FAT16BOOT FAT16BOOT
58
end virtual
59
 
60
; Initializes FAT16 structures on the disk.
61
; Called with edi = pointer to disk data, esi = size of disk.
62
format_disk_fat16:
63
; 1. Calculate number of clusters.
64
; 1a. There are fixed-sized areas and there are data+FAT;
65
; every cluster uses 512 bytes in data area and 2 bytes in FAT area.
66
        lea     eax, [esi-1-FAT16_ROOTDIR_SECTORS]
67
; two following lines are equivalent to edx = floor(eax*512/514)
68
        mov     ecx, 0xFF00FF01
69
        mul     ecx     ; edx = number of clusters
70
; 1b. Force the number be less than 0xfff5.
71
        mov     eax, 0xFFF4
72
        cmp     edx, eax
73
        jb      @f
74
        mov     edx, eax
75
@@:
76
; 2. Zero all system areas on the disk.
3285 clevermous 77
        lea     ecx, [256*(1+FAT16_ROOTDIR_SECTORS)+edx+255]
2644 clevermous 78
        and     ecx, not 255
79
        shr     ecx, 1
80
        xor     eax, eax
81
        push    edi
82
        rep stosd
83
        pop     edi
84
; 3. Generate the bootsector.
85
; 3a. Copy static stub.
86
        push    esi edi
87
        mov     esi, fat16bootsector_stub
88
        mov     ecx, fat16bootsector_stub_size
89
        rep movsb
90
        pop     edi esi
91
        mov     word [edi+510], 0xAA55
92
; 3b. Set fields which depend on size.
93
        cmp     esi, 0x10000
94
        jae     .size_is_32bit
95
        mov     [edi+FAT16BOOT.BPB_TotSec16], si
96
        jmp     .size_written
97
.size_is_32bit:
98
        mov     [edi+FAT16BOOT.BPB_TotSec32], esi
99
.size_written:
100
        lea     eax, [edx+255]
101
        shr     eax, 8
102
        mov     [edi+FAT16BOOT.BPB_FATSz16], ax
103
; 3c. Generate volume ID.
104
        call    generate_volume_id
105
        mov     [edi+FAT16BOOT.BS_VolID], eax
106
; 4. Initialize FAT.
107
        mov     dword [edi+512], 0xFFFFFFF8
108
; 5. Return.
109
        ret
110
 
111
; Structure of FAT32 bootsector. Field names are from MS spec.
112
struc FAT32BOOT
113
{
114
.BS_jmpBoot     rb      3
115
.BS_OEMName     rb      8
116
.BPB_BytsPerSec dw      ?
117
.BPB_SecsPerClus db     ?
118
.BPB_RsvdSecCnt dw      ?
119
.BPB_NumFATs    db      ?
120
.BPB_RootEntCnt dw      ?
121
.BPB_TotSec16   dw      ?
122
.BPB_Media      db      ?
123
.BPB_FATSz16    dw      ?
124
.BPB_SecPerTrk  dw      ?
125
.BPB_NumHeads   dw      ?
126
.BPB_HiddSec    dd      ?
127
.BPB_TotSec32   dd      ?
128
.BPB_FATSz32    dd      ?
129
.BPB_ExtFlags   dw      ?
130
.BPB_FSVer      dw      ?
131
.BPB_RootClus   dd      ?
132
.BPB_FSInfo     dw      ?
133
.BPB_BkBootSec  dw      ?
134
.BPB_Reserved   rb      12
135
.BS_DrvNum      db      ?
136
.BS_Reserved1   db      ?
137
.BS_BootSig     db      ?
138
.BS_VolID       dd      ?
139
.BS_VolLab      rb      11
140
.BS_FilSysType  rb      8
141
}
142
virtual at 0
143
FAT32BOOT FAT32BOOT
144
end virtual
145
 
146
; Initializes FAT32 structures on the disk.
147
; Called with edi = pointer to disk data, esi = size of disk.
148
format_disk_fat32:
149
; 1. Calculate number of clusters.
150
; 1a. There is fixed-sized area and there are data+FAT;
151
; every cluster uses 512 bytes in data area and 4 bytes in FAT area.
152
        lea     eax, [esi-1-1]
153
; two following lines are equivalent to edx=floor(eax*512/516) if eax<10000000h
154
        mov     ecx, 0xFE03F810
155
        mul     ecx     ; edx = number of clusters
156
; 2. Zero all system areas on the disk and first cluster of data,
157
; used for root directory.
158
        lea     ecx, [128*(1+1+1)+edx+127]
159
        and     ecx, not 127
160
        xor     eax, eax
161
        push    edi
162
        rep stosd
163
        pop     edi
164
; 3. Generate the bootsector.
165
; 3a. Copy static stub.
166
        push    esi edi
167
        mov     esi, fat32bootsector_stub
168
        mov     ecx, fat32bootsector_stub_size
169
        rep movsb
170
        pop     edi esi
171
        mov     word [edi+510], 0xAA55
172
; 3b. Set fields which depend on size.
173
        mov     [edi+FAT32BOOT.BPB_TotSec32], esi
174
        lea     eax, [edx+127]
175
        shr     eax, 7
176
        mov     [edi+FAT32BOOT.BPB_FATSz32], eax
177
; 3c. Generate volume ID.
178
        call    generate_volume_id
179
        mov     [edi+FAT32BOOT.BS_VolID], eax
180
; 4. Initialize fsinfo sector.
181
        mov     dword [edi+512], 'RRaA'
182
        mov     dword [edi+512+484], 'rrAa'
183
        dec     edx ; one cluster is occupied by root dir
184
        mov     dword [edi+512+488], edx ; free count
185
        mov     byte [edi+512+492], 3 ; first free cluster
186
        mov     word [edi+512+510], 0xAA55
187
; 5. Initialize FAT.
188
        mov     dword [edi+512*2], 0x0FFFFFF8
189
        mov     dword [edi+512*2+4], 0x0FFFFFFF
190
        mov     dword [edi+512*2+8], 0x0FFFFFFF
191
; 6. Return.
192
        ret
193
 
194
; Generate volume serial number, which should try to be unique for each volume.
195
; Use CMOS date+time, copy-pasted from fat32.inc.
196
generate_volume_id:
197
        call    get_time_for_file
198
        mov     cx, ax
199
        call    get_date_for_file
200
        shl     eax, 16
201
        mov     ax, cx
202
        ret
203
 
204
; Three following procedures are copy-pasted from fat32.inc.
205
bcd2bin:
206
;----------------------------------
207
; input  : AL=BCD number (eg. 0x11)
208
; output : AH=0
209
;          AL=decimal number (eg. 11)
210
;----------------------------------
211
        xor     ah, ah
212
        shl     ax, 4
213
        shr     al, 4
214
        aad
215
        ret
216
 
217
get_date_for_file:
218
;-----------------------------------------------------
219
; Get date from CMOS and pack day,month,year in AX
220
; DATE   bits  0..4   : day of month 0..31
221
;              5..8   : month of year 1..12
222
;              9..15  : count of years from 1980
223
;-----------------------------------------------------
224
        mov     al, 0x7 ;day
225
        out     0x70, al
226
        in      al, 0x71
227
        call    bcd2bin
228
        ror     eax, 5
229
 
230
        mov     al, 0x8 ;month
231
        out     0x70, al
232
        in      al, 0x71
233
        call    bcd2bin
234
        ror     eax, 4
235
 
236
        mov     al, 0x9 ;year
237
        out     0x70, al
238
        in      al, 0x71
239
        call    bcd2bin
240
        add     ax, 20  ;because CMOS return only the two last
241
                        ;digit (eg. 2000 -> 00 , 2001 -> 01) and we
242
        rol     eax, 9  ;need the difference with 1980 (eg. 2001-1980)
243
        ret
244
 
245
 
246
get_time_for_file:
247
;-----------------------------------------------------
248
; Get time from CMOS and pack hour,minute,second in AX
249
; TIME   bits  0..4   : second (the low bit is lost)
250
;              5..10  : minute 0..59
251
;              11..15 : hour 0..23
252
;-----------------------------------------------------
253
        mov     al, 0x0 ;second
254
        out     0x70, al
255
        in      al, 0x71
256
        call    bcd2bin
257
        ror     eax, 6
258
 
259
        mov     al, 0x2 ;minute
260
        out     0x70, al
261
        in      al, 0x71
262
        call    bcd2bin
263
        ror     eax, 6
264
 
265
        mov     al, 0x4 ;hour
266
        out     0x70, al
267
        in      al, 0x71
268
        call    bcd2bin
269
        rol     eax, 11
270
        ret
271
 
272
; some data
273
fat16bootsector_stub:
274
        db 0EBh, 3Ch, 90h       ; BS_jmpBoot
275
        db 'KOLIBRI '           ; BS_OEMName
276
        dw 512                  ; BPB_BytsPerSec
277
        db 1                    ; BPB_SecsPerClus
278
        dw 1                    ; BPB_RsvdSecCnt
279
        db 1                    ; BPB_NumFATs
280
        dw FAT16_ROOTDIR_SECTORS*16 ; BPB_RootEntCnt
281
        dw 0                    ; BPB_TotSec16, filled in format_disk_fat16
282
        db 0F8h                 ; BPB_Media
283
        dw 0                    ; BPB_FATSz16, filled in format_disk_fat16
284
        dw 32                   ; BPB_SecPerTrk
285
        dw 128                  ; BPB_NumHeads
286
        dd 0                    ; BPB_HiddSec
287
        dd 0                    ; BPB_TotSec32, filled in format_disk_fat16
288
        db 80h                  ; BS_DrvNum
289
        db 0                    ; BS_Reserved1
290
        db 29h                  ; BS_BootSig
291
        dd 0                    ; BS_VolID, filled in format_disk_fat16
292
        db 'NO NAME    '        ; BS_VolLab
293
        db 'FAT16   '           ; BS_FilSysType
294
; just in case add some meaningful bytes if someone tries to boot
295
        db 0CDh, 19h, 0EBh, 0FEh ; int 19h, jmp $
296
fat16bootsector_stub_size = $ - fat16bootsector_stub
297
fat32bootsector_stub:
298
        db 0EBh, 58h, 90h       ; BS_jmpBoot
299
        db 'KOLIBRI '           ; BS_OEMName
300
        dw 512                  ; BPB_BytsPerSec
301
        db 1                    ; BPB_SecsPerClus
3305 clevermous 302
        dw 2                    ; BPB_RsvdSecCnt
2644 clevermous 303
        db 1                    ; BPB_NumFATs
304
        dw 0                    ; BPB_RootEntCnt
305
        dw 0                    ; BPB_TotSec16
306
        db 0F8h                 ; BPB_Media
307
        dw 0                    ; BPB_FATSz16
308
        dw 32                   ; BPB_SecPerTrk
309
        dw 128                  ; BPB_NumHeads
310
        dd 0                    ; BPB_HiddSec
311
        dd 0                    ; BPB_TotSec32, filled in format_disk_fat32
312
        dd 0                    ; BPB_FATSz32, filled in format_disk_fat32
313
        dw 0                    ; BPB_ExtFlags
314
        dw 0                    ; BPB_FSVer
315
        dd 2                    ; BPB_RootClus
316
        dw 1                    ; BPB_FSInfo
317
        dw 0                    ; BPB_BkBootSec
318
        rb 12                   ; BPB_Reserved
319
        db 80h                  ; BS_DrvNum
320
        db 0                    ; BS_Reserved1
321
        db 29h                  ; BS_BootSig
322
        dd 0                    ; BS_VolID, filled in format_disk_fat32
323
        db 'NO NAME    '        ; BS_VolLab
324
        db 'FAT32   '           ; BS_FilSysType
325
; same bytes as in fat16bootsector_stub
326
        db 0CDh, 19h, 0EBh, 0FEh ; int 19h, jmp $
327
fat32bootsector_stub_size = $ - fat32bootsector_stub