One of the many neat tricks an OS can play with paging
is lazy allocation of heap memory. On xv6, applications ask
the kernel for heap memory using the sbrk()
system call. In the
kernel we’ve given you, sbrk()
allocates physical memory and maps
it into the process’s virtual address space. There are programs
that allocate memory but never use it, for example to implement
large sparse arrays. Sophisticated kernels delay allocation of each
page of memory until the application tries to use that page—as
signaled by a page fault. You’ll add this lazy allocation feature
to xv6 in this exercise.
sbrk()
Your first task is to delete page allocation from the sbrk(n)
system
call implementation, which is function sys_sbrk()
in sysproc.c
. The
sbrk(n)
system call grows the process’s memory size by n
bytes, and
then returns the start of the newly allocated region (i.e., the old
size). Your new sbrk(n)
should just increment the process’s size
(proc->sz
) by n
and return the old size. It should not allocate
memory—so you should delete the call to growproc()
.
Try to guess what the result of this modification will be and what will break.
Make this modification, boot xv6, and type echo hi to the shell. You should see something like this:
The “pid 3 sh: trap…” message is from the kernel trap handler in
trap.c
; it has caught a page fault (trap 14, or T_PGFLT
), which the
xv6 kernel does not know how to handle. Make sure you understand
why this page fault occurs. The “addr 0x4004” indicates that the
virtual address that caused the page fault is 0x4004
.
Modify the code in trap.c
to respond to a page fault from user space
by mapping a newly allocated page of physical memory at the faulting
address, and then returning back to user space to let the process
continue executing. Add your code before the cprintf
call that produced the “pid 3 sh: trap 14” message. Your code is
not required cover all corner cases and error situations; it just
needs to be good enough to let sh
run simple commands like echo
and ls
.
tf->trapno
is equal to T_PGFLT
in trap()
.cprintf
arguments.PGROUNDDOWN(va)
to round the faulting virtual address down to a page boundary.allocuvm()
in vm.c
, which is what sbrk()
calls (via growproc()
).cprintf
and the proc->killed = 1
.If all goes well, your lazy allocation code should result in echo hi working. You should get at least one page fault (and thus lazy allocation) in the shell, and perhaps two.
By the way, this is not a fully correct implementation.
Challenges:
sbrk()
arguments.sbrk()
arguments that are too large.fork()
and exit()
work even if some sbrk()
‘d
address have no memory allocated for them.sbrk()
-allocated address
to read()
.