Mit NASM FAT12 Images erstellen

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. 8)

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: https://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. 😉

Advertisements

3 Responses to Mit NASM FAT12 Images erstellen

  1. Jan sagt:

    Kontaktier mich doch mal bitte wegen dem Webspace, ich hab da nen Vorschlag zu machen…
    ICQ 169025797 oder per Mail

  2. BMW sagt:

    Cool site! Helpful topic! 🙂

  3. […] in the wedding place u00ab Chicks Who Click Technology in the wedding place u00ab Chicks Who Click Blogged with the Flock […] Click https://twitter.com/moooker1

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: