This source file mainly describes the page allocation process.
Enum palloc_flags
{
Pal_assert = 001,/* panic on failure .*/
Pal_zero = 002,/* zero page contents .*/
Pal_user = 004/* user page .*/
};
Three States are available for page allocation,
Pal_assert: If the page cannot be allocated, the kernel panics
Pal_zero: The allocation page is cleared.
Pal_user: Split pages from the user pool.
The first two types are split pages from the kernel pool.
We divide the memory into two types. One is the user pool and the other is the kernel pool.
Struct pool
{
Struct lock;/* Mutual Exclusion .*/
Struct bitmap * used_map;/* bitmap of free pages .*/
Uint8_t * base;/* base of pool .*/
};
Here we use bitmap to indicate idle pages. This is similar to the bitmap index of the database.
Lock is used to search for bitmap and can only be atomic.
Void
Palloc_init (size_t user_page_limit)
{
/* Free memory starts at 1 MB and runs to the end of Ram .*/
Uint8_t * free_start = ptov (1024*1024); // start from 1 MB
Uint8_t * free_end = ptov (init_ram_pages * pgsize); // The end is the ram page * 4kb
Size_t free_pages = (free_end-free_start)/pgsize; // There are several blank pages
Size_t user_pages = free_pages/2; // if half of the space is less than user_page_limit, it will not change. If it is greater than user_page_limit, it will be reduced to this value.
Size_t kernel_pages ;//
If (user_pages> user_page_limit)
User_pages = user_page_limit;
Kernel_pages = free_pages-user_pages; // other idle pages are assigned to the kernel.
/* Give half of memory to kernel, half to user .*/
Init_pool (& kernel_pool, free_start, kernel_pages, "kernel pool ");
Init_pool (& user_pool, free_start + kernel_pages * pgsize,
User_pages, "user pool ");
}
This is the memory Shard, And the user_page_limit parameter is used to limit the size of the user pool to within this size.
Void *
Palloc_get_multiple (Enum palloc_flags flags, size_t page_cnt)
{
Struct pool * Pool = flags & pal_user? & User_pool: & kernel_pool; // select the pool type.
Void * pages;
Size_t page_idx;
If (page_cnt = 0) // The required page size is 0
Return NULL;
Lock_acquire (& Pool-> lock );
Page_idx = bitmap_scan_and_flip (pool-> used_map, 0, page_cnt, false); // find the page location of the first consecutive blank page of page_cnt, which is the page number.
Lock_release (& Pool-> lock );
If (page_idx! = Bitmap_error)
Pages = pool-> base + pgsize * page_idx; // locate the specific page location
Else
Pages = NULL;
If (pages! = NULL)
{
If (flags & pal_zero)
Memset (pages, 0, pgsize * page_cnt); // If pal_zero, the allocation must be cleared.
}
Else
{
If (flags & pal_assert)
Panic ("palloc_get: Out of pages ");
}
Return pages;
}
// Configure //-----------------------------------------------------------------------------------------------------
Static bool
Page_from_pool (const struct pool * Pool, void * Page)
{
Size_t page_no = pg_no (PAGE );
Size_t start_page = pg_no (pool-> base );
Size_t end_page = start_page + bitmap_size (pool-> used_map );
Return page_no> = start_page & page_no <end_page;
}
Pg_no is to convert the virtual address to its page number. Therefore, if page_no is between start_page and end_page, it indicates that the page has been allocated.
When free-page is used, set these pages to 0xcc.
// Configure //-------------------------------------------------------------------------------------------------------
Static void
Init_pool (struct pool * P, void * base, size_t page_cnt, const char * name)
// In addition to idle pages and bitmap in the pool, this is used for recording. Therefore, bm_pages is the number of pages occupied by bitmap.
The P pool is a pool of pages page_cnt starting from the base ,.
{
Size_t bm_pages = div_round_up (bitmap_buf_size (page_cnt), pgsize );
If (bm_pages> page_cnt) // If the size assigned to the pool cannot be attached to the bitmap. Not enough.
Panic ("not enough memory in % s for bitmap.", name );
Page_cnt-= bm_pages; // The page_cnt-bm_pages is really idle pages.
Printf ("% zu pages available in % S./N", page_cnt, name );
/* Initialize the pool .*/
Lock_init (& P-> lock );
P-> used_map = bitmap_create_in_buf (page_cnt, base, bm_pages * pgsize );
P-> base = base + bm_pages * pgsize; // The base address of the pool is the original base + bitmap_page * pgsize; this is the real base address. The base address of the pool is the base address of the bitmap space.
}
High
| <----- A pool
| ----------------------------------------------------------------------- | <----- Page_get_multiple ()
| Allocated space | Address
|
| ------------------------------------------------------------------------ | <----- Base (never changed)
| Div_round_up (bitmap_buf_size (page_cnt), pgsize); | <----- space to use for page_cnt
| ---------------------------------------------------------------------- | Low