| 6.097: OPERATING SYSTEM ENGINEERING |
| Fall 2002 |
| Lab 2 |
| Hand out date: Wednesday September 18th |
| Due date: Thursday October 3rd |
In this lab, your will write the memory management code for your operating system. Memory management is comprised of two components.
The first component that comes under the umbrella of memory management is virtual memory. You will set up the virtual memory layout for your operating system according to the specification we provide. Your task will be to build the page table data structure which matches our specification.
The second component is managing the physical memory of the computer. The x86 divides physical memory up into 4096 byte regions called pages. Your task will be to maintain data structures that record which pages are free and allocated and how many processes are sharing each allocated page. You will also write the routines to allocate and free pages of memory.
You should now download the code for the lab and untar it into your 6.097 directory. For example,
athena% add gnu 6.097 sipb athena% mkdir ~/6.097 athena% cd ~/6.097 athena% wget http://pdos.lcs.mit.edu/6.097/labs/lab2.tar.gz athena% gtar -zxf lab2.tar.gz drwxr-xr-x cates/wheel 0 Sep 15 19:34 2002 ossrc/ drwxr-xr-x cates/wheel 0 Sep 15 19:34 2002 ossrc/kern/ drwxr-xr-x cates/wheel 0 Sep 15 19:34 2002 ossrc/kern/inc/ -rw-r--r-- cates/wheel 2528 Sep 14 17:00 2002 ossrc/kern/inc/asm.h . . .
athena% cd ossrc
# build the OS and the bochs disk image
athena% gmake
.
[ gmake output goes here ]
.
.
# this is the disk image
athena% ls -l kern/obj/bochs.img
-rw-r--r-- 1 cates wheel 5120000 Sep 15 19:48 kern/obj/bochs.img
# there is a bochsrc file in this directory (which boots this image)
athena% cat .bochsrc | grep diskc
diskc: file="./kern/obj/bochs.img", cyl=200, heads=16, spt=63
# so let's see what this OS does!
athena% bochs
Your OS should print a few lines of text the last of which should read:
panic: i386_vm_init: This function is not finishedDo not continue unless you see this. At this point you should examine the output of
gmake to
make sure you understand what is happening. You should also read the
source files in the subdirectories kern and
tools/bootloader.
The VM layout you are going to setup divides the address space into
two parts. The user process has complete control over the lower part,
while the kernel maintains control over the top part. The dividing
line is defined, somewhat arbitrarily by ULIM in
kern/inc/mmu.h (roughly, 256MB from the top of the
virtual address space).
Since, the kernel and user process co-exist in each address space, we will have to use permission bits to prevent the user from accessing the kernel's memory (ie. to enforce fault isolation). We do this as follows:
The user process will have no permission to any of the
memory above ULIM, while the kernel will be able to
read/write this memory. For the address range
(UTOP,ULIM], both the kernel and the user process have
the same permission: they can read but not write this address range.
This range of address is used to expose kernel data structures,
read-only to the user process. Lastly, the address space below
UTOP is for the user process to use; the user process
will set permissions for accessing this memory.
In this lab, you are going to setup the address space above
UTOP--the kernel part of the address space.
You might want to consult chapter 3 of IA-32 Intel Architecture Software Developer's Manual, Volume 3: System programming guide for reference.
You are to turn in this lab in the form of a web page. When you are
done email the URL to 6.097-handin@pdos.lcs.mit.edu.
Your web page should contain your answers to the questions posed in
this lab and a link to your kern/pmap.c.
The layout of the kernel portion of the virtual address space will be
handled by the i386_vm_init() function, defined in
kern/pmap.c. The actual lay out is as described above and
is diagrammed in kern/inc/mmu.h. It would behoove you to
become familiar with this file as it also contains useful macros and
definitions.
The comments in i386_vm_init() specify the virtual memory
layout. Your task is to fill in the missing code to build a 2-level
page table fulfilling this specification.
Once you have done this, run the code. The function
check_boot_page_directory() (it's located about half way
down the i386_vm_init()) will check over the page table
you have built and report any problems. Do not continue until you
pass this check. You may find it helpful to add your own
assert()s to verify that your own assumptions are, in
fact, correct.
Questions:
| Entry | Base Virtual Address | Points to (logically): |
| 1023 | ? | Page table for top 4MB of phys memory |
| 1022 | ? | ? |
| . | ? | ? |
| . | ? | ? |
| . | ? | ? |
| 2 | 0x00800000 | ? |
| 1 | 0x00400000 | ? |
| 0 | 0x00000000 | [see next question?] |
i386_vm_init(), after
check_boot_page_directory, we map the first entry of
the page directory to the page table of the first four MB of
RAM, but delete this mapping at the end of the function. Why is
this necessary? What would happen if it were omitted? Does this
actually limit our kernel to be 4MB? What must be true if our
kernel were larger than 4MB?
In the file kern/pmap.c you must implement code for
the five function listed below:
ppage_init () ppage_alloc () ppage_free () ppage_insert () ppage_remove ()
Once you are done call the function ppage_check() from
i386_init(), to test these functions. You must get
ppage_check() to run successfully.
You may find reading kern/inc/pmap.h useful.
Questions:
Questions:
Is there a comparable mechanism on the PDP-11/40 which would provide the fault isolation necessary to allow the kernel and the user process to run in the same address space? (read: "same address space" as "with the same set of PARs/PDRs")
Questions:
printf.c and
console.c. Specifically, what function does
console.c export? How is this function used by
printf.c?
console.c:
1 if (crt_pos >= CRT_SIZE) {
2 int i;
3 bcopy (crt_buf + CRT_COLS, crt_buf, CRT_SIZE << 1);
4 for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++)
5 crt_buf[i] = 0x0700 | ' ';
6 crt_pos -= CRT_COLS;
7 }
Trace the execution of the following code step-by-step:
int x = 1, y = 3, z = 4;
warn ("x %d, y %x, z %d\n", x, y, z);
kprintf(), to what does fmt point? to
what does ap point?
cnputc, va_arg, and ksprintn.
For cnputc, list its argument as well. For
va_arg, list what ap points to before and
after the call. For ksprintn list the values of it's
first two arguments.
u_int i = 0x00646c72;
warn ("H%x Wo%s", 57616, &i);
What is the output? Explain how this output is arrived out in the
step-by-step manner of the previous exercise.
The output depends on that fact that Intel is little-endian. If
Intel were instead big-endian what would you set i to in
order to yield the same output? Would you need to change
57616 to a different value?
warn in the above code were replaced by
printf the code fails to compile. Why? And why does the
code, as shown above, compile?
'y='? (note: the answer is not a specific value.) Why
does this happen?
warn ("x=%d y=%d", 3);
printf or its
interface so that it would still be possible to pass it a variable
number of arguments?
This completes the lab.