0% found this document useful (0 votes)
6 views18 pages

Raspberry Pi OS Development Course

You can build an operating system for embedded devices.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views18 pages

Raspberry Pi OS Development Course

You can build an operating system for embedded devices.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd

Building an Operating System

Date Created January 2021


Reviewed
Version

Description

GiaKonda Solar Schools [Link] info@[Link]


Latest binutils is 2.35.1

/conversion/tmp/activity_task_scratch/[Link]
Page 2 of 18
Baking Pi – Operating Systems Development
This course has not yet been updated to work with the Raspberry Pi models B+ and A+. Some
elements may not work, in particular the first few lessons about the LED. It has also not been
updated for Raspberry Pi v2.
Welcome to Baking Pi: Operating Systems Development! Course by Alex Chadwick.
You can now help contribute to this tutorial on GitHub.
This website is here to guide you through the process of developing very basic operating systems on
the Raspberry Pi! This website is aimed at people aged 16 and upwards, although younger readers
may still find some of it accessible, particularly with assistance. More lessons may be added to this
course in time.
This course takes you through the basics of operating systems development in assembly code. I
have tried not to assume any prior knowledge of operating systems development or assembly code.
It may be helpful to have some programming experience, but the course should be accessible
without. The Raspberry Pi forums are full of friendly people ready to help you out if you run into
trouble. This course is divided into a series of 'lessons' designed to be taken in order as below. Each
'lesson' includes some theory, and also a practical exercise, complete with a full answer.
Rather than leading the reader through the full details of creating an Operating System, these
tutorials focus on achieving a few common tasks separately. Hopefully, by the end, the reader
should know enough about Operating Systems that they could try to put together everything they've
learned and make one. Although the lessons are generally focused on creating very specific things,
there is plenty of room to play with what you learn. Perhaps, after reading the lesson on functions,
you imagine a better style of assembly code. Perhaps after the lessons on graphics you imagine a 3D
operating system. Since this is an Operating Systems course, you will have the power to design
things how you like. If you have an idea, try it! Computer Science is still a young subject, and so
there is plenty left to discover!

Contents

• 1 Requirements
• 1.1 Hardware
• 1.2 Software
• 2 Lessons

/conversion/tmp/activity_task_scratch/[Link]
Page 3 of 18
1 Requirements
1.1 Hardware
In order to complete this course you will need a Raspberry Pi with an SD card and power supply. It
is helpful, but not necessary, for your Raspberry Pi to be able to be connected to a screen and
keyboard.
In addition to the Raspberry Pi used to test and run your operating system code, you also need a
seperate computer running Linux, Microsoft Windows or Mac OS X capable of writing to the type
of SD card used by your Raspberry Pi. This other computer is your development and support
system.

1.2 Software
In terms of software, you require a GNU compiler toolchain that targets ARMv6 processors. You
will install or build a set of tools, called a cross-compiler, on your development system. This cross-
compiler converts your source code files into Raspberry Pi-compatible executable files which are
placed on the SD card. The SD card is then transferred to the Raspberry Pi where the executable can
be tested.
You can find instruction for getting the toolchain on the Downloads Page, along with model
answers for all of the exercises.

2 Lessons
Table 2.1 - Lessons
Name Description
This introductory lesson does not contain a practical element, but exists to explain
the basic concepts of what is an operating system, what is assembly code, and
0 Introduction
other important basics. If you just want to get straight into practicals, it should be
safe to skip this lesson.
OK LED Series (Beginner)
The OK01 lesson contains an explanation about how to get started and teaches
1 OK01 how to enable the 'OK' or 'ACT' LED on the Raspberry Pi board near the RCA
and USB ports.
The OK02 lesson builds on OK01, by causing the 'OK' or 'ACT' LED to turn on
2 OK02
and off repeatedly.
The OK03 lesson builds on OK02 by teaching how to use functions in assembly
3 OK03
to make more reusable and rereadable code.
The OK04 lesson builds on OK03 by teaching how to use the timer to flash the
4 OK04
'OK' or 'ACT' LED at precise intervals.
The OK05 lesson builds on OK04 using it to flash the SOS morse code pattern
5 OK05
(...---...).
Screen Series (Advanced)
6 Screen01 The Screen01 lesson teaches some basic theory about graphics, and then applies it

