In this tutorial, I will not teach you how to make a bunch of if statements in Python or Node.js or Java, but will teach you how to make a real OS, although it won't be able to do much. Basic experience with NASM x86 Assembly, but it is not required since this will explain everything needed along the way.
Installing Packages
To create an OS, you need two packages: NASM and QEMU. NASM is the Assembler we will use and QEMU is the VM we will use to run the OS.
You can use this basic Bash script to automatically download them if needed.
if ! which nasm > /dev/null; then install-pkg nasm; fi
if ! which qemu-system-x86_64 > /dev/null; then install-pkg qemu; fi
Next up, you need to install the required libraries.
Installing Libraries
There are a number of libraries needed to run everything in QEMU. Thanks to @CSharpIsGud , this is fairly easy...
Using the following Bash script, you can install all of the required libraries.
You only need to run this once, so if you put it in your main.sh file, you can comment it out after running once.
Setting Up The File System
Now, we need to set up the proper files for this all to work.
First, create a folder named iso and inside that, create a folder named boot. You also, in the root directory, need to create two files: Link.ld and Loader.asm. Link.ld tells the linker how to put together the binary file so it can be used and Loader.asm is your main Assembly code.
Setting Up The Linker File
Inside Link.ld, put the following code:
ENTRY(entry) /* the name of the entry label */
SECTIONS {
. = 0x00100000; /* the code should be loaded at 1 MB */
.text ALIGN (0x1000) : /* align at 4 KB */
{
*(.text) /* all text sections from all files */
}
.rodata ALIGN (0x1000) : /* align at 4 KB */
{
*(.rodata*) /* all read-only data sections from all files */
}
.data ALIGN (0x1000) : /* align at 4 KB */
{
*(.data) /* all data sections from all files */
}
.bss ALIGN (0x1000) : /* align at 4 KB */
{
*(COMMON) /* all COMMON sections from all files */
*(.bss) /* all bss sections from all files */
}
}
Of course, this is copied from @CSharpIsGud 's tutorial which was in turn copied from LittleOSBook, so I cannot really explain all of this that well.
The Assembly Template
To start working on your OS, you need to follow a basic template which makes the code bootable. Here is the template:
global entry
MAGIC equ 0x1BADB002 ; These tell the bootloader that we are bootable
FLAGS equ 0
SUM equ -MAGIC
; Now, setting up some basic constants to use in our program
SYS_WRITE equ 4
SYS_READ equ 3
STDOUT equ 1
STDIN equ 2
SYS_EXIT equ 1
WRITESTART equ 0xB8000
; Macros will go here
section .data
; Nothing here for now...
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
entry:
loop:
jmp loop ; For now we won't do anything but loop forever.
This is just a basic template so that you can start writing your OS... Now, for the actual coding!
Making The OS
All of the code in this section will be done in the Loader.asm file.
Declaring Variables
First off, in the .data section, we need to set up a few variables. In the section, you should add the following code.
msg dd " HelloWorld OS 0.0.1 " ; Title message
len equ $ - msg ; Get length
msg2 dd "HelloWorld OS is a basic operating system that does nothing but print this text." ; Line 1
len2 equ $ - msg2 ; Get length
msg3 dd 'HelloWorld OS is named after the common practice to make your first program simply say "Hello World".' ; Line 2
len3 equ $ - msg3 ; Get Length
position dd 0 ; Required
temp dd 0 ; Required
templen dd 0 ; Required
line dd 0 ; Required
All of the variables that have "Required" commented next to them are absolutely required for this. The other lines are messages to be printed and you can feel free to change them in any way you want.
Macros
Now, we need to create a few macros for this program to run!
Printing Characters
We need to have a way to print characters at a specified position. We can use a macro for that!
%macro printchar 2 ; The macro printchar will take 2 arguments
mov eax, WRITESTART ; Set eax to the memory position of the start of text output
mov ebx, [position] ; Now, we take the value of position and put it into ebx.
add eax, ebx ; Now, we add ebx to eax to get the current memory position.
mov ebx, %1 ; Now, we set ebx to the character we are printing.
mov [eax], ebx ; And we set the given memory position to ebx to print the character.
mov ecx, eax ; Now, we move eax to ecx for some more memory manipulation to set the color
add ecx, 1 ; We increase ecx by 1 since we need to go to the next byte for the color data.
mov edx, %2 ; Here, we set edx to the color we want.
mov [ecx], edx ; And here we set the given memory position to edx to set the color.
mov eax, [position] ; Lastly, these last 3 lines of the macro add 2 to the position variable.
add eax, 2
mov [position], eax
%endmacro
The comments explain how this works. Now, we need to be able to clear the screen.
Clearing the Screen
Now that we can print single characters, we need to be able to clear the screen! We need two macros for that!
First off, the macro to clear a given number of characters!
%macro clearscreen 1 ; The clearscreen macro takes 1 argument: the number of characters to clear.
mov eax, %1 ; We move the number of characters to eax...
mov [templen], eax ; ... and we use that to set templen.
%%clearscreen: ; This label will be used for a loop.
printchar ' ', 0 ; For each iteration of the loop, we print a space character with the default color, 0, to clear that character's position on the screen
mov esi, [templen] ; Now, we need to move templen to esi...
sub esi, 1 ; ..and subtract 1...
mov [templen], esi ; ... and move that back to templen so we can decrement the variable.
mov al, [templen] ; And now, we need to move templen to al so we can compare it.
cmp al, 0 ; This checks if al (from templen) is 0.
jne %%clearscreen ; If it is not 0, it iterates through the loop again. If it is 0, the macro ends.
%endmacro
Once again, the comments explain this macro.
Now, we need to use this to clear the entire screen.
This just repeats the clearscreen macro multiple times. Since the al register is only a 8-bit register (at least I think... It might be 16-bit), there are limits to the amount it can go, so each 4000 doesn't actually clear 4000 digits.
This macro will be used for clearing the screen at the start of the program.
Printing Strings
Now, we need a macro to print strings.
%macro printstr 3 ; This takes 3 arguments, the string, the length, and the color.
mov eax, %1 ; These two lines move the string to temp.
mov [temp], eax
mov eax, %2 ; And these move the length to templen.
mov [templen], eax
%%printstart: ; This is the start of a loop.
mov esi, [temp] ; Here, we get the current character...
mov esi, [esi]
printchar esi, %3 ; ... and print it with the given color.
mov esi, [temp] ; Now, we increment temp so we can get to the next character
add esi, 1
mov [temp], esi
mov esi, [templen] ; And we decrement templen...
sub esi, 1
mov [templen], esi
mov al, [templen] ; ... and compare it to 0 to see if we need to go through another iteration of the loop.
cmp al, 0
jne %%printstart
%endmacro
Moving Lines
Now, we need one last macro...
%macro gotoline 1
mov eax, %1 ; Move the line number to eax ...
imul eax, 160 ; ... and multiply by 160 (characters per line) ...
mov [position], eax ; ... and set the position to that.
%endmacro
This macro will allow you to skip to certain lines.
Now that we have the macros, we can start programming the rest of the OS!
Programming the OS
Now that we have the macros, we need to use them in the .text section.
Currently we have
entry:
loop:
jmp loop ; For now we won't do anything but loop forever.
but we will need to change this code.
The code for this basic OS is
entry:
clearall ; Clear the screen
mov eax, 0 ; Now, we need to reset the character position.
mov [position], eax
printstr msg, len, 0b00011010 ; Blue background, green text.
gotoline 4 ; Go to line 4
printstr msg2, len2, 10 ; Green text
gotoline 6 ; Go to line 6
printstr msg3, len3, 10 ; Green text
loop:
jmp loop ; For now we won't do anything but loop forever.
Of course, you can change things like the color, number of messages, order of messages, etc. This is just a basic OS like HelloWorld OS which can be found here: https://repl.it/talk/share/HelloWorld-OS/52435
Compiling and Running QEMU
To compile and run QEMU, you simply use the following Bash script:
How To Make a Basic OS
Introduction
In this tutorial, I will not teach you how to make a bunch of if statements in Python or Node.js or Java, but will teach you how to make a real OS, although it won't be able to do much. Basic experience with NASM x86 Assembly, but it is not required since this will explain everything needed along the way.
Installing Packages
To create an OS, you need two packages: NASM and QEMU. NASM is the Assembler we will use and QEMU is the VM we will use to run the OS.
You can use this basic Bash script to automatically download them if needed.
Next up, you need to install the required libraries.
Installing Libraries
There are a number of libraries needed to run everything in QEMU. Thanks to @CSharpIsGud , this is fairly easy...
Using the following Bash script, you can install all of the required libraries.
You only need to run this once, so if you put it in your
main.sh
file, you can comment it out after running once.Setting Up The File System
Now, we need to set up the proper files for this all to work.
First, create a folder named
iso
and inside that, create a folder namedboot
. You also, in the root directory, need to create two files:Link.ld
andLoader.asm
.Link.ld
tells the linker how to put together the binary file so it can be used andLoader.asm
is your main Assembly code.Setting Up The Linker File
Inside
Link.ld
, put the following code:Of course, this is copied from @CSharpIsGud 's tutorial which was in turn copied from LittleOSBook, so I cannot really explain all of this that well.
The Assembly Template
To start working on your OS, you need to follow a basic template which makes the code bootable. Here is the template:
This is just a basic template so that you can start writing your OS... Now, for the actual coding!
Making The OS
All of the code in this section will be done in the
Loader.asm
file.Declaring Variables
First off, in the
.data
section, we need to set up a few variables. In the section, you should add the following code.All of the variables that have "Required" commented next to them are absolutely required for this. The other lines are messages to be printed and you can feel free to change them in any way you want.
Macros
Now, we need to create a few macros for this program to run!
Printing Characters
We need to have a way to print characters at a specified position. We can use a macro for that!
The comments explain how this works. Now, we need to be able to clear the screen.
Clearing the Screen
Now that we can print single characters, we need to be able to clear the screen! We need two macros for that!
First off, the macro to clear a given number of characters!
Once again, the comments explain this macro.
Now, we need to use this to clear the entire screen.
This is a crude way of doing it, but it works!
This just repeats the
clearscreen
macro multiple times. Since theal
register is only a 8-bit register (at least I think... It might be 16-bit), there are limits to the amount it can go, so each 4000 doesn't actually clear 4000 digits.This macro will be used for clearing the screen at the start of the program.
Printing Strings
Now, we need a macro to print strings.
Moving Lines
Now, we need one last macro...
This macro will allow you to skip to certain lines.
Now that we have the macros, we can start programming the rest of the OS!
Programming the OS
Now that we have the macros, we need to use them in the
.text
section.Currently we have
but we will need to change this code.
The code for this basic OS is
Of course, you can change things like the color, number of messages, order of messages, etc. This is just a basic OS like HelloWorld OS which can be found here: https://repl.it/talk/share/HelloWorld-OS/52435
Compiling and Running QEMU
To compile and run QEMU, you simply use the following Bash script:
The next steps will be adding in C and then user input, so stay tuned to my next OSs and the tutorials for those next steps!
If you have any questions about this tutorial, please just ask!
Also, @DynamicSquid , here is a ping since you said you wanted this tutorial!
@DiveshTheReal That's all it does. LOL! Read the post. This doesn't include any input.