Index | Boot: Load Sector

Write Your Own OS from Scratch - Chapter 1. Boot

Boot: Hello, World!

The first step in the boot process is the boot sector of the disk. This sector is loaded at 0000:7C00 hex. In this example we are going to use it to print a message then run a continuous loop to stop the system.

Our first line of our code isn't actually code it is an assembler setting to tell the assembler what offset we want to assemble from.

    org     07C00h
		

The next thing we have to do is write a subroutine to print a message. We will use the BIOS Video Service calls for this task. Using lodsb to load a character from the location ds:si we will check it to see if the value we got was zero with or al, al and jz stroutdone. then using BIOS Video Service 0E hex the character will be printed at the cursor location on the screen. Then we repeat the process with jmp strout. This is a routine worth keeping in mind for later code it can be used to print a string wherever you may need to do so.

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

Now that we have our print routine we need something to print. The following code is our string to print. 0D hex is are carrage return, this moves the cursor to the beginning of the line. 0A hex is line feed, this moves are cursor down 1 line. We then end our string with zero so the string routine knows to stop rather than to continue printing characters.

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

Processor setup is next making sure everything is pointing to the correct place and opperating correctly. cli turns off the interrupts. Which we do before we setup the processor. cld sets the direction of the string instructions to forward. So when our lodsb executes in our print routine it will increment the si register rather than decriment it. Next we set the data segment and the stack segment to zero. xor ax, ax is a quick way to zero the ax register. Then we set the stack pointer to equal to the start of our boot sector. when stuff is pushed onto the stack the stack is decrimented so this will be moving downward through memory away from our code. We then finally turn back on the interrupts with sti.

    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
		

Now the main goal of this tutorial, printing a message on the screen. We point si to the offset of our message using mov si, message. Then we call our subroutine with call strout to print the message.

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

While we have the code to print messages all ready to go there are a couple things we need to do to finish this up. The first of which is our die loop. without it our code would drop back into the strout routine with si pointing to the end of our string. since the times statement adds more zeros it would immediately decide it is done and execute the ret command since there is no return address on the stack it would use the cli, and cld bytes at the start of our program as the return address and return to that location in memory. Something we don't want to happen so lets add the die loop.

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

The final code we need to add is the boot signature. This tells the BIOS that this is a valid boot sector when the BIOS sees the boot signature it will load the boot sector into memory and run it. The times command will produce db 000h commands until the 510 bytes into the file where we will then place the boot signature of 0AA55h

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

boot.asm

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

    org     07C00h                                      ; 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     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

    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, "Hello, World!"     ; 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
                

What do we do with this code now that we have it? I you don't already have NASM you can downloade it at https://www.nasm.us/. Then open a command line terminal. make sure you are in the directory with your asm file and if you don't have a path to NASM make sure it is also in the same directory. Then run the following command.

> nasm boot.asm -o boot.bin
		

Now we have a boot sector and have several options. the first option is you can write it to the boot sector of a drive using HxD which can be downloaded at https://mh-nexus.de/en/hxd/ or the method I am going to be doing is use NASM to make a floppy disk image and load it with VirtualBox which can be downloaded at https://www.virtualbox.org/

We will add two lines to a file to generate our disk image with the boot sector. The first line of code imports are boot sector as a binary file which means it won't assemble it since we have already done that. The second line of code fills the rest of our file full of zeros to make it a proper disk image.

osdisk.asm

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

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


Hello, World!
		
Index | Boot: Load Sector

Support This Project On Patreon

Copyright © 2021 Marcus Kelly