Lab Assignment 0 - Hello osv
Deadlines
- Due: Monday, January 8, at 4:00pm
Introduction
All of our assignments are based on osv
, which is an eperimental operating system kernel used for teaching the principles and practie of operating systems. The baseline code for osv
is a complete, bootable operating system. It provides some simple system calls that make it capable of running a minimal shell program.
Goals
This assignment is about exploring the osv
codebase and generally getting oriented. Your task for future assignments will be to make osv
complete and also add a few additional functionalities.
Collaboration policy
For this and most other assignments, you are encouraged to talk at a high level with your classmates. However, any low-level discussions (e.g., that involve actual code instead of ideas) should be with at most one other student in the class.
See our class collaboration policy for more information.
Getting osv
Linux environment
You will need to be on a Linux computer to work with osv
; your work will be done in C. Lab assignments need to be completed on a x86-64 Linux machine with gcc
and qemu
. The CS department server mantis
is already set up to work; otherwise, you can get your local computer working.
If you want to work on your local computer, and it’s Mac or Windows, you will need to set up a separate Linux environment.
- On Windows 10/11, this is pretty straightforward due to Windows Subsystem for Linux. Follow this guide to set it up.
- On Mac or earlier versions of Windows, you will need a Linux virtual machine (VM). Instructions are available for the official CS VM on the Carleton wiki. Note that it’s pretty large (11GB to download, and ~30 GB once expanded, as it has lots of handy stuff pre-installed), so you may want to use Xubuntu VM from osboxes.org instead; you’d want the free VirtualBox to run the VM.
If you need a refresher on navigating a Linux command line, see this tutorial or the Unix resources on the course web page.
Instead of developing the operating system on a real, physical personal computer (PC), we will use a program called an emulator that (mostly) 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 breakpoints inside of the emulated x86-64 architecture, which is difficult to do with the silicon version of an x86-64 arhitecture.
In osv
, we will use qemu
, 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 (recall that $
is the prompt–don’t type that):
$ sudo apt install qemu qemu-system-x86
or the equivalent if you’re using a non-Debian/Ubuntu Linux distribution (a.k.a. distro).
Cloning the git
repository
To acquire the osv
code that will be the basis for the assignments in this course, you will need to use git
. I have set up the repository (i.e., a collection of files with versions managed by git
) on the CS mantis
server, so you will clone the repo 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. (Note that it may not show anything as you type–just be careful and hit Return
/Enter
when you’re done`.)
$ git clone ssh://YOUR_CARLETON_USERNAME@mantis.mathcs.carleton.edu:/web-pages/www.cs.carleton.edu/faculty/tamert/courses/cs332-w24/osv-w24
This will create a osv-w24
directory wherever you ran that command.
To learn more about git
, take a look at the git section of the course resources page.
Running osv
Run make
in the osv-w24
directory to build the osv
kernel. Make sure the build successfully completes before continuing.
Here is what my successful build looks like (it’s long, so there is more where the ...
is):
...
ild/user/lab4/sbrk-small build/user/lab4/malloc-test build/user/lab4/sbrk-lar
ge build/user/lab4/bad-mem-access build/user/cat build/user/lab5/cow-small
build/user/lab5/cow-large build/user/lab5/cow-multiple build/user/lab5/cow-lo
w-mem build/user/lab2/race-test build/user/lab2/fork-fd build/user/lab2/wait
-twice build/user/lab2/fork-tree build/user/lab2/exit-test build/user/lab2/f
ork-test build/user/lab2/wait-bad-args build/user/ls build/user/sh build/us
er/lab1/read-bad-args build/user/lab1/readdir-test build/user/lab1/open-twice
build/user/lab1/dup-read build/user/lab1/read-small build/user/lab1/fstat-t
est build/user/lab1/fd-limit build/user/lab1/write-bad-args build/user/lab1/
open-bad-args build/user/lab1/close-test build/user/lab1/dup-console
tamert@mantis:~/cs332/osv-w24$
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 mulated PC’s virtual hard disk. You don’t have to worry too much about this yet, but just so you know, 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 for us, too (read the Makefile
to learn more). 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, like this:
E820: physical memory map [mem 0x126000-0x1FFE0000]
[0x0 - 0x9FC00] usable
[0x9FC00 - 0xA0000] reserved
[0xF0000 - 0x100000] reserved
[0x100000 - 0x1FFE0000] usable
[0x1FFE0000 - 0x20000000] reserved
cpu 0 is up and scheduling
cpu 1 is up and scheduling
OSV initialiation...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.
Organization of source code
When you clone the repo, it should have the following structure:
osv
├── arch(x86_64) // all architecture-dependent code for different architectures
│ └── 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 // all 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 source code for user applications
│ └── lab* // tests for assginment* (e.g., lab0 has tests for assignent0)
│ └── Rules.mk // user applications makefile macros
├── lib // all 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 (running make
), a new folder build
will appear, which contains the kernel and fs image and all of the intermediate binaries (.d
, .o
, .asm
).
Part 1: Debugging osv
The purpose of this first exercise is to get you started with qemu
and qemu
+gdb
debugging.
A note on x86-64 assembly
The definitive reference for x86-64 assembly language programming using Intel’s instruction set architecture reference is Intel 64 and IA-32 Architecture Software Developer’s Manuals. It covers all of the features of the most recent processes that we won’t need in class, but you may be interested in learning about anyway.
An equivalent (and perhaps 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
You can use gdb
as a remote debugger for osv
, just as you did in CS 208 for various assignments. We have provided a gdbinit
file for you to use as your ~/.gdbinit
file (look up “Linux dotfiles” during a weekend internet rabbithole sometime if you’re curious). This file connects to a port that qemu
will connect to when running make qemu-gdb
, and also 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-w24
root directory. In one terminal, type make qemu-gdb
. This starts the qemu
process and waits for gdb
to attach. In another terminal, type gdb
. Now the gdb
process is attached to qemu
. (As another rabbithole, you can look up tmux
as a way to easily have two terminals available in one window.)
In osv
, when the 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
. The file entry.S
sets up 64-bit virtual memory (more on that later this term) and enables 64-bit mode. You don’t need to understand entry.S
; it jumps to the main
function in kernel/main.c
, which is the starting point of our 64-bit OS.
Question #1
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
command to have gdb
execute one line of C code at a time.)
Note: As part of your answer to Question #1 in your submission, make sure you explain how you determined the answer. What did you look for and/or find in gdb
and the source code that led you to your answer?
Question #2
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 the n
32-bit “words” of memory starting at address ADDR
. (Note that both x
s in the command are lowercase; the second x
tells gdb
to display the mmeory contents in hexadecimal.)
To examine instructions in memory (besides the immediate next one to be executed, which gdb
prints automatically), you can 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 is the memory address of main
(hint: use p main
)? Does gdb
work with real physical addresses? Explain your answer.
Question #3
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
When osv
boots up, it has multiple threads, as you can see by running info threads
within gdb
. We’ll talk a lot more about threads in the coming weeks. For now, just know that the basic idea is that each thread is an independent unit of execution, which enables simultaneous computation.
For this assignment, I just want you 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.
Explore and answer the following questions, again with explanations of how you got to your answers:
- What function starts the thread running?
- What main function does the second thread start in?
- What happens if you restart
qemu
/gdb
and set a breakpoint for that function?
Submission
For this assignment, you should submit a file a0.txt
with your answers to the questions listed above to the CS 332 Gradescope.
Evaluation
This assignment will be graded out of 50 points, as shown in the table below. Comments explaining your approach are always expected, and can help earn partial credit if you don’t fully complete a part of the assignment.
Grade breakdown:
Component Points
--------------------------
Submission 20 points
Question #1 10 points
Question #2 10 points
Question #3 10 points