Use your memory manager from M2 to write a simple pager that supports on-demand memory mapping of an application and an allocate on demand memory heap.
The current implementation simply pre-maps in the pages for
the single binary. Any actual VM page faults will trigger an
assert() which halts the system, under the assumption something
has gone wrong. The executable itself is mapped in with untracked
frames (i.e. we leak them), and finally, the current sos
application malloc
implementation uses a static
array.
'malloc' is the standard library function to allocate memory in C. In our system, malloc is provided by the musl libc library. malloc manages memory from a bigger memory pool. In the SOS code you are provided, malloc uses memory from a pre-allocated array in the initial data section as the memory pool. This pool is fixed in size, and malloc fails when the pool is exhausted. See the diagram below for an approximate picture of the memory layout. The code musl uses to allocate memory from the static region for SOS is in apps/sos/src/sys/sys_morecore.c
SOS applications use an independent implementation that
uses a pre-allocated memory pool in the application's data section
(as shown in the middle of the diagram). The code musl libc uses in
applications is in libs/libsos/src/sys_morecore.c
. So
just for emphasis, there are two versions of the morecore code
in the system.
One of the tasks of this milestone is to leverage virtual memory to create a dynamically allocated memory region for malloc's use, usually termed the heap, as shown at the bottom of the diagram. The dynamic region is allocated on-demand via VM faults, and can be expanded in range dynamically by requesting that SOS increase the brk point.
In this milestone, you will modify the application-level
morecore routines in libs/libsos/src/sys_morecore.c
to use your dynamically-allocated memory region. Again, be sure
you're modifying the morecore routines for sos applications, not
SOS's own morecore routines.
The malloc
implementation in musl libc (i.e. the
application C library) has two behaviours for implementing
memory allocation of the memory pool:
brk
syscall that has similar
semantics to the Linux brk
syscall. The
current implementation is sys_brk
in libs/libsos/src/sys_morecore.c
and it returns
memory from a static array, as described above.malloc
is called to allocate more than
112KiB
, then musl libc does not allocate from
the heap or increase the heap via sys_brk
,
but instead it uses mmap
to create an large
anonymous mapping. The sample implementation of this is
the sys_mmap2
function
in libs/libsos/src/sys_morecore.c
and it
currently steals memory from the top of the static
morecore region, and leaks memory on when it's released
with munmap
In this milestone you will:
map_page()
. Your version
(say sos_map_page()
) will need to populate
and use your data structures to keep track of address
spaces, virtual addresses, frame physical addresses and
cptrs. Note: The existing map_page()
is used
internally and thus needs to continue to work as before,
so be careful if modifying it.sys_brk()
to use the heap memory region,
thus removing the need for a static array (just allow the
application to fault in memory within the heap region), as
shown at the bottom of the above diagram.
brk
system call to expand the
region. You can choose a fixed (large-ish) virtual
memory range. You can add a brk()
system call in a later milestone.mmap
syscall for anonymous memory
in this project. We don't expect you to support
applications calling malloc
for sizes
over 112KiB
(you can gracefully fail
those requests in the library). Note: there is a
small bonus available for those who do implement
mmap/munmap.
Probably the main thing that you should consider here is the layout of your processes address space. Some things you will want to consider is where you place various parts of memory such as the stack, heap and code segments. You may also have some other regions in your process address space, one of these is the IPC Buffer.
You should also think about if you want to make different ranges of the address space have different permissions, eg: you may want to make code read-only to prevent bugs, or have a guard page at the end of your stack to prevent overflow.
While not needed for this milestone, you should think about what book keeping is required to delete an address space and free all the resources associated with it.
The main demonstration here will be to show a user process running with a high stack pointer (> 0x20000000). You should also demonstrate a user process using malloc() from a heap.
#define NPAGES 27 /* called from pt_test */ static void do_pt_test( char *buf ) { int i; /* set */ for(i = 0; i < NPAGES; i ++) buf[i * 4096] = i; /* check */ for(i = 0; i < NPAGES; i ++) assert(buf[i * 4096] == i); } static void pt_test( void ) { /* need a decent sized stack */ char buf1[NPAGES * 4096], *buf2 = NULL; /* check the stack is above phys mem */ assert((void *) buf1 > (void *) 0x20000000); /* stack test */ do_pt_test(buf1); /* heap test */ buf2 = malloc(NPAGES * 4096); assert(buf2); do_pt_test(buf2); free(buf2); }
You should also be able to explain to the tutor how your code works and any design decisions you took.