Subversion Repositories Kolibri OS

Rev

Rev 3232 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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.
  77.         lea     ecx, [256*(1+FAT16_ROOTDIR_SECTORS)+edx+255]
  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
  302.         dw 2                    ; BPB_RsvdSecCnt
  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
  328.