Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
*.elf
*.sym
.DS_STORE
os-tutorial.pdf
3 changes: 3 additions & 0 deletions 00-environment/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Environment
===========

*Concepts you may want to Google beforehand: linux, mac, terminal, compiler, emulator, nasm, qemu*

**Goal: Install the software required to run this tutorial**
Expand Down
9 changes: 6 additions & 3 deletions 01-bootsector-barebones/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Bootsector: Barebones
=====================

*Concepts you may want to Google beforehand: assembler, BIOS*

**Goal: Create a file which the BIOS interprets as a bootable disk**
Expand Down Expand Up @@ -25,7 +28,7 @@ e9 fd ff 00 00 00 00 00 00 00 00 00 00 00 00 00
```

It is basically all zeros, ending with the 16-bit value
`0xAA55` (beware of endianness, x86 is little-endian).
`0xAA55` (beware of endianness, x86 is little-endian).
The first three bytes perform an infinite jump

Simplest boot sector ever
Expand All @@ -38,12 +41,12 @@ simple assembler code:
```nasm
; Infinite loop (e9 fd ff)
loop:
jmp loop
jmp loop

; Fill with 510 zeros minus the size of the previous code
times 510-($-$$) db 0
; Magic number
dw 0xaa55
dw 0xaa55
```

To compile:
Expand Down
7 changes: 5 additions & 2 deletions 02-bootsector-print/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Bootsector: Print
=================

*Concepts you may want to Google beforehand: interrupts, CPU
registers*

Expand All @@ -14,7 +17,7 @@ is a general interrupt for video services.
`0x0e` on `ah` tells the video interrupt that the actual function
we want to run is to 'write the contents of `al` in tty mode'.

We will set tty mode only once though in the real world we
We will set tty mode only once though in the real world we
cannot be sure that the contents of `ah` are constant. Some other
process may run on the CPU while we are sleeping, not clean
up properly and leave garbage data on `ah`.
Expand All @@ -39,7 +42,7 @@ jmp $ ; jump to current address = infinite loop

; padding and magic number
times 510 - ($-$$) db 0
dw 0xaa55
dw 0xaa55
```

You can examine the binary data with `xxd file.bin`
Expand Down
3 changes: 3 additions & 0 deletions 03-bootsector-memory/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Bootsector: Memory
==================

*Concepts you may want to Google beforehand: memory offsets, pointers*

**Goal: Learn how the computer memory is organized**
Expand Down
5 changes: 4 additions & 1 deletion 04-bootsector-stack/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Bootsector: Stack
=================

*Concepts you may want to Google beforehand: stack*

**Goal: Learn how to use the stack**
Expand All @@ -11,5 +14,5 @@ decremented)

This lesson is quite straightforward, so jump ahead to the code.

I suggest that you try accessing in-stack memory addresses by yourself,
I suggest that you try accessing in-stack memory addresses by yourself,
at different points in the code, and see what happens.
7 changes: 5 additions & 2 deletions 05-bootsector-functions-strings/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Bootsector: Functions and Strings
=================================

*Concepts you may want to Google beforehand: control structures,
function calling, strings*

Expand Down Expand Up @@ -52,7 +55,7 @@ endif:

Think in your head in high level, then convert it to assembler in this fashion.

There are many `jmp` conditions: if equal, if less than, etc. They are pretty
There are many `jmp` conditions: if equal, if less than, etc. They are pretty
intuitive but you can always Google them


