Day 01 - Hello World Assembly

Today, we will write a tiny program (to far away to be called an OS) that will print “Hello World” on screen. In the meanwhile, we will talk a little bit about Makefile.

Here are the download links to files that is mentioned in today’s work.

Baisc Knowledge

When the computer powered up, the hardware system follows a pre-defined process to initialize everything. The BIOS (Basic Input Output System) chip automatically loads the first sector (512 Bytes) into the memory starting at address 0x7C00 (and ends at 0x7E00). When the CPU verifies that the first sector is a startup sector, the CPU will execute the inside code. Note that, the startup sector must end with “AA55”.

You also need to know a little bit about Assembly Language. Don’t be afraid, since we are not going to go to far away. I wrote detailed comments to the source code and it should be friendly to beginners.

Source Code

This is the first assembly language, we will spend some time on explaining the code.

bits 16                 ; tell NASM this is 16 bit code
org 0x7c00              ; tell NASM to start outputting stuff at offset 0x7c00,
                        ; Or to say, load the following code to memory address 0x7c00

boot:
    mov si, hello       ; point si register to hello label memory location
    mov ah, 0x0e        ; 0x0e means 'Write Character in TTY mode'

.loop:
    lodsb               ; load string [DS:SI]into AL

    ; check whether it's the end of the string (seeing an zero)
    or al,al            ; is al == 0 ?  Note that AL OR AL = AL. Simply to set the flags
    jz halt             ; if (al == 0) jump to halt if Zero Flag (ZF) is set
                        ; another way to write is
                        ; CMP   AL, 0       ; compare AL
                        ; JE    HALT        ; Jump if Equal

    int 0x10            ; runs BIOS interrupt 0x10 - Video Services for printing the character in AL
    jmp .loop
halt:
    cli                 ; clear interrupt flag
    hlt                 ; halt execution until wake up

hello: db "Hello world!",0

times 510 - ($-$$) db 0 ; pad remaining 510 bytes with zeroes
                        ; the above line is equivalent to RESB 510 - ($-$$)
dw 0xaa55               ; magic bootloader magic - marks this 512 byte sector bootable for no reason! Checked by system.

Execute

In terminal, we first generate the startup file loader.bin using nasm

nasm -f bin -o loader.bin loader.asm

If you simply want to see the result, you can directly use qemu to run your newly made by

qemu-system-x86_64 -fda loader.bin

If you want to make a bootable image, you can

# generate a 1.44MB floppy disk img
dd if=/dev/zero of=myos.img bs=512 count=2880

# write the .bin into the img
dd if=loader.bin of=myos.img seek=0 count=1 conv=notrunc

# execute
qemu-system-x86_64 -fda myos.img

You will see

../../../../_images/result.png

Write a Makefile

In the development process, we would like to simply the process of typing commands. Write all commands in to a Bash scipt is an option, but what if we want more? For instance, we may want to generate the bin file only, may want to clean all unrelated file, may want to conduct the dry run. Using Makefile is a good idea.

The basic syntax for makefile rules is

target ... : prerequisites ...
    [tab] one command to generate target

For our case, in order to generate the .bin file, we need the assembly file. We can have

loader.bin : loader.asm
        nasm -f bin -o loader.bin loader.asm

The provided makefile reads:

myos.img : loader.bin
    dd if=/dev/zero of=myos.img bs=512 count=2880 &&\
    dd if=loader.bin of=myos.img seek=0 count=1 conv=notrunc

loader.bin : loader.asm
    nasm -f bin -o loader.bin loader.asm



run : myos.img
    qemu-system-x86_64 -fda myos.img

.PHONY : clean # .PHONY means clean is not a file or an object
clean:
    rm *.bin *.img

The possible commands you can try are

make # equivalent to "make myos.img"
make myos.img
make loader.bin
make run
make clean

The make command automatically figures out which files are required to generate the target file. For example, when executing “make run”, make command knows that it needs myos.img, and loader.bin must be generated before myos.img.

Makefile is a efficient tool to manage big project with complex file dependency.