PseudOS — A baremetal RaspPi OS

Now that I’ve got a bit of time, I thought I’d do a debrief of a couple of cool projects that I’ve worked on this past year. First up, PseudOS, a baremetal Raspberry PI OS that I wrote with some friends for our Software Systems final project.

(We were really sleep deprived when making the final video, apologies for any strange noises we make.)

It doesn’t look really amazing, because we didn’t really implement any OS features other than UART and a basic calculator program. However, we did do this all baremetal. What is baremetal, you ask? Well, it means that the code we wrote interacted with the RaspPi at the hardware level. We modified an Assembly boot file to give us control over the hardware registers, and wrote a kernel in C to provide the actual OS functionality. This website was an amazing resource for us through the whole process.

Here’s the slide deck we made for our final presentation. It might be more entertaining to read than my wall of text below, haha:

It’s commonly said that all computers do is shuffle around 0s and 1s, which is actually pretty true. So, an OS has to be able to properly manage the shuffling of those bits to generate meaningful information. We do this by getting access to the necessary registers, and doing work on the data via basic binary arithmetic. A registry is something that stores information that can be accessed via an address, and manipulating the bytes in the registry is what results in all the higher level functions. At its core, all a computer does is ADD, SUB, MULT, JUMP, MOV. (JUMP moves the stack pointer from one memory address to another. MOV moves stuff from one memory address to another.) Ah, but I digress, this is more Computer Architecture territory than Software Systems.

Anyhow, we wrote a kernel that would initiate a UART port to allow communication to the RaspPi via PuTTY. We didn’t write any video drivers, so PseudOS itself is completely UART based and must be accessed via PuTTY when running on the RaspPi, or through the text interface when virtualized through QEMU. I/O with PseudOS is done entirely through UART, via the functions uart_puts() and uart_gets(). Because this was baremetal, we had to implement a lot of basic functionality. We wrote a pseudo-command line to allow control of the OS, which will allow the user to write anything in the 80-character array that automatically checks for overflow. Currently, the OS can recognize four commands, “calc”, “blink”, “help”, and “stop”. You can see this functionality in the video above.

The major part of the project that I worked on was the calculator. In order to demonstrate that our OS could do something interesting, the calculator application lets the user add, subtract, multiple, or divide with positive or negative integers. The challenge for this was largely in converting arrays of integers into strings and vice versa because the math could only work on integers, while uart_puts() only accepted strings. Solving the suspiciously interview-question-esque problem was actually pretty fun. The solutions for both problems were surprisingly similar, as seen below:

convert_to_int takes a character array of ASCII characters like [49,50,51] and converts it into a single integer, 123.

convert_to_string take an integer like 123 and converts it into an ASCII character array [49, 50, 51]

Because we didn’t have malloc() or free() we weren’t able to actually pass stuff around through pointers. A workaround for this was to simply pass everything around instead of relying on whatever the functions were returning to make sure we had the right version of everything at each point in the code.

The last order of business was to get some form of multiprocessing happening. All operating systems have to handle multiple things in parallel, and ours would be no different because we wanted to be kind of legit. To do this, we demonstrated that we could have the blinking LED on the RaspPi happening at the same time as the calculator program. This boiled down to rewriting the UART to be interrupt-driven instead of hogging the request queue all the time. Essentially, we wrote the OS such that its default state was an infinitely running loop that would blink an LED. Any I/O over UART triggers an interrupt that will run the interrupt handler that we wrote before returning to the LED blinking loop, a process that happens so fast that it appears to be simultaneous. (To be honest though, nothing in your computer is actually happening “simultaneously”, its just that the CPU is switching between processes so fast that it appears that everything is happening at once :P) 

All in all, this was a really fun project. I learned a lot, and have gotten over my fear of pointers thanks to this class. Honestly though, I probably won’t do much bare metal programming in the future, I’m too spoiled on C++ and Python to write all of my own functions forever, haha. 🙂

-Sophie

Leave a Reply

Your email address will not be published. Required fields are marked *