/conversion/tmp/activity_task_scratch/[Link]
Page 4 of 18
Name Description
to display a gradient pattern to the screen or TV.
The Screen02 lesson builds on Screen01, by teaching how to draw lines and also
7 Screen02
a small feature on generating pseudo random numbers.
The Screen03 lesson builds on Screen02 by teaching how to draw text to the
8 Screen03
screen, and introduces the concept of the kernel command line.
The Screen04 lesson builds on Screen03 by teaching how to manipulate text to
9 Screen04
display computed values on the screen.
Input Series (Advanced)
The Input01 lesson teaches some theory about drivers, and linking programs, as
10 Input01
well as keyboards. It is then applied to print out input characters to the screen.
The Input02 lesson builds on Input01 by teaching how to make a command line
11 Input02
interface for an Operating System.

Lesson 0 Introduction
This introductory lesson does not contain a practical element, but exists to explain the basic
concepts of what is an operating system, what is assembly code and other important basics. If you
just want to get straight into practicals, it should be safe to skip this lesson.

Contents

• 1 Operating Systems
• 2 Assembly Code

1 Operating Systems
Throughout these tutorials I will put interesting information in boxes like this one.
Throughout these tutorials I will put information about each command we learn in boxes like this
one.
An operating system is just a very complicated program. It has the job of organising other programs
on a computer, including sharing the computer's time, memory, hardware and other resources. Some
big families of desktop operating systems that you may have heard of include GNU/Linux, Mac OS
X and Microsoft Windows. Other devices also need operating systems such as phones, which may
use operating systems such as Android, iOS and Windows Phone.[1]
Since the operating system has to interact with the hardware on a computer system, it also has to
have specific knowledge of the hardware on a system. To allow operating systems to be used on a
variety of computers, the concept of drivers was invented. Drivers are small bits of code that can be
added and removed from the operating system in order to allow the operating system to talk to a

/conversion/tmp/activity_task_scratch/[Link]
Page 5 of 18
particular piece of hardware. In this course, we do not cover how to create such removable drivers,
and instead focus on making specific ones for the Raspberry Pi.
There are all kinds of different designs of operating systems, and this course can only just scratch
the surface. In this course we will mainly focus on getting the operating system to interact with a
variety of bits of hardware, as this is often the trickiest bit, and the part for which the least
documentation and help exists online.

2 Assembly Code
A processor can often perform millions of instructions per second, but they must be simple.
This course will be written almost exclusively in assembly code. Assembly code is code that is very
close to what the computer understands. How a computer really works is that there is a small device
called a processor which is capable of performing simple jobs like adding numbers, and there is a
set of one or more microchips called the RAM which are capable of storing numbers. When a
computer has power, the processor works through a sequence of instructions given to it by the
programmer, which cause it to change numbers in the RAM, and interact with connected hardware.
Assembly code is a translation into human readable text of those commands.
When programming normally, the programmer writes code in a programming language such as C+
+, Java, C#, Basic, etc, and then a program called the compiler translates what the programmer
wrote into assembly code, which is the further reduced into binary code[2]. Binary code is what the
computer actually understands, but it is almost impossible for humans to read. Assembly code is
much better, but it can be frustrating how few commands are possible. Remember that every
command you write in assembly code is something that the processor understands directly, and so
the commands are simple by design, as a physical circuit must process each one.

Just like with ordinary programming, there are many different assembly code languages, however
unlike ordinary programming, the reason these exist is due to the fact that there exists many
different processors, each designed to understand a different language. Thus a program written in
assembly code for one machine, will not work on a different one. For most things, this would be a
disaster as each program would have to be rewritten for every system it was used on, but for
operating systems this isn't so much of a problem, as it would have to be rewritten anyway due to

