Boot: Hello, World! | Index | Boot: Root Calculations

Write Your Own OS from Scratch - Chapter 1. Boot

Boot: Load Sector

After our exciting "Hello, World!" acheivement it is time to dig in and read some sectors. We are going to load sector 2, the sector that follows the boot sector into memory and jump to it.

The first thing we need to add is the standard FAT header. This will be used to calculate locations to load in the future. Right now we just need a couple peices of data out of it for reading a sector.

    jmp     short start                                 ; Jump to boot sector start
    nop                                                 ; place holder

oemname:        db      "DEMO OS "                      ; Operating system name
bytespersec:    dw      512                             ; Bytes per sector
secperclust:    db      1                               ; Sectors per cluster
ressectors:     dw      1                               ; Reserved Sectors
fats:           db      2                               ; Number of FATs on disk
rootdirents:    dw      224                             ; Number of directory entries
sectors:        dw      2880                            ; Sectors per disk
media:          db      0F0h                            ; Always F0 hex for floppy
fatsecs:        dw      9                               ; Sectors per FAT
secpertrack:    dw      18                              ; Sectors per track
heads:          dw      2                               ; Number of heads
hiddensecs:     dd      0                               ; Hidden sectors
hugesectors:    dd      0                               ; Huge sectors
drivenumber:    db      000h                            ; Drive number 000h for floppy
currenthead:    db      0                               ; Reserved we are using for disk read
bootsignature:  db      029h                            ; Boot signature
volumeid:       dd      02394C726h                      ; Serial Number
vlumelabel:     db      "DEMO OS DSK"                   ; Disk label
filesystype:    db      "FAT12   "                      ; File system
		

Immediately following that we add a couple extra variables for the track and sector data to pass to our subroutine.

track:          dw      0                               ; Track for disk read
sector:         db      0                               ; Sector for disk read
		

Near our strout subroutine we will add our readsec subroutine. this uses a BIOS call to read a sector from the disk.

;-------------------------------------------------------
; Read Sector
; Input:
;    bsTrack = Track
;    bsSector = Sector
;    bsHead = Head
;    ES:BX = Location to load sector at
; Output:
;       AX, BX, CX, DX are destroyed
;-------------------------------------------------------
readsec:
    mov     dx, [track]	                                ; Get the track
    mov     cl, 006h                                    ; Rotate the bits 8 and 9 into position
    shl     dh, cl
    or      dh, [sector]                                ; Get the sector don't changing high bits
    mov     cx, dx                                      ; Place in the correct register
    xchg    ch, cl                                      ; Swap bytes to complete the process
    mov     dl, [drivenumber]                           ; Drive number
    mov     dh, [currenthead]                           ; Current Head
    mov     ax, 00201h                                  ; BIOS Disk Read 1 Sector
    int     013h
    ret                                                 ; Return from subroutine
		

Next we should reset the disk system. It may work without this line but we want to be sure.

    int     013h                                        ; AH = 0, Reset disk system 
		

We then add the code to read the sector. We read the sector in at 00000h:00700h and jump to 00070h:00000h which may seem strage but they are the same address because segments overlap offsets.

    mov     bx, 00700h                                  ; Load second sector at 00000h:00700h
    mov     [track], ax                                 ; Zero track
    mov     [currenthead], al                           ; Zero currenthead
    mov     al, 2                                       ; Sector 2
    mov     [sector], al
    call    readsec                                     ; Read Sector
    jc      loaderror                                   ; Error on read fail

    jmp     00070h:00000h                               ; Jump to code from sector 2
		

Now place a label before our print message code

loaderror:
		

Finally change the message we print to Error Loading.

message:        db      00Dh, 00Ah, "Hello, World!"     ; Message to be printed
                db      00Dh, 00Ah, 000h
		

to

message:        db      00Dh, 00Ah, "Error Loading"     ; Message to be printed
                db      00Dh, 00Ah, 000h
		

boot.asm

