Let’s make your own operating system (#week_8_Page_Frame_Allocation)

Nimantha Gayan
4 min readSep 10, 2021

Hello, friends! This is the 8th week of my article series about creating my own operating system as a test. If you’ve read any of my earlier articles in this series, I believe it will help you grasp this section. In last week we talked about virtual memory and paging. In this week I’m going to talk about Page Frame Allocation. you can go through my last week article by this link.

Managing available memory

First, we need to know how much memory is available on the computer running the operating system. The easiest way to do this is to read it from the multiboot framework that GRUB gave us. GRUB collects the information we have about memory that is reserved, mapped I / O, read-only memory, etc., as reserved). One way to find out how much memory the kernel is using is to export labels at the beginning and end of the kernel binary from the linker script.

These labels can directly be read from assembly code and pushed on the stack to make them available to C code

extern kernel_virtual_start
extern kernel_virtual_end
extern kernel_physical_start
extern kernel_physical_end

; ...

push kernel_physical_end
push kernel_physical_start
push kernel_virtual_end
push kernel_virtual_start

call kmain

This way we get the labels as arguments to kmain. If you want to use C instead of assembly code, one way to do it is to declare the labels as functions and take the addresses of these functions.

void kernel_virtual_start(void);

/* ... */

unsigned int vaddr = (unsigned int) &kernel_virtual_start;

If you are using GRUB modules, you must ensure that the memory they are using is also marked as reserved. Note that available memory does not have to be contiguous. The first 1 MB contains several sections of memory allocated to I / O, as well as memory used by GRUB and the BIOS. Other parts of memory may not be available either. It is useful to divide the memory sections into full page frames because we cannot map some of the pages in memory.

Accessing a Page Frame

The page frame mapper returns the physical starting address of the page frame. This page frame is not mapped anywhere in the page table to this page frame. How can we read and write data to the frame?

We need to map the page frame to virtual memory by updating the PDT and / or PT used by the kernel. What if all the available side tables are full? So we can’t map the page frame to memory because we would need a new page table that occupies a full page frame and to write to that page frame we would have to map its page frame Somehow this circular dependency has to be done.

One solution is to reserve a part of the first page table used by the kernel (or some other higher-half page table) for temporarily mapping page frames to make them accessible. If the kernel is mapped at 0xC0000000 (page directory entry with index 768), and 4 KB page frames are used, then the kernel has at least one page table. If we assume - or limit us to - a kernel of size at most 4 MB minus 4 KB we can dedicate the last entry (entry 1023) of this page table for temporary mappings. The virtual address of pages mapped in using the last entry of the kernel’s PT will be

(768 << 22) | (1023 << 12) | 0x000 = 0xC03FF000

After we’ve temporarily mapped the page frame we want to use as a page table, and set it up to map in our first page frame, we can add it to the paging directory, and remove the temporary mapping.

A Kernel Heap

Previously, we could only work with fixed-size data or directly with raw storage. Now that we have a page frame mapper, we can implement malloc and use it freely in the kernel.

Kernighan and Ritchie [8] have an example implementation in their book [8] from which we can draw inspiration. The only change we need to make is to replace the calls to sbrk / brk with calls to the page frame allocator when more memory is needed. We also need to make sure that the page frames returned by the page frame mapper are mapped to virtual addresses. A correct implementation should also return page frames to the page frame allocator when calling free if sufficiently large blocks of memory are freed.

This is the end of this week. Hope to see you in next article.

Thank you for reading!!!

--

--

Nimantha Gayan

Software Engineering Undergraduate, University Of Kelaniya