/conversion/tmp/activity_task_scratch/[Link]
Page 6 of 18
differing hardware. Nevertheless, most operating systems are written in C++ or C, so that they can
be converted more easily, and only the sections that absolutely have to be written in assembly are.
You're now ready to move on to the first lesson, Lesson 1: OK01

/conversion/tmp/activity_task_scratch/[Link]
Page 7 of 18
Lesson 1 OK01
The OK01 lesson contains an explanation about how to get started and teaches how to enable the
'OK' or 'ACT' LED on the Raspberry Pi board near the RCA and USB ports. This light was
originally labelled OK but has been renamed to ACT on the revision 2 Raspberry Pi boards.

Contents

• 1 Getting Started
• 2 The Beginning
• 3 The First Line
• 4 Enabling Output
• 5 A Sign Of Life
• 6 Happily Ever After
• 7 Pi Time

1 Getting Started
I am assuming at this point that you have already visited the Downloads page, and got the necessary
GNU Toolchain. Also on the downloads page is a file called OS Template. Please download this and
extract its contents to a new directory.

2 The Beginning
The '.s' file extension is commonly used for all forms of assembly code, it is up to us to remember
this is ARMv6.
Now that you have extracted the template, create a new file in the 'source' directory called 'main.s'.
This file will contain the code for this operating system. To be explicit, the folder structure should
look like:
build/
(empty)
source/
main.s
[Link]
LICENSE
Makefile

Open 'main.s' in a text editor so that we can begin typing assembly code. The Raspberry Pi uses a
variety of assembly code called ARMv6, so that is what we'll need to write in.
Copy in these first commands.
.section .init
.globl _start
_start:

/conversion/tmp/activity_task_scratch/[Link]
Page 8 of 18
As it happens, none of these actually do anything on the Raspberry Pi, these are all instructions to
the assembler. The assembler is the program that will translate between assembly code that we
understand, and binary machine code that the Raspberry Pi understands. In Assembly Code, each
line is a new command. The first line here tells the Assembler[1] where to put our code. The
template I provided causes the code in the section called .init to be put at the start of the output. This
is important, as we want to make sure we can control which code runs first. If we don't do this, the
code in the alphabetically first file name will run first! The .section command simply tells the
assembler which section to put the code in, from this point until the next .section or the end of the
file.
In assembly code, you may skip lines, and put spaces before and after commands to aid readability.

The next two lines are there to stop a warning message and aren't all that important. [2]

3 The First Line


Now we're actually going to code something. In assembly code, the computer simply goes through
the code, doing each instruction in order, unless told otherwise. Each instruction starts on a new
line.
Copy the following instruction.
ldr r0,=0x20200000
ldr reg,=val puts the number val into the register named reg.
That is our first command. It tells the processor to store the number 0x20200000 into the register r0.
I shall need to answer two questions here, what is a register, and how is 0x20200000 a number?
A single register can store any integer between 0 and 4,294,967,295 inclusive on the Raspberry Pi,
which might seem like a large amount of memory, but it is only 32 binary bits.
A register is a tiny piece of memory in the processor, which is where the processor stores the
numbers it is working on right now. There are quite a few of these, many of which have a special
meaning, which we will come to later. Importantly there are 13 (named r0,r1,r2,...,r9,r10,r11,r12)
which are called General Purpose, and you can use them for whatever calculations you need to do.
Since it's the first, I've used r0 in this example, but I could very well have used any of the others. As
long as you're consistent, it doesn't matter.
0x20200000 is indeed a number. However it is written in Hexadecimal notation. To learn more
about hexadecimal expand the box below:
Hexadecimal explained
So our first command is to put the number 2020000016 into r0. That doesn't sound like it would be
much use, but it is. In computers, there are an awful lot of chunks of memory and devices. In order
to access them all, we give each one an address. Much like a postal address or a web address this is
just a means of identifying the location of the device or chunks of memory we want. Addresses in

