Are you tired of staring at hex dumps, white papers and manual pages? Want to feel like you truly know how a data type like a file format, or a disk partition LOOKS like. Well I can't help you with the manual pages and white papers, (https://staff.washington.edu/dittrich/misc/fatgen103.pdf, http://www.eit.lth.se/fileadmin/eit/courses/eitn50/Projekt1/FAT12Description.pdf) but here is a great example of implementing a fat12 floppy image in assembly.
;////////////////////////////////////////////////////////////////////////////////
;// THE SCOTCH-WARE LICENSE (Revision 0):
;// <aaronryool@gmail.com> wrote this file. As long as you retain this notice you
;// can do whatever you want with this stuff. If we meet some day, and you think
;// this stuff is worth it, you can buy me a shot of scotch in return
;////////////////////////////////////////////////////////////////////////////////
; This assembles to a floppy disk image
[bits 16]
[org 0x7C00]
;;;;;;;;;;;;;;;;;;;;;;;;
; BIOS Parameter Block
jmp short boot_code
nop
db "MadOSv01" ; OEM identifier
dw 512 ; Bytes per sector
db 1 ; sectors per cluster
dw 1 ; reserved sectors
db 1 ; number of fats
dw 112 ; directory entries
dw 1280 ; logical sectors
db 0xFB ; media descriptor type
dw 1 ; sectors per fat, fat12/fat16 only
dw 18 ; sectors per track
dw 2 ; number of heads / sides on media
dd 0 ; number of hidden sectors
dd 0 ; Large amount of sector on media. This field is set if there are more than 65535 sectors in the volume.
; Extended Boot Record
db 0 ; drive number
db 0 ; reserved / NT flags (maybe use for MadOS, More research needed)
db 0x29 ; signiture, 0x28 or 0x29 for fat12 /fat16
dd 0x1337 ; volume serial number
db "MadOS Disk " ; volume label
db "FAT12 " ; identifier string
; Boot code
boot_code:
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, boot_code_end + (1024 * 4)
lea si, [message]
call print_string
jmp $
print_string:
lodsb
or al, al
jz done
mov ah, 0x0E
int 0x10
jmp print_string
done:
ret
message:
db "MadOS disk not bootable...", 0xd, 0xa
;dw 0xAA55 ; bootable partition signiture, uncomment to make the floppy boot
boot_code_end:
times 450 - (boot_code_end - boot_code) db 0
;;;;;;;;;;;;;;;;;;;;;
; DATA AREA START
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; FAT entries
; an entry is 3 nibbles:
; 000 -> unused
; 0xFF0-0xFF6 -> reserved cluster
; 0xFF7 -> bad cluster
; 0xFF8-0xFFF -> last cluster in file
; *** -> next data cluster
fat1:
db 0xFB, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0x00, 0x00
; 0 1 2 3 4 5 6 7 8 9 10 11 12 13
times 512 - ($ - fat1) db 0
fat2:
times 512 - ($ - fat2) db 0
;;;;;;;;;;;;;;;;;;
; root directory
root:
folder:
db "folder "
db 0x20 | 0x10 ; attributes: a, d
dw 0 ; reserved
dw 0xA496 ; creation time (h,m,s)
dw 0x4793 ; creation date
dw 0x4793 ; access date
dw 0 ; high order bits of first cluster address, 0 on fat12
dw 0xA496 ; write time (h,m,s)
dw 0x4793 ; write date
dw 3 ; low order bits of first cluster address
dd 64 ; file size
file:
db "file "
db 0x20 ; attributes: a
dw 0 ; reserved
dw 0xA496 ; creation time (h,m,s)
dw 0x4793 ; creation date
dw 0x4793 ; access date
dw 0 ; high order bits of first cluster address, 0 on fat12
dw 0xA496 ; write time (h,m,s)
dw 0x4793 ; write date
dw 2 ; low order bits of first cluster address
dd 40 ; file size
; padd out the rest of the root directory
times (512 * 4) - ($ - root) db 0
times 1024 db 0 ; first two data blocks are reserved
; 2 file
file_data:
db "This is a file in the root directory :D", 0xa
; cluster padding
times 512 - ($ - file_data) db 0
; 3 folder
folder_data:
file2:
db "file2 "
db 0x20 ; attributes: a
dw 0 ; reserved
dw 0xA496 ; creation time (h,m,s)
dw 0x4793 ; creation date
dw 0x4793 ; access date
dw 0 ; high order bits of first cluster address, 0 on fat12
dw 0xA496 ; write time (h,m,s)
dw 0x4793 ; write date
dw 4 ; low order bits of first cluster address
dd 34 ; file size
folder2:
db "folder2 "
db 0x20 | 0x10 ; attributes: a, d
dw 0 ; reserved
dw 0xA496 ; creation time (h,m,s)
dw 0x4793 ; creation date
dw 0x4793 ; access date
dw 0 ; high order bits of first cluster address, 0 on fat12
dw 0xA496 ; write time (h,m,s)
dw 0x4793 ; write date
dw 5 ; low order bits of first cluster address
dd 32 ; file size
; cluster padding
times 512 - ($ - file2) db 0
; 4 file2
file2_data:
db "This is a file in a sub directory", 0xa
; cluster padding
times 512 - ($ - file2_data) db 0
; 5 folder2_data
folder2_data:
file3:
db "file3 "
db 0x20 ; attributes: a
dw 0 ; reserved
dw 0xA496 ; creation time (h,m,s)
dw 0x4793 ; creation date
dw 0x4793 ; access date
dw 0 ; high order bits of first cluster address, 0 on fat12
dw 0xA496 ; write time (h,m,s)
dw 0x4793 ; write date
dw 6 ; low order bits of first cluster address
dd 1024 ; file size
; cluster padding
times 512 - ($ - folder2_data) db 0
; 6 file3_data
file3_data:
times 512 - ($ - file3_data) db 'A'
; 7 file3_data2
file3_data2:
times 512 - ($ - file3_data2) db 'B'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; padd out the rest of the floppy
times ((1024 * 1024) + 461373) - ($ - $$) db 0
So from this exploration, we can construct the following header file as a start:
//////////////////////////////////////////////////////////////////////////////// // THE SCOTCH-WARE LICENSE (Revision 0): //wrote this file. As long as you retain this notice you // can do whatever you want with this stuff. If we meet some day, and you think // this stuff is worth it, you can buy me a shot of scotch in return //////////////////////////////////////////////////////////////////////////////// #ifndef __FAT_H__ #define __FAT_H__ #include <stdint.h> #include <machine.h> typedef struct bpb { char jmp_code[3]; char oem[8]; uint16_t bytes_per_sector; uint8_t sectors_per_cluster; uint16_t reserved_sectors; uint8_t fats; uint16_t dir_entries; uint16_t logical_sectors; uint8_t media_type; uint16_t sectors_per_fat; uint16_t sectors_per_track; uint16_t heads; uint32_t hidden_sectors; uint32_t large_sectors; } bpb_t; typedef struct ebr { uint8_t drive; uint8_t rflags; uint8_t signiture; uint32_t serial; char label[11]; char identifier[8]; char boot_code[448]; uint16_t boot_sign; } ebr_t; typedef struct fat12_partition_info { // see fat12.s for an implementation // in assembly for visualization :D bpb_t bpb; ebr_t ebr; char data[]; } fat12_partition_info_t; typedef struct fat_dir_entry { char name[11]; uint8_t attributes; uint16_t reserved; uint16_t creation_time; uint16_t creation_date; uint16_t access_date; uint16_t caddr_high; uint16_t write_time; uint16_t write_date; uint16_t caddr_low; uint32_t size; } fat_dir_entry_t; const uint8_t fat12_format_stub[122] = { 0xEB, 0x3C, 0x90, 0x4D, 0x61, 0x64, 0x4F, 0x53, 0x76, 0x30, 0x31, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x37, 0x13, 0x00, 0x00, 0x4D, 0x61, 0x64, 0x4F, 0x53, 0x20, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x31, 0xC0, 0x8E, 0xD8, 0x8E, 0xC0, 0x8E, 0xD0, 0xBC, 0x7A, 0x8C, 0x8D, 0x36, 0x5E, 0x7C, 0xE8, 0x02, 0x00, 0xEB, 0xFE, 0xAC, 0x08, 0xC0, 0x74, 0x06, 0xB4, 0x0E, 0xCD, 0x10, 0xEB, 0xF5, 0xC3, 0x4D, 0x61, 0x64, 0x4F, 0x53, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2E, 0x2E, 0x2E, 0x0D, 0x0A }; ///////////////////////////////////////////// // FAT12 entries // ///////////////////////////////////////////// // an entry is 3 nibbles: // // 000 -> unused // // 0xFF0-0xFF6 -> reserved cluster // // 0xFF7 -> bad cluster // // 0xFF8-0xFFF -> last cluster in file // // *** -> next data cluster // ///////////////////////////////////////////// typedef char fat12_t[]; #define GET_FAT12_ENTRY(n, fat)\ (n % 2 == 0 ? fat[((3 * n) / 2)] | (fat[1 + (3 * n) / 2] & 0x0F) << 8 : \ (fat[(3 * n) / 2] & 0xF0) >> 4 | fat[1 + (3 * n) / 2] << 4) #endif








