Gestern und heute habe ich an einer Makrosammlung für NASM gebastelt, die es ermöglicht ohne die Zuhilfenahme weiterer Tools ein FAT12 Image zu erstellen. Zu benutzen ist das in etwa so:
%include "fat12.inc"
; Die Standardeinstellung erzeugt ein Image für 1,44MB Disketten. Mehr Tuning gibt es in fat12.inc.
fat_start
; erzeugt eine Datei namens README.TXT
fat_file "readme.txt", "README TXT"
; erzeugt eine Datei namens README.TXT
fat_file "wasauchimmer.txt", "BLUBB TXT"
; erzeugt eine Datei namens MEINFOTO.JPG
fat_file "Urlaub 2006 - Strand.jpg", "MEINFOTOJPG"
fat_end
Das ganze kann man dann einfach mit nasm -o disk.img -f bin diskimage.asm assemblieren.
fat_start beginnt ein Diskettenimage. Es hat einen Optionalen Parameter, der die Anzahl der reservierten Sektoren angibt. Wenn kein Parameter angegeben wird, wird ein Bootloader mit passendem Bootpartitionblock erstellt. Wenn dort ein Parameter angegeben wird, muss der Bootpartitionblock selbst gebastelt werden. Als Vorlage kann dazu das Makro default_boot_sector in fat12.inc dienen.
fat_file fügt eine Datei in das Image ein. Der erste Parameter ist der Pfad zu der Datei, die eingefügt werden soll. Der zweite Parameter gibt den Namen der Datei auf dem Image an. Dieser Name muss ein 8.3-Name sein. Das heisst die ersten 8 Zeichen sind der Teil vor dem Punkt, die letzten 3 Zeichen sind die Erweiterung. Der Name muss immer 11 Zeichen lang sein, und nicht genutzte Bytes müssen mit Leerzeichen gefüllt werden. Hier gibt es keine Überprüfung auf fehlerhafte Eingaben. Mehr zu den Dateinamen gibt es auch in der FAT Spezifikation. Bei den Dateigrößen muss darauf geachtet werden, dass diese Dateien auf die Diskette passen. Es gibt auch hier keine Fehlerüberprüfung.
fat_end muss ganz zum Schluss aufgerufen werden, damit das Diskimage und die einzelnen Sektionen bis zum Ende aufgefüllt werden.
Noch ein Hinweis zum Code: Da eine FAT-Formatierte Diskette/Partition in 3 Teile aufgeteilt ist (root-Directory, FAT, und Datenteil) musste ich einige Tricks anwenden, weil die Anordnung wie die Teile definiert werden, anders ist, als die Ordnung auf der Diskette. So schreibe ich zuerst die Datei in die Datensektion, damit ich die Größe feststellen kann, und erstelle erst dann den Eintrag in der FAT, die auf dem Image allerdings davor liegt. Damit dies gelingt, nutze ich die Multisection-Unterstützung im bin-Format. Das Makro fat_start, sieht vereinfacht so aus:
%macro fat_start 0
section .root_dir
section .fat
section .file_data
%endmacro
Damit lege ich die Reihenfolge der Sektionen fest und nun kann ich im weiteren Code in beliebiger Reihenfolge in die Sektionen schreiben, ohne diese Anordnung wieder zu verlieren. Diese Sammlung von Makros ist eine sehr ungetestete Alpha-Version. Zum Beispiel waren bis vor wenigen Minuten Dateien deren Größe modulo 1024 kleiner als 512 ist nicht unterstützt.
Den Download gibt es unter Auf meiner Todolist stehen unter anderem:
- Viele Zahlen, die noch "hardwired" sind, müssen in Makros verpackt werden.
- Lange Dateinamen
- FAT16
- Verzeichnisse
- Fehlerüberprüfung
Vielleicht gibt es demnächst ja ein Update von mir. Wenn jemand anders damit erfolgreich rumexperimentiert und mit dem den Makros irgendwas spektakuläres anstellt, würde ich mich freuen davon zu hören. Verbesserungsvorschläge und Bugreports sind auch willkommen. Und wenn es einfach nur funktioniert, freue ich mich noch mehr über Kommentare.
Den Code gibt es unter
; Makros für die Erstellung von FAT12-Disketten Images
; mehr: http://superschurke.wordpress.com/?p=5
; Public Domain
; Keine Garantie für irgendwas.
%define DISK_SIZE (1440*1024)
%define BYTES_PER_SECTOR 512
%define SECTORS_PER_CLUSTER 1
%define CLUSTER_SIZE (SECTORS_PER_CLUSTER*BYTES_PER_SECTOR) ; in bytes
%define ROOT_ENT_CNT 224
%define FAT_SIZE 9 ; in sectors
%define NUM_FATS 2
%macro char 1-2
%1:
%if %0==2
resb %2
%else
resb 1
%endif
%endmacro
%macro shortint 1-2
%1:
%if %0==2
resw %2
%else
resw 1
%endif
%endmacro
%macro long 1-2
%1:
%if %0==2
resd %2
%else
resd 1
%endif
%endmacro
struc bpb_s
char jmpBoot, 3
char OEMName, 8
shortint BytsPerSec
char SecPerClus
shortint RsvdSecCnt
char NumFATs
shortint RootEntCnt
shortint TotSec16
char Media
shortint FatSz16
shortint SecPerTrk
shortint NumHeads
long HiddSec
long TotSec32
char DrvNum
char Reserved1
char BootSig
long VolID
char VolLab, 11
char FilSysType, 8
endstruc
struc file_dir_entry_s
char Name, 11
char Attr
char NTRes
char CrtTimeTenth
shortint CrtTime
shortint CrtDate
shortint LstAccDate
shortint FstClusHI
shortint WrtTime
shortint WrtDate
shortint FstClusLO
long FileSize
endstruc
%define ATTR_READ_ONLY 0x01
%define ATTR_HIDDEN 0x02
%define ATTR_SYSTEM 0x04
%define ATTR_VOLUME_ID 0x08
%define ATTR_DIRECTORY 0x10
%define ATTR_ARCHIVE 0x20
%define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
; usage: make_date year, month, day
%macro make_date 3
dw (%3 & 0x1f) | ((%2 & 0xf) << 5) | (((%1 - 1980) & 0x7f) << 9)
%endmacro
; usage: make_time hour, minute, second
%macro make_time 3
dw ((%3 >> 1) & 0x1f) | ((%2 & 0x3f) << 5) | ((%3 & 0x1f) << 11)
%endmacro
%macro default_boot_sector 0
istruc bpb_s
at jmpBoot, jmp short $+bpb_s_size
nop
at OEMName, db "MSDOS5.0"
at BytsPerSec, dw BYTES_PER_SECTOR
at SecPerClus, db SECTORS_PER_CLUSTER
at RsvdSecCnt, dw 1
at NumFATs, db NUM_FATS
at RootEntCnt, dw ROOT_ENT_CNT
at TotSec16, dw DISK_SIZE/BYTES_PER_SECTOR
at Media, db 0xf0
at FatSz16, dw FAT_SIZE
at SecPerTrk, db 18
at NumHeads, dw 2
at HiddSec, dd 0
at TotSec32, dd 0
at DrvNum, db 0
at Reserved1, db 0
at BootSig, db 0x29
at VolID, dd 0x4076939f
at VolLab, db "NO NAME "
at FilSysType, db "FAT12 "
iend
xor ax, ax
mov ss, ax
mov sp, 0x7bfc
mov ds, ax
mov es, ax
cld
mov si, msg_blah
next:
lodsb
cmp al, 0
jz press_any_key
mov ah, 0x0e
int 0x10
jmp next
press_any_key:
xor ax, ax
int 0x16
reboot:
int 0x19
halt:
jmp $
msg_blah db 'This disk is not bootable.', 13, 10, 'Remove this disk and press any key', 13, 10, 0
times 510-($-$$) db 0
dw 0xaa55
%endmacro
%macro _fat_section 1
%if %1==1
section .fat
%else
section .fat%1
%endif
%endmacro
%macro fat_start 0-1
%push fat
%if %0==0
%define %$RESERVED_SECTORS 1
default_boot_sector
%else
%define %$RESERVED_SECTORS %1
%endif
section .fat
fat_start:
%assign i 1
%rep NUM_FATS
_fat_section i
db 0xF0
db 0xFF
db 0xFF
%assign i i+1
%endrep
section .root_dir
root_dir_start:
section .file_data
file_data_start:
%endmacro
%macro fat_end 0
section .fat
fat_used_bytes equ ($-fat_start)
%assign i 1
%rep NUM_FATS
_fat_section i
times FAT_SIZE * BYTES_PER_SECTOR - fat_used_bytes db 0x0
%assign i i+1
%endrep
section .fat
fat_end
fat_size equ fat_end - fat_start
section .root_dir
times ROOT_ENT_CNT * 32 - ($-root_dir_start) db 0
align BYTES_PER_SECTOR
root_dir_end
root_dir_size equ root_dir_end - root_dir_start
section .file_data
file_data_end
file_data_size equ file_data_end - file_data_start
times DISK_SIZE-(%$RESERVED_SECTORS*BYTES_PER_SECTOR+root_dir_size+NUM_FATS*fat_size+file_data_size) db 0
section .text
%pop
%endmacro
%macro fat_file 2
section .file_data
%%start equ ($-$$)
%%first_cluster equ (%%start / CLUSTER_SIZE)
incbin %1
%%end equ ($-$$)
%%size equ (%%end - %%start)
%%size_in_clusters equ ((%%size + CLUSTER_SIZE - 1) / CLUSTER_SIZE)
times (CLUSTER_SIZE*2) - (($-$$) % (CLUSTER_SIZE*2)) db 0 ; *2 simplifies generation of fat
section .root_dir
%%dir_entry:
istruc file_dir_entry_s
at Name, db %2
at Attr, db ATTR_ARCHIVE
at WrtTime, make_time 14, 38, 55
at WrtDate, make_date 2006, 6, 9
at FstClusLO, dw %%first_cluster+2
at FileSize, dw %%size
iend
%assign tsize_in_clusters %%size_in_clusters ; nasm does not support nested %reps with %%-variables
%assign i 1
%rep NUM_FATS
_fat_section i
%assign j %%first_cluster+2+1
%rep (tsize_in_clusters+1)/2
%assign c1 j
%if j > %%size_in_clusters
%assign c2 0xFFF ; end of file
%else
%assign c2 j + 1
%endif
%assign c c1 | (c2 << 12)
dw c & 0xFFFF
db (c >> 16)
%assign j j+2
%endrep
%if c2 != 0xFFF
db 0xFF
db 0x0F
db 0x00
%endif
%assign i i+1
%endrep
%endmacro
Sorry, WordPress versaut die Formatierung gehörig. Es ist halt einfach nicht geeignet für überhaupt irgendwas. Ich muss mir mal zuverlässigen Webspace suchen.
29 Mai 2007 um 13:14 |
Kontaktier mich doch mal bitte wegen dem Webspace, ich hab da nen Vorschlag zu machen…
ICQ 169025797 oder per Mail
21 Jan 2008 um 14:21 |
Cool site! Helpful topic!