My Operating system Development Experience and understanding -Part 08

M.R.M Abdullah
4 min readSep 10, 2021

Hello developers…!

in this article we are going to understand about Page Frame Allocation in OS development. Before that if you don’t read my previous OS development Articles please go and check those from below links

  1. My Operating system Development Experience and understanding. Part 01 -Setting Up environments
  2. My Operating system Development Experience and understanding -Part 02- C instead of assembly
  3. My Operating system Development Experience and understanding -Part 03-implement Drivers
  4. My Operating system Development Experience and understanding -Part 04-Segmentation in OS development
  5. My Operating system Development Experience and understanding -Part 05-nterrupts and inputs
  6. My Operating system Development Experience and understanding -Part 06-user modes
  7. My Operating system Development Experience and understanding -Part 07-virtual memory paging

let get into todays Topics

Managing Available Memory

First, we must determine how much RAM is accessible on the computer on which the OS is installed. Reading it from the multiboot structure supplied to us by GRUB is the simplest way to do it.
GRUB gathers the memory information we require, such as what is reserved, I/O mapped, read-only, and so on. We must additionally ensure that the memory used by the kernel is not marked as free (because GRUB does not identify this memory as reserved). Exporting labels at the beginning and end of the kernel binary from the linker script is one technique to figure out how much RAM the kernel uses:

These labels can be read directly from assembly code and pushed into the stack so that C code can access them:

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

As I previously stated, we can obtain the labels as arguments to kmain in this manner. We can declare the labels as functions and take the addresses of these functions if we wish to utilize C instead of assembly code:

void kernel_virtual_start(void); /*the function*/

/* … */

unsigned int vaddr = (unsigned int) &kernel_virtual_start;
/*Taking the address to a variable*/

Because we’re utilizing GRUB modules, we’ll need to ensure that the RAM they utilize is also marked as reserved. (I hope you recall that in a previous stage, we used modules to develop a basic program that pushed a number into the EAX register.)

It’s important to remember that the accessible memory doesn’t have to be in any particular order. However, because we can’t map parts of pages into memory, it’s easier to partition the memory regions into whole page frames.

How Can We Access a Page Frame?

What method do we use to determine which page frames are in use? The page frame allocator is one of the most crucial methods you’ll have to develop. The page frame allocator keeps track of which frames are available and which are not. Bitmaps, linked lists, trees, the Buddy System (used by Linux), and other techniques can be used to do this.
Bitmaps are quite simple to use. Each page frame uses one bit, and one (or more) page frames are allocated to storing the bitmap.

Bitmap

As a huge bit map of memory consumption, a large array of N/8 bytes is employed (bit I in byte #n defines page #n*8+i status). Allocating a page may take time (O(N)), while setting the state of a particular page is quick (O(1)).

Up to 32 bits can be tested at once with an uint32 t comparison, which speeds up allocations.

The performance of the next search may be improved by keeping a pointer to the last allocated bit (keeping information about the fact all the previous bytes were searched unsuccessfully)

The page frame allocator returns the physical start address of a free page frame after execution. This signifies that this page frame isn’t mapped in or that no page table refers to it.

So, how do we get data into and out of the frame?

We must first map this page frame into virtual memory by modifying the kernel’s Page Directory Table and/or Page Table.
However, there will be a conflict if all accessible page tables are full. In this scenario, we can’t map the page frame into memory since we’d need a new page table that takes up the entire page frame, and we’d have to map the page frame to write to it. Somehow, this circular reliance must be broken.

Setting aside a piece of the kernel’s first page table (or another higher-half page table) for temporarily mapping page frames to make them available is one solution. If the kernel is mapped at 0xC0000000 (page directory entry with index 768) and 4 KB page frames are used, the kernel has at least one page table. If we assume — or limit ourselves to — a kernel with a maximum size of 4 MB minus 4 KB, we can dedicate the last item (entry 1023) of this page table to temporary mappings. Pages mapped in with the kernel’s PT’s last entry will have the following virtual address:

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

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

We’ve only been able to operate with fixed-size data or raw memory up until now. We can implement malloc and free to use in the kernel now that we have a page frame allocator. When sufficiently large blocks of memory are freed, a proper implementation should also return page frames to the page frame allocator on call to free.

That’s all there is to it when it comes to page frame allocation! With this post, I hope you gained a better knowledge of page frame allocation. Be inspired until we meet again with another great topic! Continue to learn! :)

see you :)

Abdullah M.R.M

--

--

M.R.M Abdullah

Software Engineering undergraduate at University of Kelaniya.