Last time we got an OS that just booted up and did nothing and thats great, but most operating systems do more than just nothing. And im sure you don't want to be doing the entire thing in just assembly!
So we are going to be adding C to our OS.
Using C
C requires a stack and right now we don't have one. We have to fix that
global entry
MAGIC equ 0x1BADB002 ; These tell the bootloader that we are bootable
FLAGS equ 0
SUM equ -MAGIC
section .text:
align 4 ; Align everything after this to a 4 byte boundary, which the boot header needs to be aligned to
dd MAGIC ; dd means "define double word", a word is usually 2 bytes on most computers, so a dword is 4 bytes. You can think of a word as being a short in C and a dword being an int.
dd FLAGS
dd SUM
CSTACK_SIZE equ 4096 ; This is how big we want our stack to be
entry:
mov esp, cstack + CSTACK_SIZE ; The ESP register holds the current position on the stack
jmp entry ; For now we won't do anything but loop forever.
section .bss:
align 4 ; We should align our stack on a 4 byte boundary, im unsure of the consquences of not doing this but im sure you do not want to find out.
cstack:
resb CSTACK_SIZE ; resb == "reserve bytes"
Great! We have a stack and now we can call C, which we must compile separately. We don't have any standard library or protections so we need a lot of compiler flags
Now lets make our C entry point and call it from the OS
int main() {
return 0;
}
And to call it
global entry
MAGIC equ 0x1BADB002 ; These tell the bootloader that we are bootable
FLAGS equ 0
SUM equ -MAGIC
section .text:
align 4 ; Align everything after this to a 4 byte boundary, which the boot header needs to be aligned to
dd MAGIC ; dd means "define double word", a word is usually 2 bytes on most computers, so a dword is 4 bytes. You can think of a word as being a short in C and a dword being an int.
dd FLAGS
dd SUM
CSTACK_SIZE equ 4096 ; This is how big we want our stack to be
entry:
mov esp, cstack + CSTACK_SIZE ; The ESP register holds the current position on the stack
extern main
call main
jmp entry ; if main returns, just do nothing. there isn't anything else to do here
section .bss:
align 4 ; We should align our stack on a 4 byte boundary, im unsure of the consquences of not doing this but im sure you do not want to find out.
cstack:
resb CSTACK_SIZE ; resb == "reserve bytes"
Now we have an OS that calls a C function
Writing text to the screen
Have you ever done console.log("Hello World") or maybe even called print a few times? Im sure you never paid much attention to what goes on far behind the scenes. Unfortunately we don't get the convenience of a print function until we make one, we are going to be using the VGA Text Mode Framebuffer as it is extremely easy to use.
// 0xB8000 is the address of the vga framebuffer
char* fb = (char*) 0xB8000;
int main() {
// The framebuffer is a 1 dimensional "array", to get a character cell from an x and y value I did some trial and error and came up with 2 * x + 160 * y
int x = 0;
int y = 0;
// Now we get to display text!
// First you write the letter
// Then you write the color attribute you want to write it in, we will just use white on black for now
// We can do this better and more efficiently later
int position = 2 * x + 160 * y;
fb[position] = 'H';
fb[position + 1] = 0xF0;
x++;
position = 2 * x + 160 * y;
fb[position] = 'i';
fb[position + 1] = 0xF0;
}
Once compiled and ran this should output Hi to the screen! Unfortunately we can't do all of an operating system with just C.
Whenever I use pointers (or more specifically, strings) I get this error: Could not open option rom 'linuxboot_dma.bin': No such file or directory
Do you know what would cause that? (My project is a little different than yours, you can look at it here: https://repl.it/@fuzzyastrocat/OS) Even just doing char* mystr = "A string"; in main() causes this error.
@fuzzyastrocat string literals get stored in a section like .rodata while assigning it to an array makes an array in memory and copies the characters to it.
Last time we got an OS that just booted up and did nothing and thats great, but most operating systems do more than just nothing. And im sure you don't want to be doing the entire thing in just assembly!
So we are going to be adding C to our OS.
Using C
C requires a stack and right now we don't have one. We have to fix that
Great! We have a stack and now we can call C, which we must compile separately. We don't have any standard library or protections so we need a lot of compiler flags
Here is the new compiling script
Now lets make our C entry point and call it from the OS
And to call it
Now we have an OS that calls a C function
Writing text to the screen
Have you ever done
console.log("Hello World")
or maybe even called print a few times? Im sure you never paid much attention to what goes on far behind the scenes. Unfortunately we don't get the convenience of a print function until we make one, we are going to be using the VGA Text Mode Framebuffer as it is extremely easy to use.Once compiled and ran this should output
Hi
to the screen!Unfortunately we can't do all of an operating system with just C.
Whenever I use pointers (or more specifically, strings) I get this error:
Could not open option rom 'linuxboot_dma.bin': No such file or directory
Do you know what would cause that? (My project is a little different than yours, you can look at it here: https://repl.it/@fuzzyastrocat/OS)
Even just doing
char* mystr = "A string";
in main() causes this error.@CSharpIsGud I've actually fixed the issue — instead of
I do
Not sure why this happens, since I thought pointers and arrays were essentially interchangeable, but it works so yay!
@fuzzyastrocat string literals get stored in a section like .rodata
while assigning it to an array makes an array in memory and copies the characters to it.
@CSharpIsGud Oh, interesting — so there must be something strange with
.rodata
then, using it tries to findlinuxboot_dma.bin