Nix is a toy operating system that serves only to teach me and some of my friends about operating systems.
Nix targets the AM3358 Sitara implementation of the Cortex-A8 processor currently and is too early in development to really start thinking about other platforms. Nevertheless, code should be written in such a way that porting to other platforms is feasible.
Download the ARM cross-compiler toolchain:
- Install the ARM cross-compiler toolchain:
$ sudo apt-get install gcc-arm-linux-gnueabi
- Download and install the ARM cross-compiler toolchain:
- Add
/usr/local/linaro/arm-linux-gnueabihf/binto your$PATH - These binaries have "hf" in the name which you will need to remove. Here is a one-liner to do so:
$ cd /usr/local/linaro/arm-linux-gnueabihf/bin
$ for i in $(ls); do sudo mv $i $(echo $i | sed "s/\(arm.*\)hf\(-.*\)/\1\2/"); done
- Lastly, from within the
srcdirectory, edit theMakefileand change theGETSIZEvariable tostat -f "%z"
From within the src directory:
$ make
This builds several things, but most importantly sys.bin which has the kernel
image in it.
You will need an empty, fat32 formatted micro SD card with the following files copied to it:
- http://downloads.angstrom-distribution.org/demo/beagleboard/MLO
- http://downloads.angstrom-distribution.org/demo/beagleboard/u-boot.img
- http://downloads.angstrom-distribution.org/demo/beagleboard/uImage-beagleboard.bin
Now copy uEnv.txt and sys.bin to the SD card.
And that's it!
The boot image sys.bin can be broken into two parts: the entry section, and
the kernel section. The raw entry section image is contained in entry.bin and
the kernel section is contained in kernel.bin. Each section is compiled as
free standing (no standard library linked in), statically compiled ELF file
which is then used to generate a binary image (it is copied exactly in that
format to memory when loaded). The binary files are then copied to the same
single file with an appropriate amount of padding in between.
The entry section is compiled as a separate binary from the rest of the kernel because it is responsible for turning on the MMU. Thus, it starts off in physical addressing mode and ends in virtual addressing mode; this corrupts any pointers in existence prior to the MMU being turned on. The entry section overcomes the addressing change issue by simply not sharing any linkage with the rest of the kernel. This is most easily achieved by compiling it as a completely separate binary. The entry section's behavior is further described in the Boot Sequence section below.
This is where all the magic happens, or will happen once it does something interesting.
Execution begins in _start in boot/entry-asm.s.
Currently, all it does is ensures that the MMU is disabled and jumps into
init_mmu in boot/entry.c.
init_mmu:
- Sets up the memory translation table
- Creates a flat mapping for the code that turns on the MMU
- Sets up the
ttbr0,ttbcr, anddacrregisters - Jumps to
__start_mmuinboot/entry-asm.s
__start_mmu:
- Turns on the MMU.
- Jumps to itself in the new virtual address space.
- NOT IMPLEMENTED: Invalidates the TLB.
- Jumps to the kernel,
__kernel_startinboot/kernel-start-asm.s.
__kernel_start:
- Sets up the stack.
- Jumps to
kernel_startinboot/kernel-start.c
kernel_start:
- Prints
Starting kernel ... - Clears the BSS.
- Finishes MMU initialization.