Part 1: Intro
Part 2: Basic Concepts
Part 3: Writing the Code
Part 4: Using QEMU and NASM
Writing a Boot Sector
This is the point where we actually start writing code. We will start by writing a basic boot sector. We will expand on this in the following steps.
We start off by putting our directives at the top of the file
[BITS 16] ;Tell the assembler to compile the code for 16 bit execution
[ORG 0x7c00] ;Tell the assembler that our addresses start at the address 0x7c00
[ORG 0x7c00] ;Tell the assembler that our addresses start at the address 0x7c00
After that we can get into the program. Though it is not required I always start with a label.
main: ;Declare a label for the start of the program
cli ;Disable Interrupts
hlt ;Halt the Processor
cli ;Disable Interrupts
hlt ;Halt the Processor
A boot sector must be 512 bytes and end with the word (2 bytes) 0xAA55. This can easily be done using the times macro in the assembler.
times 510-($-$$) db 0 ;Pad the file to make it 512 Bytes or 1 sector
dw 0xAA55 ;Declare the word 0xAA55 signifying the end of the boot sector
dw 0xAA55 ;Declare the word 0xAA55 signifying the end of the boot sector
Writing a Character to the Screen
At this point if you compile the code with NASM you will get a blank screen. We need to do a little more if we want to get some output.
We will add the following code into our file after the HLT instruction.
print:
push bx ;Push the BX register to the stack
mov bh, 0x0 ;Set the Page
mov bl, 0x07 ;Set the Text Color
mov ah, 0x0E ;Instruct the Bios to Write a Character
int 0x10 ;Call the Video Interrupt
pop bx ;Pop the BX register back from the stack
ret
push bx ;Push the BX register to the stack
mov bh, 0x0 ;Set the Page
mov bl, 0x07 ;Set the Text Color
mov ah, 0x0E ;Instruct the Bios to Write a Character
int 0x10 ;Call the Video Interrupt
pop bx ;Pop the BX register back from the stack
ret
In order to push a character to the screen we need to set BH to the page 0, BL to 0x07 which is light gray on black, set AH to 0x0E which tells the BIOS that we are writing a character to the screen using Teletype Output.
AL must contain the value of the character we are going to write to the screen. We set that and call this method by updating main.
main:
mov al, 'H' ;Store the value of the character H in the register AL
call print ;Call the Print Function
cli ;Disable Interrupts
hlt ;Halt the Processor
mov al, 'H' ;Store the value of the character H in the register AL
call print ;Call the Print Function
cli ;Disable Interrupts
hlt ;Halt the Processor
Output Hello World to the Screen
Finally we get to write the string hello world to the screen.
This is simply done by pointing the register BX to the address of the string and printing the character at that address recursively while we increment the address stored in BX. If the value at the address in BX is 0 we return as that signifies the end of the string.
A string ending with a 0 is called a null terminated string, and is the common standard among programming languages.
print_string:
push ax ;Push the AX register to the stack
push bx ;Push the BX register to the stack
mov al, [bx] ;Move the first byte from the address stored in bx
or al,al ;Do a binary OR on al to verify it is not zero
jz .return ;If al is zero then skip the loop and return
.loop:
call print ;Print the character in al
inc bx ;Increase the address in BX by 1
mov al, [bx] ;Get the next byte from the address stored in bx
or al,al ;Once again do a binary OR on al to verify it is not zero
jnz .loop ;If al is not zero go back to the start of the loop
.return:
pop bx ;POP the BX register back from the stack
pop ax ;POP the AX register back from the stack
ret
HelloWorldString db 'Hello World', 0
push ax ;Push the AX register to the stack
push bx ;Push the BX register to the stack
mov al, [bx] ;Move the first byte from the address stored in bx
or al,al ;Do a binary OR on al to verify it is not zero
jz .return ;If al is zero then skip the loop and return
.loop:
call print ;Print the character in al
inc bx ;Increase the address in BX by 1
mov al, [bx] ;Get the next byte from the address stored in bx
or al,al ;Once again do a binary OR on al to verify it is not zero
jnz .loop ;If al is not zero go back to the start of the loop
.return:
pop bx ;POP the BX register back from the stack
pop ax ;POP the AX register back from the stack
ret
HelloWorldString db 'Hello World', 0
When declaring a static location in memory with the DB instruction you can prefix it with a label. At this point you do not need to put the colon as though it is not required the assembler expects a label to precede this instruction.
At this point we can update the call in main. Do remember that a label points to an address, so when we use the MOV instruction to set BX we are setting it to the address that the HelloWorldString label is at.
main: ;Declare a label for the start of the program
mov bx, HelloWorldString ;Set BX to the address of the Hello World String
call print_string ;Call the print string function
cli ;Disable Interrupts
hlt ;Halt the Processor
mov bx, HelloWorldString ;Set BX to the address of the Hello World String
call print_string ;Call the print string function
cli ;Disable Interrupts
hlt ;Halt the Processor
No comments:
Post a Comment