January 2, 2022
osv
All of our labs are based on osv
. osv
is a new experimental operating system kernel for teaching the principles and practice of operating systems. osv
’s baseline code is a complete, bootable operating system. It provides some simple system calls that it is capable of running a minimal shell program. This lab is about exploring the osv codebase and generally getting oriented. Your task for futures labs will be to make osv
complete and also add a few functionalities.
osv
You will need to be on a Linux computer to work with osv
. See the section on programming environments on the course web page. If you need a refresher on navigating a Linux command line, see this tutorial or the other resources on the course web page.
Instead of developing the operating system on a real, physical personal computer (PC), we will use a program that faithfully emulates a complete PC: the code you write for the emulator will boot on a real PC too. Using an emulator simplifies debugging; you can, for example, set break points inside of the emulated x86_64 architecture, which is difficult to do with the silicon version of an x86_64 architecture. In osv
, we will use the qemu
Emulator, a modern and fast emulator. If you are working on your local machine (mantis
already has these installed) you will likely need to install qemu
with
$ sudo apt install qemu qemu-system-x86
or the equivalent if you’re using a non-Debian/Ubuntu Linux.
To acquire the osv
code that will be the basis for the labs, you will use git. I have set up the repository (i.e., a collection of files managed by git) on the CS mantis
server, so you will clone the repository from there to get the code. Run the command below to do so (replacing YOUR_CARLETON_USERNAME
with your own username—the part of your Carleton email before the ‘@’). If prompted about authenticity of mantis
, enter yes
to continue. Type in your Carleton password when prompted.
$ git clone ssh://YOUR_CARLETON_USERNAME@mantis.mathcs.carleton.edu/web-pages/www.cs.carleton.edu/faculty/awb/cs332/osv-w22
This will create a osv-w22
directory wherever you ran that command.
To learn more about git, take a look at Git resources on the course web page.
osv
Run make
in the osv-w22
directory to build the osv
kernel. Now you’re ready to run qemu
. You’ll need to supply the files build/fs.img
and build/osv.img
, created by the make
process, as the contents of the emulated PC’s virtual hard disk. Those hard disk images contain our boot loader build/arch/x86_64/boot
, our kernel build/kernel/kernel.elf
and a list of user applications in build/user
. Fortunately, make
can take care of this too. Run make qemu
to run qemu
with the options required to set the hard disk and direct serial port output to the terminal. Some text should appear in the terminal:
E820: physical memory map [mem 0x126000-0x1FFE0000]
[0x0 - 0x9FC00] usable
[0x9FC00 - 0xA0000] reserved
[0xF0000 - 0x100000] reserved
[0x100000 - 0x1FFE0000] usable
[0x1FFE0000 - 0x20000000] reserved
[0xFFFC0000 - 0x100000000] reserved
cpu 0 is up and scheduling
cpu 1 is up and scheduling
OSV initialization...Done
$
Press Ctrl-a x to exit qemu
.
If you see warnings about TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]
, you can safely ignore them.
osv
├── arch(x86_64) // all architecture dependent code for different architecture
│ └── boot // bootloader code
│ └── include(arch) // architecture dependent header files (contain architecture specific macros)
│ └── kernel // architecture dependent kernel code
│ └── user // architecture dependent user code (user space syscall invocation code)
│ └── Rules.mk // architecture dependent makefile macros
├── include // all architecture independent header files
│ └── kernel // header files for kernel code
│ └── lib // header files for library code, used by both kernel and user code
├── kernel // the kernel source code
│ └── drivers // driver code
│ └── mm // memory management related code, both physical and virtual memory
│ └── fs // file system code, generic filesys interface (VFS)
│ └── sfs // a simple file system implementation implementing VFS
│ └── Rules.mk // kernel specific makefile macros
├── user // all the source code for user applications
│ └── lab* // tests for lab*
│ └── Rules.mk // user applications makefile macros
├── lib // all the source code for library code
│ └── Rules.mk // user applications makefile macros
├── tools // utility program for building osv
└── Makefile // Makefile for building osv kernel
After compilation (make
), a new folder build
will appear, which contains the kernel and fs image and all the intermediate binaries (.d, .o, .asm).
osv
The purpose of the first exercise is to get you started with qemu
and qemu
/gdb
debugging.
The definitive reference for x86_64 assembly language programming is Intel’s instruction set architecture reference is Intel 64 and IA-32 Architectures Software Developer’s Manuals. It covers all the features of the most recent processors that we won’t need in class but you may be interested in learning about. An equivalent (and often friendlier) set of manuals is AMD64 Architecture Programmer’s Manual. Save the Intel/AMD architecture manuals for later or use them for reference when you want to look up the definitive explanation of a particular processor feature or instruction.
You don’t have to read them now, but you may want to refer to some of this material when reading and writing x86_64 assembly.
gdb
gdb
can be used as a remote debugger for osv
. We have provided a gdbinit file for you to use as ~/.gdbinit
. It connects to a port that qemu will connect to when running make qemu-gdb
and loads in kernel symbols. You can generate your ~/.gdbinit
using the following command.
$ cp arch/x86_64/gdbinit ~/.gdbinit
To attach gdb
to osv
, you need to open two separate terminals. Both of them should be in the osv-w22
root directory. In one terminal, type make qemu-gdb
. This starts the qemu process and wait for gdb
to attach. In another terminal, type gdb
. Now the gdb
process is attached to qemu.
In osv
, when bootloader loads the kernel from disk to memory, the CPU operates in 32-bit mode. The starting point of the 32-bit kernel is in arch/x86_64/kernel/entry.S
. entry.S
sets up 64-bit virtual memory and enables 64-bit mode. You don’t need to understand entry.S
. entry.S
jumps to main
function in kernel/main.c
which is the starting point of 64-bit OS.
After attaching the qemu instance to gdb
, set a breakpoint at the entrance of osv
by typing in b main
. You should see a breakpoint set at main
in kernel/main.c
. Then type c
to continue execution. osv
will go through booting and stop at main
. Which line of code in main
prints the physical memory table? (Hint: use the n
comand to have gdb
execute one line of C code at a time.)
We can examine memory using gdb
’s x
command. The gdb
manual has full details, but for now, it is enough to know that the command x/nx ADDR
prints n
words of memory at ADDR
. (Note that both ‘x’s in the command are lowercase, the second x tells gdb to display memory content in hex.)
To examine instructions in memory (besides the immediate next one to be executed, which gdb
prints automatically), use the x/i
command. This command has the syntax x/ni ADDR
, where n
is the number of consecutive instructions to disassemble and ADDR
is the memory address at which to start disassembling.
Repeat the previous process to break at main
. What’s the memory address of main
(p main
)? Does gdb
work with real physical addresses? Explain your answer.
You may have noticed that when gdb
hit your breakpoint, the message specified a thread:
Thread 1 hit Breakpoint 1, main () at kernel/main.c:34
osv
boots up with multiple threads, which you can see by running info threads
. We’ll talk a lot more about threads in the coming weeks—the basic idea is that each thread is an independent unit of execution, which enables simultaneous computation. For now the goal is to explore gdb
’s capabilities when it comes to multi-threaded programs. At the start of main
, the output of the info threads
command indicates that one thread is halted. What function starts it running? What main function does the second thread start in? What happens if you restart and set a breakpoint for that function?
Submit a file lab0.txt
with your answers to the questions listed above to the CS 332 Gradescope.
This lab will be graded out of 50 points, as shown in the table below. Comments explaining your approach can help earn partial credit.
Test | Points |
---|---|
Submission | 20 points |
Question #1 | 10 points |
Question #2 | 10 points |
Question #3 | 10 points |