| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# boot16.htm

This program demonstrates how EuroAssembler format BOOT can be utilized to compile file boot16.sec which can be used as a floppy disk boot sector.

Boot sector is a 512 bytes long image recorded in the first sector of disk volume. When personal computer starts, its BIOS will read boot sector and store its contents at address 0x07C00 in memory. This sample source file compiles boot sector of floppy diskette 3.5" formated by MS-DOS ver.6.

Code in this sector is executed in real CPU mode, no DOS services are available yet. Since the binary format cannot contain any metainformation (entry point, relocations etc), all absolute addresses in its code must be assembled to fixed values.

BIOS loads the sector at agreed linear address 0x07C00 and then it will set register DL to the drive number (DL=0 for floppy drive A:), CS=0x0000 and IP=0x7C00 (some BIOS vendors may prefer CS=0x07C0 and IP=0x0000). Other registers are undefined. This transfers control to the first boot-sector instruction `JMPS Start:` which skips data structures expected near the beginning of the sector.

EuroAssembler pseudoinstruction `PROGRAM FORMAT=BOOT` implies properties of the output file:

- Image is assembled and linked at fixed offset 0x7C00
- Output file size is padded to 512 bytes
- The last two bytes will contain signature 0x55,0xAA
- Default extension of output file is .sec

> I wanted the sample code to be binary-identical with real boot sector of floppy disk formated by MS-DOS 6. Compiler used by Microsoft prefers machine instructions with alternative (long) opcode, hence the instruction modifier `CODE=LONG` is sometimes used, althoug it is not necessary.

Format
  Special binary file for 16bit real CPU mode, executable by BIOS.
Platform
  Personal Computer with x86 processor
Documented
  [BootSec]
Manual
  BOOT
See also
  binboot.htm
Build
  euroasm boot16.htm
