3.5 Code: Physical memory allocator
The allocator resides in kalloc.c (kernel/kalloc.c:1).
The allocator’s data structure is a
free list
of physical memory pages that are available
for allocation.
Each free page’s list element is a
struct run
(kernel/kalloc.c:17).
Where does the allocator get the memory
to hold that data structure?
It store each free page’s
run
structure in the free page itself,
since there’s nothing else stored there.
The free list is
protected by a spin lock
(kernel/kalloc.c:21-24).
The list and the lock are wrapped in a struct
to make clear that the lock protects the fields
in the struct.
For now, ignore the lock and the calls to
acquire
and
release
;
Chapter 6 will examine
locking in detail.
The function
main
calls
kinit
to initialize the allocator
(kernel/kalloc.c:27).
kinit
initializes the free list to hold
every page between the end of the kernel and PHYSTOP.
Xv6 ought to determine how much physical
memory is available by parsing configuration information
provided by the hardware.
Instead xv6 assumes that the machine has
128 megabytes of RAM.
kinit
calls
freerange
to add memory to the free list via per-page calls to
kfree
.
A PTE can only refer to a physical address that is aligned
on a 4096-byte boundary (is a multiple of 4096), so
freerange
uses
PGROUNDUP
to ensure that it frees only aligned physical addresses.
The allocator starts with no memory;
these calls to
kfree
give it some to manage.
The allocator sometimes treats addresses as integers
in order to perform arithmetic on them (e.g.,
traversing all pages in
freerange
),
and sometimes uses addresses as pointers to read and
write memory (e.g., manipulating the
run
structure stored in each page);
this dual use of addresses is the main reason that the
allocator code is full of C type casts.
The function
kfree
(kernel/kalloc.c:47)
begins by setting every byte in the
memory being freed to the value 1.
This will cause code that uses memory after freeing it
(uses “dangling references”)
to read garbage instead of the old valid contents;
hopefully that will cause such code to break faster.
Then
kfree
prepends the page to the free list:
it casts
pa
to a pointer to
struct
run
,
records the old start of the free list in
r->next
,
and sets the free list equal to
r
.
kalloc
removes and returns the first element in the free list.