/conversion/tmp/activity_task_scratch/[Link]
Page 9 of 18
computers are just numbers, and so the number 2020000016 happens to be the address of the GPIO
controller. This is just a design decision taken by the manufacturers, they could have used any other
address (providing it didn't conflict with anything else). I know this address only because I looked it
up in a manual[3], there is no particular system to the addresses (other than that they are all large
round numbers in hexadecimal).

4 Enabling Output

Having read the manual, I know we're going to need to send two messages to the GPIO controller.
We need to talk its language, but if we do, it will obligingly do what we want and turn on the OK
LED. Fortunately, it is such a simple chip, that it only needs a few numbers in order to understand
what to do.
mov r1,#1
lsl r1,#18
str r1,[r0,#4]
mov reg,#val puts the number val into the register named reg.
lsl reg,#val shifts the binary representation of the number in reg by val places to the left.
str reg,[dest,#val] stores the number in reg at the address given by dest + val.
These commands enable output to the 16th GPIO pin. First we get a necessary value in r1, then send
it to the GPIO controller. Since the first two instructions are just trying to get a value into r1, we
could use another ldr command as before, but it will be useful to us later to be able to set any given
GPIO pin, so it is better to deduce the value from a formula than write it straight in. The OK LED is
wired to the 16th GPIO pin, and so we need to send a command to enable the 16th pin.
The value in r1 is needed to enable the LED pin. The first line puts the number 110 into r1. The mov
command is faster than the ldr command, because it does not involve a memory interaction,
whereas ldr loads the value we want to put into the register from memory. However, mov can only
be used to load certain values[4]. In ARM assembly code, almost every instruction begins with a
three letter code. This is called the mnemonic, and is supposed to hint at what the operation does.
mov is short for move and ldr is short for load register. mov moves the second argument #1 into the
first r1. In general, # must be used to denote numbers, but we have already seen a counterexample
to this.

/conversion/tmp/activity_task_scratch/[Link]
Page 10 of 18
The second instruction is lsl or logical shift left. This means shift the binary representation for the
first argument left by the second argument. In this case this will shift the binary representation of
110 (which is 12) left by 18 places (making it 10000000000000000002=26214410).

If you are unfamiliar with binary, expand the box below:


Binary explained

Once again, I only know that we need this value from reading the manual[3]. The manual says that
there is a set of 24 bytes in the GPIO controller, which determine the settings of the GPIO pin. The
first 4 relate to the first 10 GPIO pins, the second 4 relate to the next 10 and so on. There are 54
GPIO pins, so we need 6 sets of 4 bytes, which is 24 bytes in total. Within each 4 byte section,
every 3 bits relates to a particular GPIO pin. Since we want the 16th GPIO pin, we need the second
set of 4 bytes because we're dealing with pins 10-19, and we need the 6th set of 3 bits, which is
where the number 18 (6×3) comes from in the code above.
Finally the str 'store register' command stores the value in the first argument, r1 into the address
computed from the expression afterwards. The expression can be a register, in this case r0, which
we know to be the GPIO controller address, and another value to add to it, in this case #4. This
means we add 4 to the GPIO controller address and write the value in r1 to that location. This
happens to be the location of the second set of 4 bytes that I mentioned before, and so we send our
first message to the GPIO controller, telling it to ready the 16th GPIO pin for output.

5 A Sign Of Life
Now that the LED is ready to turn on, we need to actually turn it on. This means sending a message
to the GPIO controller to turn pin 16 off. Yes, turn it off. The chip manufacturers decided it made
more sense[5] to have the LED turn on when the GPIO pin is off. Hardware engineers often seem to
take these sorts of decisions, seemingly just to keep OS Developers on their toes. Consider yourself
warned.
mov r1,#1
lsl r1,#16
str r1,[r0,#40]
Hopefully you should recognise all of the above commands, if not their values. The first puts a 1
into r1 as before. The second shifts the binary representation of this 1 left by 16 places. Since we
want to turn pin 16 off, we need to have a 1 in the 16th bit of this next message (other values would
work for other pins). Finally we write it out to the address which is 4010 added to the GPIO
controller address, which happens to be the address to write to turn a pin off (28 would turn the pin
on).

6 Happily Ever After


It might be tempting to finish now, but unfortunately the processor doesn't know we're done. In
actuality, the processor never will stop. As long as it has power, it continues working. Thus, we need

/conversion/tmp/activity_task_scratch/[Link]
Page 11 of 18
to give it a task to do forever more, or the Raspberry Pi will crash (not much of a problem in this
example, the light is already on).
loop$:
b loop$
name: labels the next line name.
b label causes the next line to be executed to be label.
The first line here is not a command, but a label. It names the next line loop$. This means we can
now refer to the line by name. This is called a label. Labels get discarded when the code is turned
into binary, but they're useful for our benefit for referring to lines by name, not number (address).
By convention we use a $ for labels which are only important to the code in this block of code, to
let others know they're not important to the overall program. The b (branch) command causes the
next line to be executed to be the one at the label specified, rather than the one after it. Therefore,
the next line to be executed will be this b, which will cause it to be executed again, and so on
forever. Thus the processor is stuck in a nice infinite loop until it is switched off safely.
The new line at the end of the block is intentional. The GNU toolchain expects all assembly code
files to end in an empty line, so that it is sure you were really finished, and the file hasn't been cut
off. If you don't put one, you get an annoying warning when the assembler runs.

7 Pi Time
So we've written the code, now to get it onto the pi. Open a terminal on your computer and change
the current working directory to the parent directory of the source directory. Type make and then
press enter. If any errors occur, please refer to the troubleshooting section. If not, you will have
generated three files. [Link] is the compiled image of your operating system. [Link] is a
listing of the assembly code you wrote, as it was actually generated. This is useful to check that
things were generated correctly in future. The [Link] file contains a map of where all the labels
ended up, which can be useful for chasing around values.
To install your operating system, first of all get a Raspberry PI SD card which has an operating
system installed already. If you browse the files in the SD card, you should see one called
[Link]. Rename this file to something else, such as kernel_linux.img. Then, copy the file
[Link] that make generated onto the SD Card. You've just replaced the existing operating
system with your own. To switch back, simply delete your [Link] file, and rename the other one
back to [Link]. I find it is always helpful to keep a backup of you original Raspberry Pi
operating system, in case you need it again.
Put the SD card into a Raspberry Pi and turn it on. The OK LED should turn on. If not please see
the troubleshooting page. If so, congratulations, you just wrote your first operating system. See
Lesson 2: OK02 for a guide to making the LED flash on and off.

/conversion/tmp/activity_task_scratch/[Link]
Page 12 of 18
1. [1]^ OK, I'm lying it tells the linker, which is another program used to link several assembled
files together. It doesn't really matter.
2. [2]^Clearly they're important to you. Since the GNU toolchain is mainly used for creating
programs, it expects there to be an entry point labelled _start. As we're making an operating
system, the _start is always whatever comes first, which we set up with the .section .init
command. However, if we don't say where the entry point is, the toolchain gets upset. Thus,
the first line says that we are going to define a symbol called _start for all to see (globally),
and the second line says to make the symbol _start the address of the next line. We will
come onto addresses shortly.
3. [3]^^ This
tutorial is designed to spare you the pain of reading it, but, if you must, it can be
found here [Link]. For added confusion, the manual uses a different addressing
system. An address listed as 0x7E200000 would be 0x20200000 in our OS.
4. [4]^Only values which have a binary representation which only has 1s in the first 8 bits of
the representation. In other words, 8 1s or 0s followed by only 0s.
5. [5]^ A hardware engineer was kind enough to explain this to me as follows:
The reason is that modern chips are made of a technology called CMOS, which stands for
Complementary Metal Oxide Semiconductor. The Complementary part means each signal is
connected to two transistors, one made of material called N-type semiconductor which is
used to pull it to a low voltage and another made of P-type material to pull it to a high
voltage. Only one transistor of the pair turns on at any time, otherwise we'd get a short
circuit. P-type isn't as conductive as N-type, which means the P-type transistor has to be
about 3 times as big to provide the same current. This is why LEDs are often wired to turn
on by pulling them low, because the N-type is stronger at pulling low than the P-type is in
pulling high.
There's another reason. Back in the 1970s chips were made out of entirely out of N-type
material ('NMOS'), with the P-type replaced by a resistor. That means that when a signal is
pulled low the chip is consuming power (and getting hot) even while it isn't doing anything.
Your phone getting hot and flattening the battery when it's in your pocket doing nothing
wouldn't be good. So signals were designed to be 'active low' so that they're high when
inactive and so don't take any power. Even though we don't use NMOS any more, it's still
often quicker to pull a signal low with the N-type than to pull it high with the P-type. Often
a signal that's 'active low' is marked with a bar over the top of the name, or written as
SIGNAL_n or /SIGNAL. But it can still be confusing, even for hardware engineers!

/conversion/tmp/activity_task_scratch/[Link]
Page 13 of 18
GNU Toolchain
1.1 Microsoft Windows
For Microsoft Windows, I use the YAGARTO and MinGW packages.
Please visit the YAGARTO website and download and install YAGARTO Tools and YAGARTO
GNU ARM toolchain for Windows. MinGW can be downloaded from here. You may need to restart
your computer for this to work (honestly).
Note: YAGARTO must be installed to a path with no spaces, e.g. 'C:\YAGARTO\' not 'C:\Program
Files\YAGARTO\'.

1.2 Mac OS X
For Mac OS X, I use the YAGARTO packages.
Please visit the YAGARTO website and download and install YAGARTO GNU ARM toolchain for
Mac OS X.

1.3 Linux
There are a number of options for getting the GNU ARM toolchain on Linux.

1.3.1 Prebuilt
You can download a prebuilt toolchain using the following commands:
$ wget [Link]
[Link].bz2
--2012-08-16 18:26:29--
[Link]
[Link].bz2
Resolving [Link] ([Link])... [Link],
2001:630:212:267::80:14
Connecting to [Link] ([Link])|[Link]|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 32108070 (31M) [application/x-bzip2]
Saving to: `[Link].bz2'

100%[======================================>] 32,108,070 668K/s in 67s

2012-08-16 18:27:39 (467 KB/s) - `[Link].bz2' saved


[32108070/32108070]

$ tar xjvf [Link].bz2


arm-2008q3/arm-none-eabi/
arm-2008q3/arm-none-eabi/lib/
arm-2008q3/arm-none-eabi/lib/libsupc++.a
arm-2008q3/arm-none-eabi/lib/libcs3arm.a
...
arm-2008q3/share/doc/arm-arm-none-eabi/info/[Link]
arm-2008q3/share/doc/arm-arm-none-eabi/info/[Link]
arm-2008q3/share/doc/arm-arm-none-eabi/[Link]

/conversion/tmp/activity_task_scratch/[Link]
Page 14 of 18
$ export PATH=$PATH:$HOME/arm-2008q3/bin

1.3.2 apt-get
Some Linux distributions including Ubunutu offer the ARM GNU Toolchain via apt-get. Run the
following command:
$ sudo apt-get install gcc-arm-none-eabi

1.3.3 Build from source


Linux users may wish to build their own cross-compiler toolchain. This will require downloading
and building the binutils and gcc packages from GNU. The binutils package contains the basic tools
for building executables, including the assembler, the linker, a disassembler, and tools to manipulate
object and binary files. These two packages are built separately but should be installed into the
same destination directory. Make an area in your home directory to build your development kit.
$ cd
$ mkdir devkit
$ mkdir devkit-build
$ cd devkit-build

Download the [Link].bz2 package from GNU binutils into the devkit-build directory and
uncompress it with the tar jxv [Link].bz2 command. Replace the [Link] with the current
version number, such as 2.24 or 2.25 which have both been used successfully for this course. A note
about make commands: if your development system has multiple processors or cores, you can use
then to build and compile in parallel by adding -j #cores A note about the --program-prefix option:
the trailing dash (-) is necessary to make sure the command names match helper templates used
later in the course. Build the tools with these steps, replacing [Link] with your specific binutils
version number:
$ cd $HOME/devkit-build
$ mkdir binutils-build
$ cd binutils-build
$ ../[Link]/configure --prefix=$HOME/devkit/ \
--program-prefix=arm-none-eabi- --target=arm-none-eabi --disable-nls
$ make
$ make check
$ make install
$ cd ..

The gcc package contains a C compiler. Download the [Link].bz2 package from GCC, The
GNU Compiler Collection into the devkit-build directory and uncompress it with the tar jxv gcc-
[Link].bz2 command. Replace the [Link] with the current version number, such as 4.8.2 or 5.1
which have both been used successfully for this course. Build the tools with these steps, replacing
[Link] with your specific gcc version number, and add the -j #cores option, if desired
$ cd $HOME/devkit-build
$ mkdir gcc-build
$ cd gcc-build
$ ../[Link]/configure --prefix=$HOME/devkit/ \
--program-prefix=arm-none-eabi- --target=arm-none-eabi --disable-nls \

/conversion/tmp/activity_task_scratch/[Link]
Page 15 of 18
--without-headers --with-newlib --with-as=$HOME/devkit/bin/arm-none-eabi-as \
--with-ld=$HOME/devkit/bin/arm-none-eabi-ld --enable-languages=c
$ make all-gcc
$ make check all-gcc
$ make install-gcc
$ make all-target-libgcc
$ make check all-target-libgcc
$ make install-target-libgcc
$ cd ..

Now that you have a custom cross-compiler in your $HOME/devkit directory, you will need to add
this directory to your shell's PATH environment variable to be able to run the tools later in the
course. Each time you are ready to use the toolchain, run the following shell command:
$ export PATH=$PATH:$HOME/devkit/bin

2 OS Template
The OS Template file is one I have created which contains enough instructions for the compiler to
create a basic Operating System for the Raspberry Pi. It contains no actual assembly code, just a
Makefile script and a Linker script.
Download Template.
Download Template for USB Operating System.

3 Lesson Solutions
3.1 Lesson 1: OK01
Full Solution

3.2 Lesson 2: OK02


Full Solution

3.3 Lesson 3: OK03


Full Solution
Extension Solution

3.4 Lesson 4: OK04


Full Solution

3.5 Lesson 5: OK05


Full Solution

/conversion/tmp/activity_task_scratch/[Link]
Page 16 of 18
3.6 Lesson 6: Screen01
Full Solution

3.7 Lesson 7: Screen02


Full Solution

3.8 Lesson 8: Screen03


Full Solution

3.9 Lesson 9: Screen04


Full Solution

3.10 Lesson 10: Input01


Lesson Template
Full Solution

3.11 Lesson 11: Input02


Full Solution

4 Example Operating Systems


Here are some example operating systems for you to learn from. If you've coded an operating
system that you think others could benefit from, please email me at awc32@[Link].
Table 4.1 Example Operating Systems
Name Author Description
This example is a small extension to Input01, featuring a coloured text
Coloured
Alex Chadwick terminal, rather than a black and white one. Special characters are used
CLI
to change the colour.
Marten van der
Pascal OSs A few small OSs written is Pascal based on this course, and beyond.
Honing

5 Fonts
Below are some fonts for you to use in your Operating Systems.

5.1 Monospace, Monochrome 8x16


These fonts are the simplest ones available. They use a 1 to represent a white pixel, a 0 to represent
a black pixel, and having representations for the first 128 ASCII characters. The use 16 bytes per
character, arranged such that each byte is one complete row, going right to left with higher bits,
going top to bottom with later bytes.

/conversion/tmp/activity_task_scratch/[Link]
Page 17 of 18
The tutorial used to suggest these fonts were stored in the opposite direction along the rows. The
lowest bit is the rightmost pixel, the highest bit is the leftmost.
Table 5.1.1 Monospace, Monochrome 8x16 Fonts
Font Image License

Free to use/redistribute commercially. Cannot be titled


Monospace Default
'Bitstream' or 'Vera'.

Liberation Mono SIL Open Font License.

Liberation Serif
SIL Open Font License.
Mono

6 USB driver (CSUD) Source


The source code for CSUD (Chadderz's Simple USB driver) used in the tutorials is available here:
[Link]

/conversion/tmp/activity_task_scratch/[Link]
Page 18 of 18

You might also like