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 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
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
;======================================================= ; 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
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
;======================================================= ; 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 2Boot: Hello, World! | Index | Boot: Root Calculations