Calendar‎ > ‎

Boot sequence

Few people these days write an operating system from scratch. But let's say you were one of those cow-girls or cow-boys who wanted to venture on this fascinating quest. We will walk through an exercise to figure out how to make the operating system boot: to make it mature to the point that it can run "normal" C code. Understanding this process will give you confidence that you can one day write your own OS from scratch.

A lot of what happens in the boot sequence is hardware-specific

Remember our discussion about how the program begins to run: it needs to be loaded into memory and the address of the first instruction to execute must be placed into a special CPU register, usually a program counter (PC) register. Usually the operating system is the one that sets that up for a user program. What happens if the operating system is not running yet? What if we turn on a machine with nothing running on it? How does it get to run anything? In other words, how does it boot

A newly powered machine begins executing from a specified address. This address is located in ROM and is hard-coded for each machine. 
  • All in all, hardware expects certain information in certain hardwired memory location. For instance: 
    • It begins executing at a fixed address.
    • It expects certain things (like exception handling code) to be at certain locations in memory. 
    • It expects certain virtual addresses to be mapped to certain physical addresses. 
  • Let's look at the following excerpt from the LAMEbus documentation to see where the MIPS processor that OS161 runs on expects to find the operating system code to execute. The documentation implies understanding of the concept of the virtual address space, so we will first have a short discussion to understand what it is. (If you missed it, look this up in the text book or on the Internet).

Q1: Based on that, can you tell what is the maximum amount of virtual memory that a user program can use? 
Q2: Where does the processor expect to find the very first instruction to run, after it is powered on? 
Q3: What is an exception address and why is it critical for the boot sequence?
Q4: What is the difference between "cached" vs "uncached" memory? 
Q5: Why is the Cached LAMEbus area labeled as "not useful"? 

LAMEbus Mapping area is linked to the hardware registers -- it is used to communicate with the hardware

  • LAMEbus mapping area is a special area of memory used to communicate with the hardware. 
  • A read from certain parts of this memory causes a read from the device register. 
  • A write into a certain part of this memory causes a write into the device register, which can make the device do something. 
Find the description of LAMEbus registers in the manual and answer the following questions:

Q6: How can the operating system find out the amount of physical RAM available on the system? 
Q7: What is the maximum number of CPUs supported by the MIPS R2000 architecture? 

Now take the time to read through  through the sections of the manual titled "Bus Power-up" and "Boot ROM" to understand how the kernel gets to run after the processor is reset. After that we will go through an exercise to figure out how the code in the boot ROM knows where to jump in the actual kernel binary that it loads.

Now let's look at the actual bootstrap code in OS161 to see how it interacts with the MIPS R2000 machine according to the rules we just learned.

Let us begin with main.c -- it is located in ~/os161/src/kern/main/main.c.
Look at the boot() function. In particular, let us trace all the way through ram_bootstrap(). Find the lowest-level function that reads the size of the RAM from the hardware. 

Q8: How does this function find out the size of RAM?

The boot function is called from kmain(), but how does kmain() actually get called? To find out, take a look at start.SThis is the very first code that runs on the system! There is a lot of assembly code there, and though it is not the most human-friendly language, do try to understand what it is trying to do -- what is the main purpose of that code? Now, answer this question:

Q9: How does kmain() get called? 

Look more closely at start.S

In particular note the following things: 
Q10: At what virtual address is the kernel loaded? 
Q11: At what address are exception handlers placed?   
Q12: What values are EXADDR_UTLB and EXADDR_GENERAL defined to? Do they correspond to any values specified in the LAMEbus manual? 

As you have seen, the code in start.S does all the arcane stuff that has to talk to the hardware and manually set up the memory so that the right things are found at just the right places. The bootstrap functions called afterwards are mostly "normal" C functions that do "conventional" things, like setting up data structures, etc. 

OS161 UBC,
Sep 13, 2018, 11:12 AM