;=======================================================
; Boot Sector - boot.asm
; -----------------------------------------------------
; Written in NASM
; Written by Marcus Kelly
;=======================================================

    org     07C00h                                      ; Assemble code for this offset

    jmp     short start                                 ; Jump to boot sector start
    nop                                                 ; place holder

oemname:        db      "DEMO OS "                      ; Operating system name
bytespersec:    dw      512                             ; Bytes per sector
secperclust:    db      1                               ; Sectors per cluster
ressectors:     dw      1                               ; Reserved Sectors
fats:           db      2                               ; Number of FATs on disk
rootdirents:    dw      224                             ; Number of directory entries
sectors:        dw      2880                            ; Sectors per disk
media:          db      0F0h                            ; Always F0 hex for floppy
fatsecs:        dw      9                               ; Sectors per FAT
secpertrack:    dw      18                              ; Sectors per track
heads:          dw      2                               ; Number of heads
hiddensecs:     dd      0                               ; Hidden sectors
hugesectors:    dd      0                               ; Huge sectors
drivenumber:    db      000h                            ; Drive number 000h for floppy
currenthead:    db      0                               ; Reserved we are using for disk read
bootsignature:  db      029h                            ; Boot signature
volumeid:       dd      02394C726h                      ; Serial Number
vlumelabel:     db      "DEMO OS DSK"                   ; Disk label
filesystype:    db      "FAT12   "                      ; File system
track:          dw      0                               ; Track for disk read
sector:         db      0                               ; Sector for disk read

start:
    cli                                                 ; Turn off interrupts
    cld							; Make sure we are going forward
    xor     ax, ax                                      ; Zero the ax register
    mov     ds, ax                                      ; Make sure data segment is zero
    mov     es, ax                                      ; Make sure extra segment is zero
    mov     ss, ax                                      ; Make sure stack segment is zero
    mov     sp, 07C00h                                  ; Place stack ptr before boot sector
    sti                                                 ; Turn on interrupts

    int     013h                                        ; AH = 0, Reset disk system

    mov     bx, 00700h                                  ; Load second sector at 00000h:00700h
    mov     [track], ax                                 ; Zero track
    mov     [currenthead], al                           ; Zero currenthead
    mov     al, 2                                       ; Sector 2
    mov     [sector], al
    call    readsec                                     ; Read Sector
    jc      loaderror                                   ; Error on read fail

    jmp     00070h:00000h                               ; Jump to code from sector 2


loaderror:
    mov     si, message                                 ; si is set to offset Message
    call    strout                                      ; call our string output routine

die:
    jmp     die                                         ; This is our die loop so the
                                                        ;  computer doesn't run random
                                                        ;  code

;-------------------------------------------------------
; String Output
; Input:
;    DS:SI = Message offset
; Output:
;       AX, BX, SI are destroyed
;-------------------------------------------------------
strout:
    lodsb                                               ; Get character from string
    or      al, al                                      ; Check if our character is zero
    jz      stroutdone                                  ; if it is zero we have finished
    mov     ah, 0Eh                                     ; BIOS print call
    mov     bx, 00007h                                  ; Character attribute
    int     010h                                        ; Call the video BIOS
    jmp     strout                                      ; Get next character
stroutdone:
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Read Sector
; Input:
;    bsTrack = Track
;    bsSector = Sector
;    bsHead = Head
;    ES:BX = Location to load sector at
; Output:
;       AX, BX, CX, DX are destroyed
;-------------------------------------------------------
readsec:
    mov     dx, [track]	                                ; Get the track
    mov     cl, 006h                                    ; Rotate the bits 8 and 9 into position
    shl     dh, cl
    or      dh, [sector]                                ; Get the sector don't changing high bits
    mov     cx, dx                                      ; Place in the correct register
    xchg    ch, cl                                      ; Swap bytes to complete the process
    mov     dl, [drivenumber]                           ; Drive number
    mov     dh, [currenthead]                           ; Current Head
    mov     ax, 00201h                                  ; BIOS Disk Read 1 Sector
    int     013h
    ret                                                 ; Return from subroutine