Expand Down Expand Up @@ -119,7 +122,7 @@ to make sure that we are reading the correct data. File `boot_sect_print_hex.asm
extends `boot_sect_print.asm` to print hex bytes, not just ASCII chars.


Code!
Code!
-----

Let's jump to the code. File `boot_sect_print.asm` is the subroutine which will
Expand Down
3 changes: 3 additions & 0 deletions 06-bootsector-segmentation/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Bootsector: Segmentation
========================

*Concepts you may want to Google beforehand: segmentation*

**Goal: learn how to address memory with 16-bit real mode segmentation**
Expand Down
7 changes: 5 additions & 2 deletions 07-bootsector-disk/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
*Concepts you may want to Google beforehand: hard disk, cylinder, head, sector,
Bootsector: Disk
================

*Concepts you may want to Google beforehand: hard disk, cylinder, head, sector,
carry bit*

**Goal: Let the bootsector load data from disk in order to boot the kernel**
Expand Down Expand Up @@ -57,7 +60,7 @@ There are two quick options:

1. Try the flag `-fda` for example, `qemu -fda boot_sect_main.bin` which will set `dl`
as `0x00`, it seems to work fine then.
2. Explicitly use the flag `-boot`, e.g. `qemu boot_sect_main.bin -boot c` which
1. Explicitly use the flag `-boot`, e.g. `qemu boot_sect_main.bin -boot c` which
automatically sets `dl` as `0x80` and lets the bootloader read data


9 changes: 6 additions & 3 deletions 08-32bit-print/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
*Concepts you may want to Google beforehand: 32-bit protected mode, VGA, video
32-bit: Print
=============

*Concepts you may want to Google beforehand: 32-bit protected mode, VGA, video
memory*

**Goal: Print on the screen when on 32-bit protected mode**

32-bit mode allows us to use 32 bit registers and memory addressing,
32-bit mode allows us to use 32 bit registers and memory addressing,
protected memory, virtual memory and other advantages, but we will lose
BIOS interrupts and we'll need to code the GDT (more on this later)

Expand All @@ -18,7 +21,7 @@ The formula for accessing a specific character on the 80x25 grid is:

`0xb8000 + 2 * (row * 80 + col)`

That is, every character uses 2 bytes (one for the ASCII, another for
That is, every character uses 2 bytes (one for the ASCII, another for
color and such), and we see that the structure of the memory concatenates
rows.

Expand Down
5 changes: 4 additions & 1 deletion 09-32bit-gdt/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
32-bit: GDT
===========

*Concepts you may want to Google beforehand: GDT*

**Goal: program the GDT**
Expand All @@ -9,7 +12,7 @@ In 32-bit mode, segmentation works differently. Now, the offset becomes an
index to a segment descriptor (SD) in the GDT. This descriptor defines
the base address (32 bits), the size (20 bits) and some flags, like
readonly, permissions, etc. To add confusion, the data structures are split,
so open the os-dev.pdf file and check out the figure on page 34 or the
so open the os-dev.pdf file and check out the figure on page 34 or the
Wikipedia page for the GDT.

The easiest way to program the GDT is to define two segments, one for code
Expand Down
5 changes: 4 additions & 1 deletion 10-32bit-enter/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
32-bit: Enter
=============

*Concepts you may want to Google beforehand: interrupts, pipelining*

**Goal: Enter 32-bit protected mode and test our code from previous lessons**
Expand All @@ -17,7 +20,7 @@ and take a look at the code.

After entering 32-bit mode, we will call `BEGIN_PM` which is the entry point
for our actual useful code (e.g. kernel code, etc). You can read the code
at `32bit-main.asm`. Compile and run this last file and you will see the two
at `32bit-main.asm`. Compile and run this last file and you will see the two
messages on the screen.

Congratulations! Our next step will be to write a simple kernel
13 changes: 8 additions & 5 deletions 11-kernel-crosscompiler/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Kernel: Crosscompiler
=====================

*Concepts you may want to Google beforehand: cross-compiler*

**Goal: Create a development environment to build your kernel**
Expand All @@ -6,7 +9,7 @@ If you're using a Mac, you will need to do this process right away. Otherwise, i
for a few more lessons. Anyway, you will need a cross-compiler once we jump to developing in a higher
language, that is, C. [Read why](http://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler%3F)

I'll be adapting the instructions [at the OSDev wiki](http://wiki.osdev.org/GCC_Cross-Compiler).
I'll be adapting the instructions [at the OSDev wiki](http://wiki.osdev.org/GCC_Cross-Compiler).


Required packages
Expand Down Expand Up @@ -63,10 +66,10 @@ tar xf gcc-4.9.1.tar.bz2
mkdir gcc-build
cd gcc-build
../gcc-4.9.1/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --disable-libssp --enable-languages=c --without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
```

That's it! You should have all the GNU binutils and the compiler at `/usr/local/i386elfgcc/bin`, prefixed by `i386-elf-` to avoid
Expand Down
3 changes: 3 additions & 0 deletions 12-kernel-c/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Kernel: C
=========

*Concepts you may want to Google beforehand: C, object code, linker, disassemble*

**Goal: Learn to write the same low-level code as we did with assembler, but in C**
Expand Down
3 changes: 3 additions & 0 deletions 13-kernel-barebones/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Kernel: Barebones
=================

*Concepts you may want to Google beforehand: kernel, ELF format, makefile*

**Goal: Create a simple kernel and a bootsector capable of booting it**
Expand Down
3 changes: 3 additions & 0 deletions 14-checkpoint/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Checkpoint
==========

*Concepts you may want to Google beforehand: monolithic kernel, microkernel, debugger, gdb*

**Goal: Pause and organize our code a little bit. Then learn how to debug the kernel with gdb**
Expand Down
3 changes: 3 additions & 0 deletions 15-video-ports/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Video: Ports
============

*Concepts you may want to Google beforehand: I/O ports*

**Goal: Learn how to use the VGA card data ports**
Expand Down
5 changes: 4 additions & 1 deletion 16-video-driver/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Video: Driver
=============

*Concepts you may want to Google beforehand: VGA character cells, screen offset*

**Goal: Write strings on the screen**
Expand Down Expand Up @@ -44,7 +47,7 @@ Like `kprint_at`, `print_char` allows cols/rows to be `-1`. In that case it retr
the cursor position from the hardware, using the `ports.c` routines.

`print_char` also handles newlines. In that case, we will position the cursor offset
to column 0 of the next row.
to column 0 of the next row.