Run
  Boot sector cannot be run directly. Use 3rd-party utility which is able to store boot16.sec to the first disk sector, for instance `dd.exe if=boot16.sec of=\\.\A:` and then boot from the disk A:.

           EUROASM AutoAlign=Off, AutoSegment=Off,DumpAll=Yes,DumpWidth=29
    boot16 PROGRAM Format=BOOT,ListMap=On, ListGlobals=Off
            INCLUDE bioss.htm                        ; Macrolibrary bioss.htm defines layout of structures used by the boot code.
    %OEM_ID       %SET "EUROASM",0                   ; This 8 bytes identifies OS which created the boot sector.
    %VolumeLabel  %SET "EUROASMBOOT"                 ; Diskette label: arbitrary 11 characters, space-padded.
    %VolumeSerial %SET 0x11223344                    ; Serial number: random DWORD generated at disk format-time.
    ;;
    [BOOT] SEGMENT ALIGN=BYTE,PURPOSE=CODE+DATA      ; It will be linked at fixed address 0x7C00.
           JMP Start:                                ; Skip OEM_ID and Bpb allocated statically in the beginning of boot-sector.
           NOP
           DB %OEM_ID                                ; Fixed address of OEM_ID is 0x7C03.
    Bpb:   DS BPB_FAT16, .VolumeLabel=%VolumeLabel, .VolumeSerialNumber=%VolumeSerial ; Fixed address of Bpb at 0x7C0B.
    Dpt:   DS DPT                                    ; Diskette Parameter Table (11 bytes) will be copied here at 0x7C3E, overwriting the Start: code.
    Lba:   DS LBA                                    ; Area used in conversion of disk geometry CHS/LBA, allocated at 0x7C49.
    $      EQU Dpt:                                  ; Assemble the following Start code back at 0x7C3E, overwriting Dpt and Lba.
    Start:                                           ; Entry point jumps to this fixed label Start: at address 0x7C3E, where the boot code actually starts.
           CLI                                       ; Disable HW interrupts, as the stack is not settled yet.
           XOR AX,AX,CODE=LONG
           MOV SS,AX
           MOV SP,0x7C00                             ; Set the stack pointer to an address just below the boot sector.
           PUSH SS
           POP ES                                    ; Let ES=SS=0.
           MOV BX,0x0078                             ; Offset of pointer to default DPT prepared by BIOS (Interrupt 0x1E vector).
           LDS SI,[SS:BX]                            ; Let DS:SI point to DPT in BIOS memory.
           PUSH DS,SI,SS,BX
             MOV DI,Dpt:                             ; Let ES:DI point to Dpt in boot-sector memory.
             MOV CX,SIZE# DPT:                       ; 11.
             CLD
             REP MOVSB                               ; Copy DPT from BIOS memory to the Dpt at 0x7C3E.
             PUSH ES
             POP DS                                  ; DS=ES=SS=0.
             MOVB [DI-SIZE#DPT+DPT.bHdSettle],15
             MOV CX,[Bpb.SectorsPerTrack]
             MOV [DI-SIZE#DPT+DPT.bLastTrack],CL
             MOV [BX+2],AX                           ; PARA# Dpt=0.
             MOV [BX+0],Dpt, DATA=WORD               ; OFFSET# Dpt=0x7C3E updates interrupt 0x1E vector to point at Dpt.
             STI                                     ; Recalibrate floppy drive number DL=0 (disk A:).
             INT 13h                                 ; AH=0 Reset disk system.
             JC Error:
             XOR AX,AX
             CMP [Bpb.SmallSectors],AX
             JZ Large:
             MOV CX,[Bpb.SmallSectors]               ; 2880 sectors = 1.44 MB.
             MOV [Bpb.LargeSectors],CX               ; Use .LargeSectors rather than .SmallSectors.
    Large:   MOV AL,[Bpb.NumberOfFats]               ; 2.
             MULW [Bpb.SectorsPerFat]                ; 9.
             ADD AX,[Bpb.HiddenSectors+0]            ; 0
             ADC DX,[Bpb.HiddenSectors+2]            ; 0.
             ADD AX,[Bpb.ReservedSectors]            ; 1.
             ADC DX,0                                ; DX:AX is now LBAroot of root-directory (19).
             MOV [Lba.root+0],AX
             MOV [Lba.root+2],DX
             MOV [Lba.data+0],AX
             MOV [Lba.data+2],DX
             MOV AX,SIZE# DIR_ENTRY                  ; 32.
             MULW [Bpb.RootEntries]                  ; 224.
             MOV BX,[Bpb.BytesPerSector]             ; 512.
             ADD AX,BX,CODE=LONG
             DEC AX
             DIV BX                                  ; Divide root-dir size by sector size (512).
             ADD [Lba.data+0],AX                     ; +14.
             ADC [Lba.data+2],0,DATA=WORD
             MOV BX,0x0500                           ; Memory address where to read disk sectors (DTA).
             MOV DX,[Lba.root+2]
             MOV AX,[Lba.root+0]
             CALL LBAtranslate:
             JB  Error:
             MOV AL,1
             CALL ReadSec:                           ; Read the directory entry.
             JB Error:
             MOV DI,BX,CODE=LONG
             MOV CX,8+3                              ; Filename size.
             MOV SI,IO.SYS:
             REPE CMPSB                              ; The first file in dir must be IO.SYS.
             JNE Error:
             LEA DI,[BX+SIZE# DIR_ENTRY]             ; The next dir entry should be MSDOS.SYS.
             MOV CX,8+3                              ; Filename size. SI points to MSDOS.SYS.
             REPE CMPSB                              ; Check if MSDOS.SYS is at expected position on disk.
             JE Loader:                              ; Load the contents of IO.SYS at address 0x00700 and go to its entry 0x0070:0.
    Error:   MOV SI,Message:
             CALL Display:
             XOR AX,AX
             INT 16h                                 ; Wait for any key pressed.
           POP SI,DS,[SI+0],[SI+2]
           INT 19h                                   ; Invoke the bootstrap loader. Try to boot again from a better disk.
    Error2:POP AX,AX,AX
           JMP Error:

    Loader: ; IO.SYS file loader reads the first three sectors of IO.SYS to the address 0x00700.
            MOV AX,[BX+DIR_ENTRY.wClstrNo]           ; BX=0x500 points to the directory entry of IO.SYS.
            DEC AX,AX
            MOV BL,[Bpb.SectorsPerCluster]           ; 1.
            XOR BH,BH
            MUL BX
            ADD AX,[Lba.data+0]
            ADC DX,[Lba.data+2]
            MOV BX,0x0700                            ; Memory address where to read.
            MOV CX,3                                 ; Only read 3 sectors. IO.SYS manages the rest.
    NextSec:PUSH AX,DX,CX
              CALL LBAtranslate:                     ; Convert the cluster number in DX:AX to C/H/S geometry.
              JC Error2:
              MOV AL,1
              CALL ReadSec:                          ; Read AL sectors to address BX.
            POP CX,DX,AX
            JC Error:
            ADD AX,1                                 ; Prepare to read the next cluster.
            ADC DX,0
            ADD BX,[Bpb.BytesPerSector]
            LOOP NextSec:
            MOV CH,[Bpb.MediaDescriptor]
            MOV DL,[Bpb.PhysicalDriveNumber]
            MOV BX,[Lba.data+0]
            MOV AX,[Lba.data+2]
            JMP 0x0070:0                             ; Start the code in IO.SYS.

    Display:PROC                                     ; Subprocedure which displays a zero-terminated string DS:SI.
            LODSB
            OR AL,AL,CODE=LONG
            JZ Return:                               ; Return when the string is completely displayed.
            MOV AH,0x0E
            MOV BX,0x0007
            INT 10h                                  ; Output character AL on screen, advance cursor.
            JMP Display:

    LBAtranslate:PROC                                ; Subprocedure which translates LBA in DX:AX (cluster number, 19 for root-dir, 33 for data) to the disk geometry.
            CMP DX,[Bpb.SectorsPerTrack]             ; 18.
            JNB RetCF:
            DIVW [Bpb.SectorsPerTrack]               ; AX=track number, DX=sector number in the track.
            INC DL
            MOV [Lba.track],DL
            XOR DX,DX,CODE=LONG
            DIVW [Bpb.NumberOfHeads]                 ; 2.
            MOV [Bpb.Reserved],DL                    ; This BPB member is misused for the  head number.
            MOV [Lba.cylinder],AX
            CLC
            RET
    RetCF:  STC                                      ; Signalize return with error.
    Return: RET
            ENDPROC LBAtranslate:
            ENDPROC Display:

    ReadSec:PROC                                     ; Subprocedure which reads AL sectors to memory at ES:BX from translated disk address.
            MOV AH,2
            MOV DX,[Lba.cylinder]
            MOV CL,6
            SHL DH,CL
            OR DH,[Lba.track]
            MOV CX,DX,CODE=LONG
            XCHG CH,CL
            MOV DL,[Bpb.PhysicalDriveNumber]
            MOV DH,[Bpb.Reserved]                    ; Head number.
            INT 0x13                                 ; Read AL sectors starting from CL to ES:BX by BIOS service.
            RET
            ENDPROC ReadSec:

    Message:DB 13,10,"Non-System disk or disk error"
            DB 13,10,"Replace and press any key when ready"
            DB 13,10,0
    IO.SYS: DB "IO      SYS"                         ; File names of MS DOS boot files.
            DB "MSDOS   SYS"
          ENDPROGRAM boot16                          ; Program format BOOT will append signature 0x55,0xAA at the end of sector.

▲Back to the top▲