;-------------------------------------------------------
; Data Area
;-------------------------------------------------------

message:        db      00Dh, 00Ah, "Error Loading"     ; Message to be printed
                db      00Dh, 00Ah, 000h

                times   510-($-$$) db 0                 ; inserts zeros from this address
                                                        ;   to address 510
                dw      0AA55h                          ; Boot signature at 510 / 511
		

Something to load

Now we will take another copy of the "Hello, World!" boot code and save it as demoos2.asm. We will modify the origin location and the string.

    org     07C00h                                      ; Assemble code for this offset
		

gets changed to

    org     00000h                                      ; Assemble code for this offset
		

We add the following lines to make sure are data segment is correct

    push    cs                                          ; Make sure data segment = code segment
    pop     ds
		

And we change

message:        db      00Dh, 00Ah, "Hello, World!"     ; Message to be printed
                db      00Dh, 00Ah, 000h
		

to

message:        db      00Dh, 00Ah, "Sector 2"          ; Message to be printed
                db      00Dh, 00Ah, 000h
		

demoos2.asm

;=======================================================
; Demo OS - demoos2.asm
; -----------------------------------------------------
; Written in NASM
; Written by Marcus Kelly
;=======================================================

    org     00000h                                      ; Assemble code for this offset

start:
    cli                                                 ; Turn off interrupts
    cld							; Make sure we are going forward
    xor     ax, ax                                      ; Zero the ax register
    mov     ds, ax                                      ; Make sure data segment is zero
    mov     ss, ax                                      ; Make sure stack segment is zero
    mov     sp, 07C00h                                  ; Place stack ptr before boot sector
    sti                                                 ; Turn on interrupts

    push    cs                                          ; Make sure data segment = code segment
    pop     ds

    mov     si, message                                 ; si is set to offset Message
    call    strout                                      ; call our string output routine

die:                                                    ; This is our die loop so the
    jmp     die                                         ;  computer doesn't run random
                                                        ;  code

;-------------------------------------------------------
; String Output
; Input:
;    DS:SI = Message offset
; Output:
;    AX, BX, SI are destroyed
;-------------------------------------------------------
strout:
    lodsb                                               ; Get character from string
    or      al, al                                      ; Check if our character is zero
    jz      stroutdone                                  ; if it is zero we have finished
    mov     ah, 00Eh                                    ; BIOS print call
    mov     bx, 00007h                                  ; Character attribute
    int     010h                                        ; Call the video BIOS
    jmp     strout                                      ; Get next character
stroutdone:
    ret                                                 ; return from subroutine


;-------------------------------------------------------
; Data Area
;-------------------------------------------------------

message:        db      00Dh, 00Ah, "Sector 2"          ; Message to be printed
                db      00Dh, 00Ah, 000h

                times   510-($-$$) db 0                 ; inserts zeros from this address
                                                        ;   to address 510
                dw      0AA55h                          ; Boot signature at 510 / 511
		

Modify the disk image

Add the following line to your osdisk.asm file to add demoos2.bin to your disk image.

incbin "demoos2.bin"					; include our demoos2.bin file as binary
		

osdisk.img

;=======================================================
; Disk Image - osdisk.asm
; -----------------------------------------------------
; Written in NASM
; Written by Marcus Kelly
;=======================================================
incbin "boot.bin"					; include our boot.bin file as binary
incbin "demoos2.bin"					; include our demoos2.bin file as binary
                times 1474560-($-$$) db 0               ; Make file size 1,474,560 bytes long
                                                        ;   This is the size of a floppy disk
		

Now lets build our disk. If you are running the previous tutorial in VirtualBox Remember to remove the disk or close virtual box before assembling the disk image.

> nasm boot.asm -o boot.bin
> nasm demoos2.asm -o demoos2.bin
> nasm osdisk.asm -o osdisk.img
		

Your osdisk.img can now be loaded with VirtualBox. The result should be as follows:


Sector 2
		
Boot: Hello, World! | Index | Boot: Root Calculations

Support This Project On Patreon

Copyright © 2021 Marcus Kelly