From 13f3c745c6bbef8aad377f7c5c6294c17f583532 Mon Sep 17 00:00:00 2001 From: Jack Wolfard Date: Sat, 4 Sep 2021 01:36:22 -0400 Subject: [PATCH] Update for Fall 2021 --- .editorconfig | 14 ++ .gitignore | 3 + CMakeLists.txt | 1 - instructions/lab1.md => README.md | 393 ++++++++++++++++-------------- scripts/docker.sh | 50 ++++ scripts/submit.sh | 14 ++ scripts/windows/docker/attach.bat | 1 + scripts/windows/docker/pull.bat | 1 + scripts/windows/docker/run.bat | 6 + scripts/xv6-qemu | 1 - 10 files changed, 303 insertions(+), 181 deletions(-) create mode 100644 .editorconfig rename instructions/lab1.md => README.md (50%) create mode 100755 scripts/docker.sh create mode 100755 scripts/submit.sh create mode 100644 scripts/windows/docker/attach.bat create mode 100644 scripts/windows/docker/pull.bat create mode 100644 scripts/windows/docker/run.bat diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..52a02f8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +[*.{md,sh,c,h,S,txt}] +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index 0a46411..802f4ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ *~ .gdbinit +build +.DS_Store +submission.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index 8972f2e..0dad660 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,4 +55,3 @@ add_custom_target( DEPENDS buildkern buildboot xv6.img makeuserfs #DEPENDS buildkern buildboot xv6.img ) - diff --git a/instructions/lab1.md b/README.md similarity index 50% rename from instructions/lab1.md rename to README.md index f4ce08c..84226be 100644 --- a/instructions/lab1.md +++ b/README.md @@ -1,66 +1,72 @@ # Lab 1 - Getting to know Kernel Development -The goal of this lab is to get you familiar with kernel devlopment, and our xv6 -environment. +The goal of this lab is to get you familiar with both kernel development and our +xv6 environment. The lab is composed of three parts: - - First, you will use git to checkout, and build the repository. (ungraded, but - required for the rest of the lab) - - Second, you will add some debugging functionality to the xv6 kernel. - - Third, you will get familiar with the boot procedure of xv6 by modifying the - kernel to support variable memory sizes. +1. Checkout and build repository +2. Add debugging functionality to the xv6 kernel +3. Modify kernel to support variable memory sizes -## Part 1 - checking out the repository +## Part 1 - Checking out the repository -All of the code for this course will be distributed and turned in using the -[git](www.git-scm.com) revision system. If you don't know git, we recommend -looking at the -[Git User's Manual](www.kernel.org/pub/software/scm/git/docs/user-manual.html). -You may also find [this](eagain.net/articles/git-for-computer-scientists/) -overview helpful. +All of the code for this course will be distributed using the [git][git] +revision system. If you don't know git, we recommend looking at the +[Git User's Manual][git-manual]. You may also find [this][git-article] overview +helpful. -The xv6 repository we're using for this course is avaialble on Georgia Tech's -github: +The xv6 repository we're using for this course is available on Georgia Tech's +GitHub: ```bash -git clone git@github.gatech.edu:cs3210-fall20/-xv6-public.git +git clone git@github.gatech.edu:cs3210-fall2021/xv6.git ``` -For this lab, we will be using the lab1 branch within git. You may switch to it +For this lab, we will be using the lab1 branch within git. You may switch to it with: ```bash git checkout lab1 ``` -Once you've checked out the lab, you'll want to build it. We're using the [cmake](cmake-homepage) -build system this semester. You may find more information about it -[here](cmake-manual). +Next, launch the docker instance for the class using the provided script. + +Using a bash compatible system: + +```bash +./scripts/docker.sh --pull # download the image from DockerHub +./scripts/docker.sh # run container and mount the pwd as /xv6 +``` + +Using Windows: + +```cmd +.\scripts\windows\docker\pull.bat +.\scripts\windows\docker\run.bat +``` + +Once you've checked out the lab and connected to Docker, you'll want to build +it. We're using the [cmake][cmake] build system this semester. You may find more +information about it [here][cmake-manual]. For now, to build the lab, we encourage you building in a separate build directory: ```bash -cd +cd /xv6 mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Debug make ``` -**NOTE: You may have to install gcc multilib support to get lab1 to build:** -``` -sudo apt install gcc-multilib -``` - - -**NOTE2: The above code uses a "Debug" build. This disables optimizations and -adds in debug symbols. Its much easier to work with than a "Release" build, the -default CMAKE_BUILD_TYPE. The autograder (more later) will run your code in -"Release" mode** +**NOTE:** The above code uses a "Debug" build. This disables optimizations and +adds in debug symbols. It's much easier to work with than a "Release" build, the +default CMAKE_BUILD_TYPE. The autograder (more later) will run your code in +"Release" mode. -Once you've built xv6, you may launch your new kernel. We've provided a +Once you've built xv6, you may launch your new kernel. We've provided a convenience script to help you launch it: ```bash @@ -71,47 +77,45 @@ This should take you to a shell prompt, where you can use your basic xv6 commands (try typing "ls" to see what files exist in your root directory). You may terminate the qemu instance launched by the script by hitting -CTRL-a,x. +CTRL-a, x. -#### What's happening under the hood +### What's happening under the hood -Our xv6 kernel is an OS kernel, its made to run on bare-hardware. However, +Our xv6 kernel is an OS kernel, its made to run on bare-hardware. However, launching it on your PC seems like a bad idea, as it would overwrite your -existing OS. Instead, we want to run it in a virtual environment that's much +existing OS. Instead, we want to run it in a virtual environment that's much more friendly for testing. We could use a classic virtual machine (VM) solution (e.g. VMWare or VirtualBox), but those are pretty heavy-weight, take a long time to launch, and are hard to configure. Instead, we use qemu, a machine -emulator. Qemu emulates a cpu, causing it to look to the program running inside -of it like it has its own raw x86 CPU. This is slow, and you may notice that xv6 -actually runs really slowly in qemu, but its much more convenient for deubbing, -as launching and tearing down a qemu instance is very fast! It is possible to -run xv6 on a more traditional VM, or even raw hardware! However, we wont require +emulator. Qemu emulates a cpu, causing it to look to the program running inside +of it like it has its own raw x86 CPU. This is slow, and you may notice that xv6 +actually runs really slowly in qemu, but its much more convenient for debugging, +as launching and tearing down a qemu instance is very fast! It is possible to +run xv6 on a more traditional VM or even raw hardware! However, we won't require that for the purpose of this course. You can see the exact command used by turning on the verbose option to -`xv6-qemu` with `-v` or `--verbose`, and all available options with `-h` - +`xv6-qemu` with `-v` or `--verbose` and all available options with `-h` -## Part 2 - Modifying The Repository +## Part 2 - Modifying the repository Now that you have the kernel launching, we're going to make some changes to the -kernel. The first change is adding [stack backtrace](https://en.wikipedia.org/wiki/Stack_trace) -support. This exercise is aimed at getting you familiar with xv6, and some -low-level x86 behaviors and registers (including the stack). Overall the -quantity of code you write for it will likely be small, but for most, it will -take a great deal of effort to write. +kernel. The first change is adding [stack backtrace][backtrace] support. This +exercise is aimed at getting you familiar with xv6 and some low-level x86 +behaviors and registers (including the stack). Overall the quantity of code you +write for it will likely be small, but for most, it will take a great deal of +effort to write. The second modification you'll be making to the kernel is to add variable memory -support. That will get you experience with the xv6 bootup, a little familiarity -with system-call like behavior, and some assembly experience. We'll cover that +support. That will get you experience with the xv6 bootup, a little familiarity +with system-call like behavior, and some assembly experience. We'll cover that more in Part 3. - ### The Specification -For part 2 of the lab, you will be modifying the xv6 kernel to add -stack-trace support through a function named `backtrace`. Backtrace has the -following specification: +For part 2 of the lab, you will be modifying the xv6 kernel to add stack-trace +support through a function named `backtrace`. Backtrace has the following +specification: ```c void backtrace(); @@ -121,71 +125,89 @@ Prints the stack trace of any functions run within the kernel. ``` The format of the data printed is: -``` + +```text Backtrace: <0xaddress0> [top_of_stack_function_name]+offs1 <0xaddress1> [next_function_in_stack_name]+offs2 ... <0xaddressN> [last_function_in_stack]+offsN ``` -**NOTE: there are three space characters (' ') preceeding each of the address lines.** -You must create a header `backtrace.h` (located in `kernel/include/`) with the declaration of the `backtrace()` -function (but not definition, definitons generally belong in c files), such that -any kernel file including `backtrace.h` may run the `backtrace()` function. +**NOTE:** there are three space characters (' ') preceding each of the address +lines. + +You must create a header `backtrace.h` (located in `kernel/include/`) with the +declaration of the `backtrace()` function (but not definition, definitions +generally belong in c files), such that any kernel file including `backtrace.h` +may run the `backtrace()` function. -##### The format: -The backtrace function will print N+1 lines, where N is the number of functions in -the kernel's stack (excluding the backtrace function itself). The first line +### The Format + +The backtrace function will print N+1 lines, where N is the number of functions +in the kernel's stack (excluding the backtrace function itself). The first line will read `Backtrace:`. Each of the following N lines will have the following information and format (in order from left to right): -- three (3) spaces to start the line -- The address of the next instruction to run in the stack, printed in lower-case hex, prefixed by "0x", surrounded on the left by a single `<` and on the right by a single `>` -- a single space -- The name of the function on the callstack -- A single `+` character -- A decimal number representing the offset from the start of that function in bytes -- A newline character +- Three (3) spaces to start the line +- The address of the next instruction to run in the stack, printed in lower-case + hex, prefixed by "0x", surrounded on the left by a single `<` and on the right + by a single `>` +- A single space +- The name of the function on the callstack +- A single `+` character +- A decimal number representing the offset from the start of that function in bytes +- A newline character So, if my codebase had a function named `foo`, starting on address `0x200` with length `0x100` (e.g. ending at `0x300`), and my backtrace identified the return address `0x210` on the stack, I would print the line: -``` + +```text <0x210> foo+16 ``` -### Some Guidance: +### Some Guidance To create this function, you'll have to handle three primary tasks: -1. Identify return addresses on the function stack to identify the call-chain before this function -2. Lookup the name of the function via its stack location -3. Find the starting address of the function, and calculate its offset + +1. Identify return addresses on the function stack to identify the call-chain + before this function +2. Lookup the name of the function via its stack location +3. Find the starting address of the function, and calculate its offset The specific details about each of these tasks is as follows: -##### Stack Addresses: +#### Stack Addresses Function calls are managed through the stack abstraction, you should have -learned about this extensively in CS2200 or equivalent. If you're rusty on the -stack, you may find references [here](TODO-stackreference). +learned about this extensively in CS2200 or equivalent. If you're rusty on the +stack, you may find references [here][stack-article]. -For this lab, you'll need to know to know how x86 handles some of these primitive stack +For this lab, you'll need to know how x86 handles some of these primitive stack operations: -- The stack pointer is maintained in the stack pointer `sp` register (`esp` in 32-bit mode) -- The stack grows downwards (pushing decrements the stack pointer) -- The `call` instruction, used to call functions implicitly pushes the return address of the call (the instruction after the call) onto the stack (e.g. after call `esp` will point to the return address used by the function) -- The `ret` instruction pops the top of the stack and jumps to that address (basically undoing a call) -- The base-pointer register (`bp` or `ebp` in 32-bit mode) points to the beginning of the stack frame for this function -- The stack pointer points to the last pushed value (e.g. `push` decrements the stack pointer, then writes to the location pointed by it, and `pop` dereferences `esp`, then increments) -- By convention, when a function is first called, the base-pointer is written to the stack, and stack-pointer is transferred into the base-pointer. +- The stack pointer is maintained in the stack pointer `sp` register (`esp` in + 32-bit mode) +- The stack grows downwards (pushing decrements the stack pointer) +- The `call` instruction, used to call functions implicitly pushes the return + address of the call (the instruction after the call) onto the stack (e.g. + after call `esp` will point to the return address used by the function) +- The `ret` instruction pops the top of the stack and jumps to that address + (basically undoing a call) +- The base-pointer register (`bp` or `ebp` in 32-bit mode) points to the + beginning of the stack frame for this function +- The stack pointer points to the last pushed value (e.g. `push` decrements the + stack pointer, then writes to the location pointed by it, and `pop` + dereferences `esp`, then increments) +- By convention, when a function is first called, the base-pointer is written to + the stack, and stack-pointer is transferred into the base-pointer. This forces the stack layout to appear as follows: -``` +```text --------------------- | ... | --------------------- @@ -243,11 +265,11 @@ in `include/asm/x86.h`: #define read_ebp(dest) ``` -#### Symbol Information: +#### Symbol Information Getting the name of the running function within the kernel is another huge -challenge. Once I know the address of the function, how can I determine what -function was running? If I were on a normal desktop, I could try to figure it +challenge. Once I know the address of the function, how can I determine what +function was running? If I were on a normal desktop, I could try to figure it out from the binary file, but do I necessarily have a filesystem on all phases of kernel boot? @@ -256,18 +278,17 @@ information about the running symbols (e.g. the names of the functions that are running, and the mapping from address to function name), we just need to parse this information out of the address space. -##### STAB information +#### STAB Information -The kernel has embedded in its address space [STAB information](https://sourceware.org/gdb/current/onlinedocs/stabs/Overview.html). -This information is placed at special symbols called `__STAB_BEGIN__` and -`__STABSTR_BEGIN__`. You can learn more about how we do this by exploring -[linker scripts](https://sourceware.org/binutils/docs/ld/Scripts.html), and -looking at ours in `kernel/kernel.ld`. +The kernel has embedded in its address space [STAB information][stab]. This +information is placed at special symbols called `__STAB_BEGIN__` and +`__STABSTR_BEGIN__`. You can learn more about how we do this by exploring +[linker scripts][linker] and looking at ours in `kernel/kernel.ld`. Having you write a library that parses the STAB information would be a little -too tedious for a class project, so we have instead provided you with a stab +too tedious for a class project, so we have instead provided you with a stab library in the file `kernel/stab.c` and its associated header -`kernel/include/stab.h`. +`kernel/include/stab.h`. The library includes the following relevant functions: @@ -277,20 +298,21 @@ The library includes the following relevant functions: int stab_info(uint eip, struct stab_info *info); ``` -Sometimes (in the instance of compiler optimizations or assembly functions) the -`stab_info` function cannot find a symbol for a valid return address, in this instance -your backtrace function should print the function name as `` with an offset of 0. +Sometimes (in the instance of compiler optimizations or assembly functions) the +`stab_info` function cannot find a symbol for a valid return address, in this +instance your backtrace function should print the function name as `` +with an offset of 0. -## Part 3 - Modifying boot. +## Part 3 - Modifying boot This part of this lab will involve modifying the boot system of the kernel to detect the amount of available RAM on the machine, then passing and utilizing that information within the xv6 kernel. -**NOTE:** For much of this portion of the lab you will be modifying the kernel before its -console print infrastructure is set up, making debugging via print basically -impossible. We strongly advise you to complete Lab 0 before attempting this -part of lab 1. +**NOTE:** For much of this portion of the lab you will be modifying the kernel +before its console print infrastructure is set up, making debugging via print +basically impossible. We strongly advise you to complete Lab 0 before +attempting this part of lab 1. Before we get into the specifics of the lab, lets cover some background knowledge. @@ -298,14 +320,14 @@ knowledge. ### Background Information Your computer has many essential low-level components, such as your RAM -controller, power supply, and other peripherals. These components are fixed on -the motherboard and generally don't change. They must also be set up properly, +controller, power supply, and other peripherals. These components are fixed on +the motherboard and generally don't change. They must also be set up properly, in a device specific way before you can run any general purpose code on your -processor. Think about it, how will your kernel load itself off the disk before +processor. Think about it, how will your kernel load itself off the disk before the disk driver is set up? This problem, of bringing up the essential low-level devices on the machine and -loading your kernel into memory is what we'll call boot-loading. Let's now +loading your kernel into memory is what we'll call boot-loading. Let's now discuss the three phases of bootloading. #### BIOS @@ -313,30 +335,30 @@ discuss the three phases of bootloading. To help enable the initial configuration and setup of these devices, motherboards come with a BIOS (now commonly replaced by the more complex EFI protocol), which sets up these devices, loads a single block of data from disk, -and provides support for additional hardware device queries. When you first +and provides support for additional hardware device queries. When you first launch xv6 (if you launch with gdb attached), you'll notice that the processor starts at address 0xfff0, then jumps (if you use `si`, or step instruction) to step to the next instruction, at address 0xe05b in the BIOS. The low-level details of what the BIOS does are hardware specific and not relevant for this course (if you're really interested, you can look at xv6's -[bios source](https://github.com/qemu/qemu/tree/master/pc-bios)). What we care about for this course is the -handshake the bios makes with the actual kernel. +[bios source][bios]. What we care about for this course is the handshake the +bios makes with the actual kernel. When the bios finishes running, it loads a single disk block (the first block on -disk) into the address 0x7c00, then jumps to and begins executing the code at -that location. This is how control is passed from the BIOS to the kernel. +disk) into the address `0x7c00`, then jumps to and begins executing the code at +that location. This is how control is passed from the BIOS to the kernel. However, the kernel doesn't fit on a single block in disk, so we have to provide -one more boot layer to help load the kernel. This layer is aptly called the +one more boot layer to help load the kernel. This layer is aptly called the Boot Loader. We will explore just a couple of details of the BIOS before we move onto the -boot loader, as they are fundamental to the BIOS construction. First, the BIOS +boot loader, as they are fundamental to the BIOS construction. First, the BIOS isn't loaded from disk -- how could it be loaded from disk when it hasn't yet -initialized the disk controllers? Instead the BIOS lives on its own ROM that -ships with your motherboard (or emulated rom for xv6). This makes the BIOS +initialized the disk controllers? Instead, the BIOS lives on its own ROM that +ships with your motherboard (or emulated rom for xv6). This makes the BIOS brittle, as it cannot easily be changed, and consequently we try to move as much -logic off of the BIOS as possible. Additionally, the BIOS runs before the +logic off of the BIOS as possible. Additionally, the BIOS runs before the boot loader (and hence kernel), and therefore must leave the processor in its lowest configuration state (as if nothing had run), 16-bit real mode (we'll talk more about this later), and any BIOS functions that run must also be run from @@ -346,78 +368,79 @@ more about this later), and any BIOS functions that run must also be run from The boot loader is the first easily modifiable code that runs (it runs from the first disk block), so it can be more complex and flexible than the BIOS. -However, the boot loader also operates in a constrained environment. It starts +However, the boot loader also operates in a constrained environment. It starts in 16-bit real mode (a mode of the x86 processor with 16-bit registers, and physical addressing), with at most 512 bytes (1 disk block) of code. The goal of the boot block is to set up the CPU for the kernel, then load the -kernel and pass it control (e.g. jump to the kernel's entry point). You can -find the code for our boot loader in the `bootblock` directory. The entry point -from the BIOS is `start` found in `bootblock/bootasm.S`. Once the bootloader -has switched the processor into 32-bit mode, initialized the disk, and loaded the -kernel into memory, it jumps into the kernel at the end of `bootmain` in +kernel and pass it control (e.g. jump to the kernel's entry point). You can +find the code for our boot loader in the `bootblock` directory. The entry point +from the BIOS is `start` found in `bootblock/bootasm.S`. Once the bootloader +has switched the processor into 32-bit mode, initialized the disk, and loaded +the kernel into memory, it jumps into the kernel at the end of `bootmain` in `bootblock/bootmain.c`. -Modern bootloaders preform much more complex tasks than our bootblock, -[GRUB](https://www.gnu.org/software/grub/) is an example of a modern boot loader. +Modern bootloaders preform much more complex tasks than our bootblock, +[GRUB][grub] is an example of a modern boot loader. #### Kernel Startup The kernel goes through a long, arduous boot process, beginning at `entry` in `kernel/src/asm/entry.S`, and continuing through much of kernel's `main` in -`kernel/src/main.c`. This process will be relevant throughout the course, so -feel free to take a look at it. However, we wont cover it in too much detail here. +`kernel/src/main.c`. This process will be relevant throughout the course, so +feel free to take a look at it. However, we wont cover it in too much detail here. ### The Assignment Currently, the kernel assumes it has `PHYSTOP` memory (defined in `include/memlayout.h` as `0xE000000`). This is a static memory assumption, so regardless of what the attached machine has, the kernel will use exactly -`PHYSTOP` bytes of RAM. This could be an issue in two ways, (1) the machine has +`PHYSTOP` bytes of RAM. This could be an issue in two ways, (1) the machine has less than `PHYSTOP` memory, and the kernel assumes it has memory that doesn't exist! or (2) the machine has much more memory, but the kernel cannot allow the user-space to utilize it. In this part of the lab, we're going to call into the BIOS, and have it tell us how much memory is available, then we'll pass this information into our kernel -proper. However, recall that the bios assumes the processor is running in +proper. However, recall that the bios assumes the processor is running in 16-bit real mode (not the more common 32-bit mode that our kernel actually runs -in). This means, we have to call the BIOS from the bootblock, before it +in). This means, we have to call the BIOS from the bootblock, before it transitions us out of 16-bit real mode, and pass the information to the kernel from there. This part of your assignment has three sub-tasks: -1. Get the available RAM from the bootblock -2. Make that information available in the kernel -3. Have the kernel read that information, and initialize its free memory structure based on the available RAM instead of an arbitrary `PHYSTOP`. -#### The BIOS Call. +1. Get the available RAM from the bootblock +2. Make that information available in the kernel +3. Have the kernel read that information, and initialize its free memory + structure based on the available RAM instead of an arbitrary `PHYSTOP`. + +#### The BIOS Call As the BIOS is responsible for initializing and configuring the RAM controller, it is our definitive source on how much RAM the machine has, and the logical -place to ask about allocated memory. However, our bootloader cannot simply jump +place to ask about allocated memory. However, our bootloader cannot simply jump into the BIOS (then our bootloader would be BIOS dependant, and we don't want that), instead the BIOS exports an interface much like the system-call -interface. We'll be making a BIOS call by interrupting and passing control into +interface. We'll be making a BIOS call by interrupting and passing control into the BIOS through the `int` instruction (much like system calls use the int -instruction). Once this is done, the BIOS will pass us the information needed, +instruction). Once this is done, the BIOS will pass us the information needed, and return. Recall that the BIOS runs before the boot loader, and must run in 16-bit -real-mode. As a result, we must make our BIOS call from code running in 16-bit -real-mode. Unfortunately, once the x86 cpu transitions into 32-bit mode, it -cannot revert to real-mode. This means, we must make our BIOS call before the +real-mode. As a result, we must make our BIOS call from code running in 16-bit +real-mode. Unfortunately, once the x86 cpu transitions into 32-bit mode, it +cannot revert to real-mode. This means, we must make our BIOS call before the CPU converts to 32-bit mode, in the bootloader. - As the BIOS call is tedious and complex, we wont require you to actually write the assembly for the call itself, we've provided that method detailed below. Your job is to place the call at the appropriate location, and handle putting -that memory in a location the kernel can read from. The bios call is defined in +that memory in a location the kernel can read from. The bios call is defined in `bootblock/e820.S` ```asm -# The desetination adder (where the data will be stored) is passed in ax +# The destination adder (where the data will be stored) is passed in ax # Makes the e820 bios call. The result of the call will be stored in the # address passed in ax (note only 16-bits available). # @@ -445,58 +468,70 @@ do_e820: ``` More information on the e820 bios call can be found -[here](https://wiki.osdev.org/Detecting_Memory_(x86)#BIOS_Function:_INT_0x15.2C_EAX_.3D_0xE820). -For the purpose of this lab, we're going to assume the call behaves well -(regions are reported in-order, and non-overlapping). +[here][e820]. For the purpose of this lab, we're going to assume the call +behaves well (regions are reported in-order, and non-overlapping). -#### The Kernel. +#### The Kernel Once you have the memory passed to the kernel, your job within the kernel is make it aware of the amount and location of physical memory, and to enable the -kernel to use that physical memory from its `kalloc` function. For simplicity, +kernel to use that physical memory from its `kalloc` function. For simplicity, we will only require you to change how the kernel handles extended memory -(ram available at physical addresses above the BIOs). After you have +(ram available at physical addresses above the BIOs). After you have completed this lab the kernel should be able to allocate all non-statically allocated physical pages present in extended memory from the `kalloc` function, -and `kalloc` should never return a physical page that isn't present on the system. +and `kalloc` should never return a physical page that isn't present on the +system. We encourage you to familiarize yourself with the kernel's `kinit` functions, and physical memory allocation functions, as they will likely be useful in -completing this exercise +completing this exercise. ## Grading -As with all labs in this course, the lab has an associated autograder. The -policies and rules of the autograder may be found on the class -[syllabus](https://gatech.instructure.com/courses/140830/assignments/syllabus) and the -[autograder page](https://github.gatech.edu/cs3210-fall20/xv6-public/blob/main/instructions/autograder_instructions.md). -You will submit your code to the auto-grader for -auto-grading. There will also be a hand graded portion of this lab, worth 15% -of your lab grade. Finally, this is our only *individual* lab, you cannot -collaborate or share code with others (although discussion is allowed). Your +As with all labs in this course, the lab has an associated autograder on +Gradescope. The policies and rules of the autograder may be found on the class +[syllabus][syllabus]. You will submit your code to the autograder for +autograding. There will also be a hand graded portion of this lab, worth 15% +of your lab grade. Finally, this is our only *individual* lab, you cannot +collaborate or share code with others (although discussion is allowed). Your code will be checked for cheating, and any detection of shared code, or pulling code from the internet will be harshly punished. -To submit to the autograder, first push your code into your class repository. -Your code must be pushed to the `lab1` branch. Then, visit the autograder's web -interface [here](https://cs3210-autograder.cc.gatech.edu) (Note, you'll have to be -on the gatech network -- e.g. through vpn -- to access the autograder site). Authenticate with github, -then submit your lab1 code for grading. The lab1 code will be automatically -pulled from github, and graded by the autograder. You should see interactive -feedback on the website, as well as receive an email once the grading is -finished. This lab is subject to all [autograder policies](todo), please review -them before submitting. +To submit, run `scripts/submit.sh` and upload the generated `submission.zip` +file to your Gradescope section ([A][gradescope-a], [GR][gradescope-gr]). **NOTE:** Any unauthorized attempt to subvert or attack the autograder will be -considered a violation of academic integrity, and will be punished. The -autograder logs all submissions both locally and remotely, so any submission may -be audited. - +considered a violation of academic integrity and will be punished. The +autograder logs all submissions both in Gradescope and remotely, so any +submission may be audited. ## Extra If you're begging for more after this assignment, you may consider trying some of the following projects (no credit given, just fun experiments): -- Explore what it takes to get the xv6 kernel to boot with a commodity bootloader (e.g. Grub), why is this hard? -- Can the xv6 bootblock be made to work with an EFI (instead of BIOS) based bootloader? What does that take? -- Can you get xv6 to use (not just recognize) arbitrarily large amounts of physical memory? (up to 4GB) This is very challenging, but also very interesting! (Its also highly related to lab 2) (Even harder, you can use over 4GB of physical memory with PAE) + +- Explore what it takes to get the xv6 kernel to boot with a commodity + bootloader (e.g. Grub), why is this hard? +- Can the xv6 bootblock be made to work with an EFI (instead of BIOS) based + bootloader? What does that take? +- Can you get xv6 to use (not just recognize) arbitrarily large amounts of + physical memory? (up to 4GB) This is very challenging but also very + interesting! (It's also highly related to lab 2) (Even harder, you can use + over 4GB of physical memory with PAE) + +[git]: https://www.git-scm.com +[git-manual]: https://www.kernel.org/pub/software/scm/git/docs/user-manual.html +[git-article]: https://eagain.net/articles/git-for-computer-scientists/ +[cmake]: https://cmake.org/ +[cmake-manual]: https://cmake.org/cmake/help/v3.21/ +[backtrace]: https://cmake.org/cmake/help/v3.21/ +[stack-article]: https://signalshore.github.io/blog/Stack-Frames-in-x86.html +[stab]: https://sourceware.org/gdb/current/onlinedocs/stabs/Overview.html +[linker]: https://sourceware.org/binutils/docs/ld/Scripts.html +[bios]: https://github.com/qemu/qemu/tree/master/pc-bios +[grub]: https://www.gnu.org/software/grub/ +[e820]: https://wiki.osdev.org/Detecting_Memory_(x86)#BIOS_Function:_INT_0x15.2C_EAX_.3D_0xE820 +[syllabus]: https://github.gatech.edu/pages/cs3210-fall2021/course/syllabus/ +[gradescope-a]: https://www.gradescope.com/courses/280787 +[gradescope-gr]: https://www.gradescope.com/courses/299636 diff --git a/scripts/docker.sh b/scripts/docker.sh new file mode 100755 index 0000000..0bfd867 --- /dev/null +++ b/scripts/docker.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +function usage() { + cat < /dev/null && pwd)" +cd "${SCRIPT_DIR}/.." +ROOT_DIR="$(pwd)" + +PULL=false +ATTACH=false + +for arg in "$@"; do + case $arg in + --pull) + PULL=true + shift + ;; + --attach) + ATTACH=true + shift + ;; + -h | --help) + usage # run usage function on help + ;; + *) + usage # run usage function if wrong argument provided + ;; + esac +done + +if [[ $PULL == true ]]; then + echo "Pulling latest image from DockerHub" + docker pull jackwolfard/cs3210:latest +elif [[ $ATTACH == true ]]; then + echo "Attaching to container" + docker exec -it xv6 bash +else + echo "Starting xv6 container" + docker run --rm -it --name="xv6" -v "${ROOT_DIR}/":/xv6 -w="/xv6" jackwolfard/cs3210:latest +fi diff --git a/scripts/submit.sh b/scripts/submit.sh new file mode 100755 index 0000000..918e19c --- /dev/null +++ b/scripts/submit.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" +cd "${SCRIPT_DIR}/.." +ROOT_DIR="$(pwd)" +OUT="$ROOT_DIR/submission.zip" +BASE_COMMIT="9e0b8c5d366a864a0298efd122bb6504a1cb6bdb" +COMMIT_TARGET="commits.txt" +DIR_TARGETS=('bootblock' 'include' 'kernel' 'tools' 'user') +FILE_TARGETS=('CMakeLists.txt' $COMMIT_TARGET) + +git log "$BASE_COMMIT..HEAD" > $COMMIT_TARGET +zip -r "$OUT" ${DIR_TARGETS[@]} ${FILE_TARGETS[@]} +rm $COMMIT_TARGET diff --git a/scripts/windows/docker/attach.bat b/scripts/windows/docker/attach.bat new file mode 100644 index 0000000..3061924 --- /dev/null +++ b/scripts/windows/docker/attach.bat @@ -0,0 +1 @@ +docker exec -it xv6 bash diff --git a/scripts/windows/docker/pull.bat b/scripts/windows/docker/pull.bat new file mode 100644 index 0000000..22551f4 --- /dev/null +++ b/scripts/windows/docker/pull.bat @@ -0,0 +1 @@ +docker pull jackwolfard/cs3210:latest diff --git a/scripts/windows/docker/run.bat b/scripts/windows/docker/run.bat new file mode 100644 index 0000000..a12f549 --- /dev/null +++ b/scripts/windows/docker/run.bat @@ -0,0 +1,6 @@ +@ECHO OFF +setlocal +SET parent=%~dp0 +FOR %%a IN ("%parent%\..\..\..") DO SET "root=%%~fa" +@ECHO ON +docker run --rm -it --name="xv6" -v %root%:/xv6 -w="/xv6" jackwolfard/cs3210:latest diff --git a/scripts/xv6-qemu b/scripts/xv6-qemu index f023a9e..3ac7777 100755 --- a/scripts/xv6-qemu +++ b/scripts/xv6-qemu @@ -73,4 +73,3 @@ if [[ ${VERBOSE} ]]; then fi ${SCRIPT} - -- 2.47.3