7f3e618a3a
git-svn-id: svn://kolibrios.org@3500 a494cfbc-eb01-0410-851d-a64ba20cac60
328 lines
11 KiB
PHP
328 lines
11 KiB
PHP
; FAT-specific code for tmpdisk.asm.
|
|
; Formats a disk to FAT16 or FAT32, depending on size.
|
|
; Note: formatting is adjusted for memory-based disks. Although the resulting
|
|
; image is a valid FAT32 volume, it has no "spare" sectors, e.g. second copy
|
|
; of FAT or place for second sector of MS FAT32 bootloader.
|
|
|
|
; Some constants
|
|
FAT16_ROOTDIR_SECTORS = 16 ; can be changed, but why not?
|
|
; FAT16:
|
|
; 1 bootsector,
|
|
; min 0xFF5 sectors for data,
|
|
; min (0xFF5*2/512) = 16 sectors per FAT, we use only one copy,
|
|
; FAT16_ROOTDIR_SECTORS for root directory
|
|
MIN_FAT16_SIZE = 1 + 16 + FAT16_ROOTDIR_SECTORS + 0xFF5
|
|
; FAT32:
|
|
; 1 bootsector,
|
|
; 1 sector for fsinfo,
|
|
; min 0xFFF5 sectors for data,
|
|
; min (0xFFF5*4/512) = 512 sectors per FAT, we use only one copy
|
|
MIN_FAT32_SIZE = 1 + 1 + 512 + 0xFFF5
|
|
MAX_SIZE = 1 shl (30 - 9) ; 1G in 512-byte sectors
|
|
|
|
; Initializes FATxx structures on the disk.
|
|
; Called with edi = pointer to disk data, esi = size of disk.
|
|
proc format_disk
|
|
; Determine FAT type and jump to the corresponding handler.
|
|
cmp esi, MIN_FAT32_SIZE
|
|
jae format_disk_fat32
|
|
; Fall through to format_disk_fat16.
|
|
endp
|
|
|
|
; Structure of FAT16 bootsector. Field names are from MS spec.
|
|
struc FAT16BOOT
|
|
{
|
|
.BS_jmpBoot rb 3
|
|
.BS_OEMName rb 8
|
|
.BPB_BytsPerSec dw ?
|
|
.BPB_SecsPerClus db ?
|
|
.BPB_RsvdSecCnt dw ?
|
|
.BPB_NumFATs db ?
|
|
.BPB_RootEntCnt dw ?
|
|
.BPB_TotSec16 dw ?
|
|
.BPB_Media db ?
|
|
.BPB_FATSz16 dw ?
|
|
.BPB_SecPerTrk dw ?
|
|
.BPB_NumHeads dw ?
|
|
.BPB_HiddSec dd ?
|
|
.BPB_TotSec32 dd ?
|
|
.BS_DrvNum db ?
|
|
.BS_Reserved1 db ?
|
|
.BS_BootSig db ?
|
|
.BS_VolID dd ?
|
|
.BS_VolLab rb 11
|
|
.BS_FilSysType rb 8
|
|
}
|
|
virtual at 0
|
|
FAT16BOOT FAT16BOOT
|
|
end virtual
|
|
|
|
; Initializes FAT16 structures on the disk.
|
|
; Called with edi = pointer to disk data, esi = size of disk.
|
|
format_disk_fat16:
|
|
; 1. Calculate number of clusters.
|
|
; 1a. There are fixed-sized areas and there are data+FAT;
|
|
; every cluster uses 512 bytes in data area and 2 bytes in FAT area.
|
|
lea eax, [esi-1-FAT16_ROOTDIR_SECTORS]
|
|
; two following lines are equivalent to edx = floor(eax*512/514)
|
|
mov ecx, 0xFF00FF01
|
|
mul ecx ; edx = number of clusters
|
|
; 1b. Force the number be less than 0xfff5.
|
|
mov eax, 0xFFF4
|
|
cmp edx, eax
|
|
jb @f
|
|
mov edx, eax
|
|
@@:
|
|
; 2. Zero all system areas on the disk.
|
|
lea ecx, [256*(1+FAT16_ROOTDIR_SECTORS)+edx+255]
|
|
and ecx, not 255
|
|
shr ecx, 1
|
|
xor eax, eax
|
|
push edi
|
|
rep stosd
|
|
pop edi
|
|
; 3. Generate the bootsector.
|
|
; 3a. Copy static stub.
|
|
push esi edi
|
|
mov esi, fat16bootsector_stub
|
|
mov ecx, fat16bootsector_stub_size
|
|
rep movsb
|
|
pop edi esi
|
|
mov word [edi+510], 0xAA55
|
|
; 3b. Set fields which depend on size.
|
|
cmp esi, 0x10000
|
|
jae .size_is_32bit
|
|
mov [edi+FAT16BOOT.BPB_TotSec16], si
|
|
jmp .size_written
|
|
.size_is_32bit:
|
|
mov [edi+FAT16BOOT.BPB_TotSec32], esi
|
|
.size_written:
|
|
lea eax, [edx+255]
|
|
shr eax, 8
|
|
mov [edi+FAT16BOOT.BPB_FATSz16], ax
|
|
; 3c. Generate volume ID.
|
|
call generate_volume_id
|
|
mov [edi+FAT16BOOT.BS_VolID], eax
|
|
; 4. Initialize FAT.
|
|
mov dword [edi+512], 0xFFFFFFF8
|
|
; 5. Return.
|
|
ret
|
|
|
|
; Structure of FAT32 bootsector. Field names are from MS spec.
|
|
struc FAT32BOOT
|
|
{
|
|
.BS_jmpBoot rb 3
|
|
.BS_OEMName rb 8
|
|
.BPB_BytsPerSec dw ?
|
|
.BPB_SecsPerClus db ?
|
|
.BPB_RsvdSecCnt dw ?
|
|
.BPB_NumFATs db ?
|
|
.BPB_RootEntCnt dw ?
|
|
.BPB_TotSec16 dw ?
|
|
.BPB_Media db ?
|
|
.BPB_FATSz16 dw ?
|
|
.BPB_SecPerTrk dw ?
|
|
.BPB_NumHeads dw ?
|
|
.BPB_HiddSec dd ?
|
|
.BPB_TotSec32 dd ?
|
|
.BPB_FATSz32 dd ?
|
|
.BPB_ExtFlags dw ?
|
|
.BPB_FSVer dw ?
|
|
.BPB_RootClus dd ?
|
|
.BPB_FSInfo dw ?
|
|
.BPB_BkBootSec dw ?
|
|
.BPB_Reserved rb 12
|
|
.BS_DrvNum db ?
|
|
.BS_Reserved1 db ?
|
|
.BS_BootSig db ?
|
|
.BS_VolID dd ?
|
|
.BS_VolLab rb 11
|
|
.BS_FilSysType rb 8
|
|
}
|
|
virtual at 0
|
|
FAT32BOOT FAT32BOOT
|
|
end virtual
|
|
|
|
; Initializes FAT32 structures on the disk.
|
|
; Called with edi = pointer to disk data, esi = size of disk.
|
|
format_disk_fat32:
|
|
; 1. Calculate number of clusters.
|
|
; 1a. There is fixed-sized area and there are data+FAT;
|
|
; every cluster uses 512 bytes in data area and 4 bytes in FAT area.
|
|
lea eax, [esi-1-1]
|
|
; two following lines are equivalent to edx=floor(eax*512/516) if eax<10000000h
|
|
mov ecx, 0xFE03F810
|
|
mul ecx ; edx = number of clusters
|
|
; 2. Zero all system areas on the disk and first cluster of data,
|
|
; used for root directory.
|
|
lea ecx, [128*(1+1+1)+edx+127]
|
|
and ecx, not 127
|
|
xor eax, eax
|
|
push edi
|
|
rep stosd
|
|
pop edi
|
|
; 3. Generate the bootsector.
|
|
; 3a. Copy static stub.
|
|
push esi edi
|
|
mov esi, fat32bootsector_stub
|
|
mov ecx, fat32bootsector_stub_size
|
|
rep movsb
|
|
pop edi esi
|
|
mov word [edi+510], 0xAA55
|
|
; 3b. Set fields which depend on size.
|
|
mov [edi+FAT32BOOT.BPB_TotSec32], esi
|
|
lea eax, [edx+127]
|
|
shr eax, 7
|
|
mov [edi+FAT32BOOT.BPB_FATSz32], eax
|
|
; 3c. Generate volume ID.
|
|
call generate_volume_id
|
|
mov [edi+FAT32BOOT.BS_VolID], eax
|
|
; 4. Initialize fsinfo sector.
|
|
mov dword [edi+512], 'RRaA'
|
|
mov dword [edi+512+484], 'rrAa'
|
|
dec edx ; one cluster is occupied by root dir
|
|
mov dword [edi+512+488], edx ; free count
|
|
mov byte [edi+512+492], 3 ; first free cluster
|
|
mov word [edi+512+510], 0xAA55
|
|
; 5. Initialize FAT.
|
|
mov dword [edi+512*2], 0x0FFFFFF8
|
|
mov dword [edi+512*2+4], 0x0FFFFFFF
|
|
mov dword [edi+512*2+8], 0x0FFFFFFF
|
|
; 6. Return.
|
|
ret
|
|
|
|
; Generate volume serial number, which should try to be unique for each volume.
|
|
; Use CMOS date+time, copy-pasted from fat32.inc.
|
|
generate_volume_id:
|
|
call get_time_for_file
|
|
mov cx, ax
|
|
call get_date_for_file
|
|
shl eax, 16
|
|
mov ax, cx
|
|
ret
|
|
|
|
; Three following procedures are copy-pasted from fat32.inc.
|
|
bcd2bin:
|
|
;----------------------------------
|
|
; input : AL=BCD number (eg. 0x11)
|
|
; output : AH=0
|
|
; AL=decimal number (eg. 11)
|
|
;----------------------------------
|
|
xor ah, ah
|
|
shl ax, 4
|
|
shr al, 4
|
|
aad
|
|
ret
|
|
|
|
get_date_for_file:
|
|
;-----------------------------------------------------
|
|
; Get date from CMOS and pack day,month,year in AX
|
|
; DATE bits 0..4 : day of month 0..31
|
|
; 5..8 : month of year 1..12
|
|
; 9..15 : count of years from 1980
|
|
;-----------------------------------------------------
|
|
mov al, 0x7 ;day
|
|
out 0x70, al
|
|
in al, 0x71
|
|
call bcd2bin
|
|
ror eax, 5
|
|
|
|
mov al, 0x8 ;month
|
|
out 0x70, al
|
|
in al, 0x71
|
|
call bcd2bin
|
|
ror eax, 4
|
|
|
|
mov al, 0x9 ;year
|
|
out 0x70, al
|
|
in al, 0x71
|
|
call bcd2bin
|
|
add ax, 20 ;because CMOS return only the two last
|
|
;digit (eg. 2000 -> 00 , 2001 -> 01) and we
|
|
rol eax, 9 ;need the difference with 1980 (eg. 2001-1980)
|
|
ret
|
|
|
|
|
|
get_time_for_file:
|
|
;-----------------------------------------------------
|
|
; Get time from CMOS and pack hour,minute,second in AX
|
|
; TIME bits 0..4 : second (the low bit is lost)
|
|
; 5..10 : minute 0..59
|
|
; 11..15 : hour 0..23
|
|
;-----------------------------------------------------
|
|
mov al, 0x0 ;second
|
|
out 0x70, al
|
|
in al, 0x71
|
|
call bcd2bin
|
|
ror eax, 6
|
|
|
|
mov al, 0x2 ;minute
|
|
out 0x70, al
|
|
in al, 0x71
|
|
call bcd2bin
|
|
ror eax, 6
|
|
|
|
mov al, 0x4 ;hour
|
|
out 0x70, al
|
|
in al, 0x71
|
|
call bcd2bin
|
|
rol eax, 11
|
|
ret
|
|
|
|
; some data
|
|
fat16bootsector_stub:
|
|
db 0EBh, 3Ch, 90h ; BS_jmpBoot
|
|
db 'KOLIBRI ' ; BS_OEMName
|
|
dw 512 ; BPB_BytsPerSec
|
|
db 1 ; BPB_SecsPerClus
|
|
dw 1 ; BPB_RsvdSecCnt
|
|
db 1 ; BPB_NumFATs
|
|
dw FAT16_ROOTDIR_SECTORS*16 ; BPB_RootEntCnt
|
|
dw 0 ; BPB_TotSec16, filled in format_disk_fat16
|
|
db 0F8h ; BPB_Media
|
|
dw 0 ; BPB_FATSz16, filled in format_disk_fat16
|
|
dw 32 ; BPB_SecPerTrk
|
|
dw 128 ; BPB_NumHeads
|
|
dd 0 ; BPB_HiddSec
|
|
dd 0 ; BPB_TotSec32, filled in format_disk_fat16
|
|
db 80h ; BS_DrvNum
|
|
db 0 ; BS_Reserved1
|
|
db 29h ; BS_BootSig
|
|
dd 0 ; BS_VolID, filled in format_disk_fat16
|
|
db 'NO NAME ' ; BS_VolLab
|
|
db 'FAT16 ' ; BS_FilSysType
|
|
; just in case add some meaningful bytes if someone tries to boot
|
|
db 0CDh, 19h, 0EBh, 0FEh ; int 19h, jmp $
|
|
fat16bootsector_stub_size = $ - fat16bootsector_stub
|
|
fat32bootsector_stub:
|
|
db 0EBh, 58h, 90h ; BS_jmpBoot
|
|
db 'KOLIBRI ' ; BS_OEMName
|
|
dw 512 ; BPB_BytsPerSec
|
|
db 1 ; BPB_SecsPerClus
|
|
dw 2 ; BPB_RsvdSecCnt
|
|
db 1 ; BPB_NumFATs
|
|
dw 0 ; BPB_RootEntCnt
|
|
dw 0 ; BPB_TotSec16
|
|
db 0F8h ; BPB_Media
|
|
dw 0 ; BPB_FATSz16
|
|
dw 32 ; BPB_SecPerTrk
|
|
dw 128 ; BPB_NumHeads
|
|
dd 0 ; BPB_HiddSec
|
|
dd 0 ; BPB_TotSec32, filled in format_disk_fat32
|
|
dd 0 ; BPB_FATSz32, filled in format_disk_fat32
|
|
dw 0 ; BPB_ExtFlags
|
|
dw 0 ; BPB_FSVer
|
|
dd 2 ; BPB_RootClus
|
|
dw 1 ; BPB_FSInfo
|
|
dw 0 ; BPB_BkBootSec
|
|
rb 12 ; BPB_Reserved
|
|
db 80h ; BS_DrvNum
|
|
db 0 ; BS_Reserved1
|
|
db 29h ; BS_BootSig
|
|
dd 0 ; BS_VolID, filled in format_disk_fat32
|
|
db 'NO NAME ' ; BS_VolLab
|
|
db 'FAT32 ' ; BS_FilSysType
|
|
; same bytes as in fat16bootsector_stub
|
|
db 0CDh, 19h, 0EBh, 0FEh ; int 19h, jmp $
|
|
fat32bootsector_stub_size = $ - fat32bootsector_stub
|