Exercise: boot xv6

Due: Fri, 30 Sep 2016 11:00:00 -0700

Booting

To compile and run xv6, you need to set up the toolchain as described in the tools guide. If you have a JOS build infrastructure on your own machine for lab 1, then you should be able to use that for building xv6, too.

Fetch the xv6 source:

$ git clone https://github.com/xiw/xv6.git
Cloning into 'xv6'...
...
$ 

Build xv6:

$ cd xv6
$ make
gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pic -O -nostdinc -I. -c bootmain.c
gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pic -nostdinc -I. -c bootasm.S
ld -m    elf_i386 -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
objdump -S bootblock.o > bootblock.asm
objcopy -S -O binary -j .text bootblock.o bootblock
...
$ 

Finding and breaking at an address

Find the address of _start, the entry point of the xv6 kernel:

$ nm kernel | grep _start
8010a48c D _binary_entryother_start
8010a460 D _binary_initcode_start
0010000c T _start

In this case, the address is 0010000c.

i386-jos-elf- prefix

If you are not using the default ELF toolchain (e.g., on macOS), you need to add the i386-jos-elf- prefix to the ELF toolchain commands, such as i386-jos-elf-nm.

Run the kernel inside QEMU GDB, setting a breakpoint at _start (i.e., the address you just found).

$ make qemu-gdb
*** Now run 'gdb'.
qemu-system-i386 -drive file=fs.img,index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp 2 -m 512  -S -gdb tcp::26000

ssh

If you are SSH’d into a remote machine, you may want to use make qemu-nox-gdb. To quit QEMU, type Ctrl-a x.

Leave it running, and in a new terminal, navigate to the same directory and run the following. If you are trying this by logging into attu, check the hostname to make sure that you are running both the commands on the same physical machine.

$ gdb
GNU gdb (GDB) Red Hat Enterprise Linux 7.10-20.el7
Copyright (C) 2015 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 "x86_64-redhat-linux-gnu".
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".
+ target remote localhost:26000
warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default i8086 settings.

The target architecture is assumed to be i8086
[f000:fff0]    0xffff0:	ljmp   $0xf000,$0xe05b
0x0000fff0 in ?? ()
+ symbol-file kernel
(gdb) br * 0x0010000c
Breakpoint 1 at 0x10000c
(gdb) c
Continuing.
The target architecture is assumed to be i386
=> 0x10000c:	mov    %cr4,%eax

Breakpoint 1, 0x0010000c in ?? ()
(gdb) 

The details of what you see are likely to differ from the above output, depending on the version of gdb you are using, but gdb should stop at the breakpoint, and it should be the above mov instruction. Your gdb may also complain that auto-loading isn’t enabled. In that case, it will print instructions on how to enable auto-loading, and you should follow those instructions.

Exercise: What is on the stack?

While stopped at the above breakpoint, look at the registers and the stack contents:

(gdb) info reg
...
(gdb) x/24x $esp
...
(gdb) 

Write a short (3-5 word) comment next to each non-zero value on the stack explaining what it is. Which part of the stack printout is actually the stack? (Hint: not all of it.)

You might find it convenient to consult the files bootasm.S, bootmain.c, and bootblock.asm (which contains the output of the compiler/assembler). The readings page has pointers to x86 assembly documentation, if you are wondering about the semantics of a particular instruction. Your goal is to understand and explain the contents of the stack that you saw above, just after entering the xv6 kernel. One way to achieve this would be to observe how and where the stack gets setup during early boot and then track the changes to the stack up until the point you are interested in. Here are some questions to help you along:

  • Begin by restarting qemu and gdb, and set a breakpoint at 0x7c00, the start of the boot block (bootasm.S). Single step through the instructions (type si at the gdb prompt). Where in bootasm.S is the stack pointer initialized? (Single step until you see an instruction that moves a value into %esp, the register for the stack pointer.)

  • Single step through the call to bootmain; what is on the stack now? What do the first assembly instructions of bootmain do to the stack? Look for bootmain in bootblock.asm.

  • Continue tracing via gdb (using breakpoints if necessary—see hint below) and look for the call that changes eip to 0x10000c. What does that call do to the stack? (Hint: Think about what this call is trying to accomplish in the boot sequence and try to identify this point in bootmain.c, and the corresponding instruction in the bootmain code in bootblock.asm. This might help you set suitable breakpoints to speed things up.)

What to submit

Write down the output of x/24x $esp with the valid part of the stack marked, plus your comments, in a file named answers.txt. Upload it using the course dropbox.

If you have decided to take this course but haven’t got added to dropbox by the due date, email your solution to the staff mailing list.