Boot: Root Calculations | Index | Boot: Final Touch Ups

Write Your Own OS from Scratch - Chapter 1. Boot

Boot: Data Calculations

We start out adding are two lba variables for our calculations

data:           dw      0                               ; lba for data
datamod:        dw      0                               ; lba modulous for data
		

Add the following code to calculate the start of the data area on the disk. Every file you load will have the result of this added to it's FAT location.

    mov     [data], ax                                  ; Seve result in data we will just add
    mov     [datamod], dx                               ; Save modulous in datamod

    mov     ax, 32					; 32 * rootdirents + bytespersec - 1 / 512
    mul     word [rootdirents]
    mov     bx,[bytespersec]
    add     ax, bx
    dec     ax
    div     bx
    add     [data], ax					; save result in data
    adc     word [datamod], byte 0                      ; save modulous in datamod

    mov     ax, [data]                                  ; Set AX to data
    mov     dx, [datamod]                               ; Set DX to datamod
		

Now AX no longer is root when we get to Calculate CHS so we can modify the comment on that line as follows:

    call    calcchs                                     ; AX = root, Calculate CHS
		

to

    call    calcchs                                     ; Calculate CHS
		

Now we will load three sectors instead of one.

    mov     cx, 3                                       ; Set count to 3
loadnext:
    push    ax						; Save LBA
    push    cx						; Save count
    push    dx						; Save LBA modulous
		

and

    pop     dx                                          ; Restore LBA modulous
    pop     cx                                          ; Restore count
    pop     ax                                          ; Restore LBA
    inc     ax                                          ; Increment LBA
    adc     dx, 0                                       ; Add carry to modulous
    add     bx, word [bytespersec]                      ; Add bytespersec to load location
    loop    loadnext                                    ; Load next sector
		

Since we added some push commands and jump before we pop we also need to change the loaderror jump so it pops the data off the stack. Add the following code then change jc loaderror to jc loaderrorpop

loaderrorpop:
    pop    dx                                           ; Clean up
    pop    cx
    pop    ax
		

Instead of continuing to die if there is an error we will add code to wait for key and then reboot.

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

with

    xor     ax, ax                                      ; BIOS Routine to Wait for Key
    int     016h
    int     019h                                        ; BIOS Bootstrap (Restart Computer)
		

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 byte 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
root:           dw      0                               ; lba for root
rootmod:        dw      0                               ; lba modulous for root
data:           dw      0                               ; lba for data
datamod:        dw      0                               ; lba modulous for data

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     al, [fats]                                  ; fats * fatsecs + hiddensecs + ressectors
    mul     word [fatsecs]
    add     ax, [hiddensecs]
    adc     dx, [hiddensecs+2]
    add     ax, [ressectors]
    adc     dx, byte 0                                  ; if carry increment modulous
    mov     [root], ax                                  ; Save result in root
    mov     [rootmod], dx                               ; Save modulous in rootmod
    mov     [data], ax                                  ; Seve result in data we will just add
    mov     [datamod], dx                               ; Save modulous in datamod

    mov     ax, 32					; 32 * rootdirents + bytespersec - 1 / 512
    mul     word [rootdirents]
    mov     bx,[bytespersec]
    add     ax, bx
    dec     ax
    div     bx
    add     [data], ax					; save result in data
    adc     word [datamod], byte 0                      ; save modulous in datamod

    mov     bx, 00700h                                  ; Load second sector at 00000h:00700h

    mov     ax, [data]                                  ; Set AX to data
    mov     dx, [datamod]                               ; Set DX to datamod
    mov     cx, 3                                       ; Set count to 3
loadnext:
    push    ax						; Save LBA
    push    cx						; Save count
    push    dx						; Save LBA modulous
    call    calcchs                                     ; Calculate CHS
    jc      loaderrorpop                                ; If there is an issue show load error
    call    readsec                                     ; Read Sector
    jc      loaderrorpop
    pop     dx                                          ; Restore LBA modulous
    pop     cx                                          ; Restore count
    pop     ax                                          ; Restore LBA
    inc     ax                                          ; Increment LBA
    adc     dx, 0                                       ; Add carry to modulous
    add     bx, word [bytespersec]                      ; Add bytespersec to load location
    loop    loadnext                                    ; Load next sector

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

loaderrorpop:
    pop    dx                                           ; Clean up
    pop    cx
    pop    ax
loaderror:
    mov     si, message                                 ; si is set to offset Message
    call    strout                                      ; call our string output routine
    xor     ax, ax                                      ; BIOS Routine to Wait for Key
    int     016h
    int     019h                                        ; BIOS Bootstrap (Restart Computer)

;-------------------------------------------------------
; 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

;-------------------------------------------------------
; Calculate CHS
; Input:
;     AX:DX = Logical Sector
; Output:
;     sector
;     head
;     track/cylinder
;-------------------------------------------------------
; sector = (lba % sectors per track) + 1
; head = lba / sectors per track % number of heads
; track = lba / sectors per track / number of heads
calcchs:
    cmp     dx, [secpertrack]                           ; Check within track
    jnc     calcchsfail                                 ; if not fail
    div     word [secpertrack]                          ; LBA / secpertrack
    inc     dl                                          ; LBA % secpertrack + 1
    mov     [sector], dl                                ; Save in sector
    xor     dx, dx                                      ; Clear the modulous
    div     word [heads]                                ; lba / secpertrack / heads
    mov     [currenthead], dl                           ; lba / secpertrack % heads
    mov     [track], ax                                 ; lba / secpertrack / heads
    clc                                                 ; Clear carry to report success
    ret                                                 ; Return from subroutine
calcchsfail:
    stc                                                 ; Set carry to report failure
    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 with out 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
		

The Operating System

Open demoos2.asm and save it as demoos.asm. Replace the following:

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

with

message:        db      00Dh, 00Ah, "DEMO OS V0.01"     ; Message to be printed
                db      00Dh, 00Ah, 000h
		

demoos.asm

;=======================================================
; Demo OS - demoos.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, "DEMO OS V0.01"     ; 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

Using the math we just added we can calculate the data area start for our image file and place our demoos.bin at that location.

                times 16896-($-$$) db 0                 ; (32 * 224 + 512 - 1) / 512 = 14
incbin "demoos.bin"                                     ; 14 * 512 + 9728 = 16896
		

osdisk.asm

;=======================================================
; 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 9728-($-$$) db 0                  ; Place our file at 9728
incbin "rootdir.bin"                                    ; root = fats(2) * fatsecs(9) + ressecs(1)
                                                        ; 9728 = 19 * 512

                times 16896-($-$$) db 0                 ; (32 * 224 + 512 - 1) / 512 = 14
incbin "demoos.bin"                                     ; 14 * 512 + 9728 = 16896

                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 demoos.asm -o demoos.bin
> nasm osdisk.asm -o osdisk.img
		

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


DEMO OS V0.01
		
Boot: Root Calculations | Index | Boot: Final Touch Ups

Support This Project On Patreon

Copyright © 2021 Marcus Kelly