On this page:
4.1 The Scope
4.2 Component Ordering
4.3 Milestones
4.4 Milestone 1
4.4.1 Freestanding Binary
4.4.1.1 Binaries
4.4.1.2 C Program to Binary
4.4.1.3 Bare Metal Rust
4.4.1.4 Aside:   The Java Virtual Machine
4.4.2 Hello World Bootable Disk Image
4.4.3 Testing
4.4.3.1 Booting
4.4.3.2 Unit Tests
4.5 Milestone 2
4.6 Milestone 3
8.10

4 The Plan

This page will explain the scope of our OS, the ordering of component implementations, and a schedule organized into milestones.

4.1 The Scope

Our goal is to build an OS that can run on bare metal, with a working shell.

The OS itself will be implemented as a monokernel.

Our OS will not be POSIX-compliant. However, the OS will be Unix-like, meaning that implementing POSIX will not require major modification.

4.2 Component Ordering

The components are to be implemented in the following order...

4.3 Milestones

Each milestone is expected to take roughly a week.

4.4 Milestone 1

4.4.1 Freestanding Binary
4.4.1.1 Binaries

A binary is a file that does not contain human-readable text. IE: Interpreting the file contents as ASCII or UTF-8 yields un-printable characters.

v=5�'�p���޸���?Te|��Ľo��yMMޭ��Xo��f����k�OX�|�|z�ڽ�H�

Programmers typically use the term binary to refer to the files produced as a result of program compilation—an executable is a common example.

4.4.1.2 C Program to Binary

"foo.c" contains a basic C program.

// foo.c

int main() {

        int x = 42;

        x += 1;

        return 0;

}

The -mno-red-zone flag disables the red zone optimization in gcc.

We can compile the program to assembly code: gcc foo.c -mno-red-zone -S.

gcc compiled "foo.c" into assembly specifically for a platform. In this case, x86-64 Linux.

# foo.s

main:

        pushq   %rbp

        movq    %rsp, %rbp

        subq    $16, %rsp

        movl    $42, -4(%rbp)

        addl    $1, -4(%rbp)

        movl    $0, %eax

        leave

        ret

Finally, we can assemble (and link) "foo.s": gcc foo.s -o foo into a binary. At this point, we have an executable—something we can run on our machine.

We use the objdump program on Linux to try to understand the contents of the binary.

objdump -d foo will dissassemble the "foo" binary.

0000000000400450 <_start>:

  ...

  400463:       49 c7 c0 c0 05 40 00    mov    $0x4005c0,%r8

  40046a:       48 c7 c1 50 05 40 00    mov    $0x400550,%rcx

  400471:       48 c7 c7 36 05 40 00    mov    $0x400536,%rdi

  400478:       ff 15 6a 0b 20 00       callq  *0x200b6a(%rip) # <__libc_start_main@GLIBC_2.2.5>

  ...

 

0000000000400536 <main>:

  400536:       55                      push   %rbp

  400537:       48 89 e5                mov    %rsp,%rbp

  40053a:       48 83 ec 10             sub    $0x10,%rsp

  40053e:       c7 45 fc 2a 00 00 00    movl   $0x2a,-0x4(%rbp)

  400545:       83 45 fc 01             addl   $0x1,-0x4(%rbp)

  400549:       b8 00 00 00 00          mov    $0x0,%eax

  40054e:       c9                      leaveq

  40054f:       c3                      retq

Notice that main is not the only function! We also see the _start function, that calls the __lib_c_start_main function, with the address of main as its first argument (%rdi).

The _start function represents the C runtime. Typically, a runtime is an environment where code is executed, can provide features such as garbage collection. For C, the runtime is minimal (and optional) and only performs simple initialization—passing command-line arguments into the main function is one example.

4.4.1.3 Bare Metal Rust

Bare metal refers to execution of programs directly on computer hardware.

Our OS should also not make system calls, since that would mean our OS runs on an OS, and not on the hardware directly.

Since, our OS doesn’t link with the Rust standard library, we can’t use the Rust runtime. Instead, we simply implement our own _start function.

4.4.1.4 Aside: The Java Virtual Machine

Many programmers say that C doesn’t really have a runtime, since the runtime is a few minimal initialization steps. A common saying is that C’s runtime is the OS itself. However, note that C can run without a runtime, and it often does! Most operating systems are written in C (bare metal).

A more classic example of a serious runtime system is the Java Virtual Machine (JVM). Java code can only run on the JVM. The JVM provides automatic memory management in the form of garbage collection.

Runtime System <- Java runs here.

Operating System <- "Standard C" runs here.

Hardware <- "Freestanding C" runs here.

We want our OS to run directly on the hardware, without any dependencies on a runtime system or an OS.

4.4.2 Hello World Bootable Disk Image

We have a freestanding binary. Now what? We want to be able to put the binary on a USB, and then boot the OS.

What makes something bootable?

What is the BIOS?

What is the bootloader dependency?

What is the bootimage thingy?

4.4.3 Testing
4.4.3.1 Booting

qemu

4.4.3.2 Unit Tests

We write unit tests by...

4.5 Milestone 2

4.6 Milestone 3