Remember that the VGA cells take two bytes, one for the character itself and another one
for the attribute.
Expand Down
3 changes: 3 additions & 0 deletions 17-video-scroll/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Video: Scroll
=============

*Concepts you may want to Google beforehand: scroll*

**Goal: Scroll the screen when the text reaches the bottom**
Expand Down
13 changes: 8 additions & 5 deletions 18-interrupts/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Interrupts
==========

*Concepts you may want to Google beforehand: C types and structs, include guards, type attributes: packed, extern, volatile, exceptions*

**Goal: Set up the Interrupt Descriptor Table to handle CPU interrupts**
Expand All @@ -24,7 +27,7 @@ From now on, our C header files will also have include guards.
Interrupts
----------

Interrupts are one of the main things that a kernel needs to
Interrupts are one of the main things that a kernel needs to
handle. We will implement it now, as soon as possible, to be able
to receive keyboard input in future lessons.

Expand All @@ -37,22 +40,22 @@ programming the IDT in assembly, we'll do it in C.

`cpu/idt.h` defines how an idt entry is stored `idt_gate` (there need to be
256 of them, even if null, or the CPU may panic) and the actual
idt structure that the BIOS will load, `idt_register` which is
idt structure that the BIOS will load, `idt_register` which is
just a memory address and a size, similar to the GDT register.

Finally, we define a couple variables to access those data structures
from assembler code.

`cpu/idt.c` just fills in every struct with a handler.
`cpu/idt.c` just fills in every struct with a handler.
As you can see, it is a matter
of setting the struct values and calling the `lidt` assembler command.


ISRs
----

The Interrupt Service Routines run every time the CPU detects an
interrupt, which is usually fatal.
The Interrupt Service Routines run every time the CPU detects an
interrupt, which is usually fatal.

We will write just enough code to handle them, print an error message,
and halt the CPU.
Expand Down
11 changes: 7 additions & 4 deletions 19-interrupts-irqs/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
Interrupts: IRQs
================

*Concepts you may want to Google beforehand: IRQs, PIC, polling*

**Goal: Finish the interrupts implementation and CPU timer**

When the CPU boots, the PIC maps IRQs 0-7 to INT 0x8-0xF
and IRQs 8-15 to INT 0x70-0x77. This conflicts with the ISRs
we programmed last lesson. Since we programmed ISRs 0-31,
we programmed last lesson. Since we programmed ISRs 0-31,
it is standard to remap the IRQs to ISRs 32-47.

The PICs are communicated with via I/O ports (see lesson 15).
The Master PIC has command 0x20 and data 0x21, while the slave has
command 0xA0 and data 0xA1.

The code for remapping the PICs is weird and includes
some masks, so check
some masks, so check
[this article](http://www.osdev.org/wiki/PIC) if you're curious.
Otherwise, just look at `cpu/isr.c`, new code after we set the IDT
gates for the ISRs. After that, we add the IDT gates for IRQs.

Now we jump to assembler, at `interrupt.asm`. The first task is to
add global definitions for the IRQ symbols we just used in the C code.
add global definitions for the IRQ symbols we just used in the C code.
Look at the end of the `global` statements.

Then, add the IRQ handlers. Same `interrupt.asm`, at the bottom. Notice
Expand All @@ -31,7 +34,7 @@ a new `[extern irq_handler]`
Now back to C code, to write the `irq_handler()` in `isr.c`. It sends some
EOIs to the PICs and calls the appropriate handler, which is stored in an array
named `interrupt_handlers` and defined at the top of the file. The new structs
are defined in `isr.h`. We will also use a simple function to register
are defined in `isr.h`. We will also use a simple function to register
the interrupt handlers.

That was a lot of work, but now we can define our first IRQ handler!
Expand Down
3 changes: 3 additions & 0 deletions 20-interrupts-timer/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Interrupts: Timer
=================

*Concepts you may want to Google beforehand: CPU timer, keyboard interrupts, scancode*

**Goal: Implement our first IRQ handlers: the CPU timer and the keyboard**
Expand Down
6 changes: 4 additions & 2 deletions 21-shell/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
Shell
=====

**Goal: Clean the code a bit and parse user input**

In this lesson we will do two things. First, we will clean up the code a bit, so it is ready
In this lesson we will do two things. First, we will clean up the code a bit, so it is ready
for further lessons. During the previous ones I tried to put things in the most predictable places,
but it is also a good exercise to know when the code base is growing and adapt it to current
and further needs.
Expand Down Expand Up @@ -52,7 +54,7 @@ arrays which are defined at the beginning of `keyboard.c`
- When the OS wants to read user input, it calls `libc/io.c:readline()`

`keyboard.c` also parses backspace, by removing the last element
of the key buffer, and deleting it from the screen, by calling
of the key buffer, and deleting it from the screen, by calling
`screen.c:kprint_backspace()`. For this we needed to modify a bit
`print_char()` to not advance the offset when printing a backspace

Expand Down
Loading