ASST0: Getting warmed up
Contents
- Due Dates and Mark Distribution
- Introduction
- Getting Started
- Reading Component
- Working with the Kernel
- Your Task
- Submitting
1. Due Time & Date and Mark Distribution
Due Time & Date: 8am (08:00), Fri March 1st (Week 2)
Marks: Worth 10 marks (contributing to the 100 potential class marks available in the course)
This warmup is done as an individual.
No bonuses apply for this warmup exercise.
2. Introduction
The aim of the warmup exercise is to have you familiarise yourself with the environment that you will be using for the more substantial assignments. The exercise consists of two parts: an assessed exercise for marks, and a non-assessable component. The non-assessable component consists of a set of directed questions to give you practice navigating and reading the code base. The answers to this code reading Q & A component of the exercise are available on the wiki (improvable by you the students). The assessable exercise consists of you: learning how to build and run OS/161, making a very minor change to the existing OS to fix a bug, and learning the submission process. The change is conceptually trivial, so you can view this exercise as us giving away marks as an incentive for you to get the assignment environment up and running early in the trimester in preparation for the assignments.
Note that this exercise is not indicative of the level of difficulty of the actual assignments. The assignments are much more challenging.
The OS/161 Environment
This assignment will introduce you to the components of the environment you will use during the semester:
- OS/161, the educational operating system you will modify to implement the assignments.
- System/161, the MIPS machine simulator that OS/161 runs on.
- GDB, a debugger that will make your life much easier.
The introduction to the OS/161 system explains how the components of the OS/161 system fit together, and contains important information about using the tools. You should take the time to read it now.
git
git is a source code management system used to track changes to a piece of software. We make use of git in this course to allow you to manage the large code base, and recover from potential problems. git keeps a copy of each committed change to your OS/161 files. It allows you to track the changes you have made, and more importantly, rollback to a known state if things get out of hand.git also enables you and your partner to work on the same code repository in a coordinated way. You can even work on versions of your code stored at home and at CSE.
git is a large system of which you need to know only a small subset. We will give you directions for the parts you need to know, but feel free to expand your knowledge as git is a common tool worth knowing, and is used widely in industry.
3. Getting Started
Setting up your development environment
See the Wiki for details of how to set up your development environment. Working at CSE requires the least effort to set up and is supported, but is also the least efficient to work with. Working on your own equipment is the most efficient, but requires a little time to set up - time that you have at the start of the trimester.
If you are here, we assume you have the following set up:
- the cross compilations tools are accessible on the commandline,
- SSH is set up,
- and your public SSH key is loaded in `gitlab.cse.unsw.edu.au`. .
Obtaining the distribution with git
The following steps obtains a copy of the assignment sources.
- Create a sub-directory off your home directory to contain your cs3231 work.
% cd ~ % mkdir cs3231
- Clone the source repository from gitlab.cse.unsw.edu.au. Note: You should change the student number to match your own, and course code (comp3231) is correct even though you might be enroled in another course code.
% cd ~/cs3231 % git clone gitlab@gitlab.cse.unsw.EDU.AU:z8990549/19t1-comp3231-asst0.git asst0-src
You should now have an asst0-src directory to work on.
4. Reading component
Now that you have an OS/161 source tree, read the code walkthrough.
This component of this warmup aims to guide you through the code base to help you begin to comprehend its contents, identify what functionality is implemented where.
Note that while the code reading component is not assessable, we view it as the ideal opportunity to get to know your way around the code, including practicing with whatever code browsing tool or editor you plan to use. You will benefit in the assignments by practicing navigating around and developing a rudimentary understanding of the code base. The code reading component is here to give you some of that practice.
5. Working with the Kernel
Building a Kernel
Now to the business end of this exercise. You will now build and install a kernel.- You first have to configure your source tree. This step sets up some information
for later compilation, such as the location of various directories, the compiler to
use, and compilation flags to supply.
% cd ~/cs3231/asst0-src % ./configure
- Now we build the application binaries that OS/161 will be able to execute in future assignments. Run the following commands in the current directory. They copy the binaries to a UNIX-like filesystem layout in ~/cs3231/root.
% bmake % bmake install
- Now you must configure the kernel itself. This step prepares for a compilation
of the specific set of files that make up the warmup kernel.
% cd ~/cs3231/asst0-src/kern/conf % ./config ASST0
- The next task is to build the kernel. Note the bmake depend step. This
step works out which include files are required by which source files so the source
files can be recompiled if the include files change. Remember to "bmake depend"
when you have added or removed files or change #include statements.
% cd ../compile/ASST0 % bmake depend % bmake
- Now install the kernel.
% bmake install
Running your Kernel
If you have made it this far, your have built and installed the entire OS in ~/cs3231/root. Now it is time to run it.- Download the sample sys161-asst0.conf and copy it to ~/cs3231/root/sys161.conf.
- Change to the root directory of your OS.
% cd ~/cs3231/root
- Now run system/161 (the machine simulator) on your kernel.
% sys161 kernel
- You will observe OS/161 begin its boot sequence and then encounter an error, panic, and wait for a debugger.
sys161: System/161 release 2.0.8, compiled Feb 19 2017 14:31:53 OS/161 base system version 2.0.3 (with locks&CVs solution) Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014 President and Fellows of Harvard College. All rights reserved. Put-your-group-name-here's system version 0 (ASST0 #9) 352k physical memory available Device probe... lamebus0 (system main bus) emu0 at lamebus0 ltrace0 at lamebus0 ltimer0 at lamebus0 beep0 at ltimer0 rtclock0 at ltimer0 lrandom0 at lamebus0 random0 at lrandom0 lser0 at lamebus0 con0 at lser0 cpu0: MIPS/161 (System/161 2.x) features 0x0 panic: Fatal exception 3 (TLB miss on store) in kernel mode panic: EPC 0x8000b504, exception vaddr 0x0 panic: I can't handle this... I think I'll just die now... sys161: trace: software-requested debugger stop sys161: Waiting for debugger connection...
Summarising, you have configured and installed in ~/cs3231/root the userland applications that will eventually run on OS/161 and the OS/161 kernel itself. Going forward, you would normally only be modifying the kernel (the files in ~/cs3231/asst0-src/kern). To rebuild the kernel after changes, only the following commands are required in ~/cs3231/asst0-src/kern/compile/ASST0.
% bmake && bmake install
Using GDB
GDB is a tool in the toolbox that can help you understand what went wrong with your code. It has the advantage over kprintf() style debugging in that it does not change the behaviour of the code, and it can be used when something unexpected happens and not require you to change the code and reproduce the problem in order to debug it. This is very useful for intermittant bugs.
The Wiki has a setup guide for os161-gdb. Now is a good time to set it up. You'll need it to follow the example below. There is also a short tutorial here on using GDB with OS/161
6. Your Task
The task for this assignment is to find the bug that is causing OS/161 to crash and fix it. You can then commit your changes with git and push the changes back to gitlab.cse.unsw.edu.au.
Firstly, lets examine the output above where OS/161 crashes. Skip the initialisation status messages until you reach the point where the panic begins. Let's examine each line at a high level (as the semester progresses you'll get a deeper understanding of what is going on).
- A fatal exception has occured, i.e. something OS/161 can't recover from, so it has paniced. The exception is related to storing to memory while in kernel mode.
- The EPC (Exception Program Counter) address is the address in memory of the intruction that caused the problem. The vaddr is the address it was attempting to store to. You might guess at this point that the code might be attempting to store to a NULL pointer.
- Yes, we are panicing, kernels should not reference NULL pointers.
- sys161 is nice enough to stop and wait for you to connect os161-gdb to find the problem.
Finding the bug
Now we will look at two methods to find the offending code. The first using mostly just GDB, then second method will take advantage of the fact with know the address of the faulting instruction already.
Using just GDB
Open a second terminal window on the same machine and run GDB as follows, then use the connect and where commands. Note: login.cse.unsw.edu.au is actually and alias for several separate machines.
% cd ~/cs3231/root % os161-gdb kernel GNU gdb (GDB) 7.8 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=mips-harvard-os161". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from kernel...done. (gdb) connect membar_any_any () at includelinks/machine/membar.h:47 47 __asm volatile( Breakpoint 1 at 0x8000ac8c: file ../../lib/kprintf.c, line 135. (gdb) where #0 membar_any_any () at includelinks/machine/membar.h:47 #1 membar_store_store () at includelinks/machine/membar.h:58 #2 lamebus_write_register (bus=<optimised out>, slot=<optimised out>, offset=offset@entry=16, val=val@entry=0) at ../../arch/sys161/dev/lamebus_machdep.c:184 #3 0x800052ec in ltrace_stop (code=code@entry=0) at ../../dev/lamebus/ltrace.c:87 #4 0x8000ad58 in panic (fmt=fmt@entry=0x80023bd8 "I can't handle this... I think I'll just die now...\n") at ../../lib/kprintf.c:184 #5 0x8001b2a8 in mips_trap (tf=0x80027f28) at ../../arch/mips/locore/trap.c:315 #6 <signal handler called> #7 0x8000b504 in boot () at ../../main/main.c:140 #8 0x8000b5d4 in kmain (arguments=0x80026020 "") at ../../main/main.c:218 #9 0x8001d1ac in __start () at ../../arch/sys161/main/start.S:216 (gdb)
The where command shows the current nesting of function calls as represented by stack frames on the current kernel stack. Here are some observations.
- Frames 9-7 show the kernel starting, entering kmain, and then boot.
- Frame 6 indicates some kind of exception occured.
- Frames 5 - 0 show the kernel catching the exception, calling panic and stopping.
Let's investigate by switching to frame 7 so we can inspect it's local variables.
(gdb) frame 7 #7 0x8000b504 in boot () at ../../main/main.c:140 140 * foo = 'x'; /* attempt to access it */ (gdb) print foo $1 = 0x0 (gdb)
The exception occurs while storing the character 'x' to the pointer foo, which has a value of zero, i.e. NULL. Lets use list to see more context.
(gdb) list 135 kheap_nextgeneration(); 136 137 { 138 /* remove this section of code to fix ASST0 */ 139 char *foo = NULL; /* create a NULL pointer */ 140 * foo = 'x'; /* attempt to access it */ 141 } 142 143 /* 144 * Make sure various things aren't screwed up. (gdb)
It should be clear now how to fix the bug
Using EPC and GDB
Let's use our knowledge of EPC to go directly to the problem using the address of the offending instruction.
(gdb) list *0x8000b504 0x8000b504 is in boot (../../main/main.c:140). 135 kheap_nextgeneration(); 136 137 { 138 /* remove this section of code to fix ASST0 */ 139 char *foo = NULL; /* create a NULL pointer */ 140 * foo = 'x'; /* attempt to access it */ 141 } 142 143 /* 144 * Make sure various things aren't screwed up. (gdb)
Here we have been taken directly to the offending statement in the code base. Note that while we can identify the line of code this way, we can't print out local variables unless we are in the correct stack frame, as illustrated below.
(gdb) print foo No symbol "foo" in current context. (gdb) frame 7 #7 0x8000b504 in boot () at ../../main/main.c:140 140 * foo = 'x'; /* attempt to access it */ (gdb) print foo $2 = 0x0 (gdb)
Fixing the bug
Remove the offending code and rebuild the kernel only, and rerun OS/161.
In asst0-src/kern/compile/ASST0.
% bmake && bmake install
The should get the following when you run sys161 on your new kernel where it runs until you get a boot prompt. You can enter 'q' to exit at this point.
% sys161 kernel sys161: System/161 release 2.0.8, compiled Feb 19 2017 14:31:53 OS/161 base system version 2.0.3 (with locks&CVs solution) Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014 President and Fellows of Harvard College. All rights reserved. Put-your-group-name-here's system version 0 (ASST0 #10) 352k physical memory available Device probe... lamebus0 (system main bus) emu0 at lamebus0 ltrace0 at lamebus0 ltimer0 at lamebus0 beep0 at ltimer0 rtclock0 at ltimer0 lrandom0 at lamebus0 random0 at lrandom0 lser0 at lamebus0 con0 at lser0 OS/161 kernel [? for menu]: q Shutting down. The system is halted. sys161: 5411375122 cycles (39129232 run, 5372245890 global-idle) sys161: cpu0: 3339292 kern, 0 user, 0 idle; 7328 ll, 7328/0 sc, 66160 sync sys161: 783 irqs 0 exns 0r/0w disk 2r/592w console 0r/0w/1m emufs 0r/0w net sys161: Elapsed real time: 213.657611 seconds (25.3273 mhz) sys161: Elapsed virtual time: 215.027700909 seconds (25 mhz) %
Note: The following sample output will vary slightly depending on the year it was originally generated.
You can also test OS/161 works with the menu choice supplied on the command line as follows.
% sys161 kernel q
This is generally the way we test your submission, so make sure that you have tested using the above method, even if you have also tested interactively.
Summarising thus far, you should now have a working code base.
Committing your changes with git
First check what your local status is to avoid anything unexpected.
% git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: kern/main/main.c no changes added to commit (use "git add" and/or "git commit -a") %
All looks as expected, so lets commit the changes and push them back to gitlab. The -m is to add a descriptive commit message on the command line.
% git commit -a -m "foo pointer fix" % git push
You now have a completed assigment on gitlab that you can submit. Feel free to log into gitlab.cse.unsw.edu.au via the web and explore your assigment.
7. Submitting
The submission instructions are available on the Wiki. To overview submission, you will be submitting the git repository via CSE's give system. For ASST0, the submission system will automark it immediately and tell you if you received the 10 marks. You can submit as many times as you like up until the deadline until you get the marks.
Warning! Don't ignore the submission system! If your submission fails the submission process, you will fail to receive any marks.You're now done.