1、點陣圖和記憶體池:
位圖:點陣圖中的一位表示物理記憶體中的一頁是否被分配,api見blog:點陣圖api
位圖結構:
struct bitmap ;
struct pool ;
struct virtual_addr ;
3、初始化點陣圖和記憶體池:
uint32_t page_table_size = pg_size * 256; // 頁表大小= 1頁的頁目錄表+第0和第768個頁目錄項指向同乙個頁表+
// 第769~1022個頁目錄項共指向254個頁表,共256個頁框
uint32_t used_mem = page_table_size + 0x100000; // 0x100000為低端1m記憶體
uint32_t free_mem = all_mem - used_mem;
uint16_t all_free_pages = free_mem / pg_size; // 1頁為4k,不管總記憶體是不是4k的倍數,
uint16_t kernel_free_pages = all_free_pages / 2;
uint16_t user_free_pages = all_free_pages - kernel_free_pages;
uint32_t kbm_length = kernel_free_pages / 8; // kernel bitmap的長度,點陣圖中的一位表示一頁,以位元組為單位
uint32_t ubm_length = user_free_pages / 8; // user bitmap的長度.
uint32_t kp_start = used_mem; // kernel pool start,核心記憶體池的起始位址
uint32_t up_start = kp_start + kernel_free_pages * pg_size; // user pool start,使用者記憶體池的起始位址
kernel_pool.phy_addr_start = kp_start;
user_pool.phy_addr_start = up_start;
kernel_pool.pool_size = kernel_free_pages * pg_size;
user_pool.pool_size = user_free_pages * pg_size;
kernel_pool.pool_bitmap.btmp_bytes_len = kbm_length;
user_pool.pool_bitmap.btmp_bytes_len = ubm_length;
// 核心位圖位址為0xc009a000
kernel_pool.pool_bitmap.bits = (void*)mem_bitmap_base;
/* 使用者記憶體池的點陣圖緊跟在核心記憶體池位圖之後 */
user_pool.pool_bitmap.bits = (void*)(mem_bitmap_base + kbm_length);
/* 將位圖置0*/
bitmap_init(&kernel_pool.pool_bitmap);
bitmap_init(&user_pool.pool_bitmap);
/* 下面初始化核心虛擬位址的點陣圖,按實際物理記憶體大小生成陣列。*/
kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_length; // 用於維護核心堆的虛擬位址,所以要和核心記憶體池大小一致
/* 點陣圖的陣列指向一塊未使用的記憶體,目前定位在核心記憶體池和使用者記憶體池之外*/
kernel_vaddr.vaddr_bitmap.bits = (void*)(mem_bitmap_base + kbm_length + ubm_length);
kernel_vaddr.vaddr_start = k_heap_start;
bitmap_init(&kernel_vaddr.vaddr_bitmap);
實現邏輯:
(1)先在核心虛擬記憶體池中尋找空閒頁
(2)在物理記憶體池中尋找空閒頁
(2)編輯頁表,在虛擬記憶體和物理記憶體間建立對映
malloc_page ->
1、vaddr_get申請虛擬頁
2、palloc申請物理頁
3、page_table_add建立對映
malloc_page:
void* malloc_page(enum pool_flags pf, uint32_t pg_cnt) }
uint32_t vaddr = (uint32_t)vaddr_start, cnt = pg_cnt;
struct pool* mem_pool = pf & pf_kernel ? &kernel_pool : &user_pool;
/* 因為虛擬位址是連續的,但實體地址可以是不連續的,所以逐個做對映*/
while (cnt-- > 0)
page_table_add((void*)vaddr, page_phyaddr); // 在頁表中做對映
vaddr += pg_size; // 下乙個虛擬頁
}
static void* vaddr_get(enum pool_flags pf, uint32_t pg_cnt)
while(cnt < pg_cnt)
vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * pg_size;
} else
return (void*)vaddr_start;
}
二、palloc:在m_pool指向的記憶體池中分配乙個物理頁
static void* palloc(struct pool* m_pool)
bitmap_set(&m_pool->pool_bitmap, bit_idx, 1); // 將此位bit_idx置1
uint32_t page_phyaddr = ((bit_idx * pg_size) + m_pool->phy_addr_start);
return (void*)page_phyaddr;
}
static void page_table_add(void* _vaddr, void* _page_phyaddr) else
} else
}
如果沒有pde,則需要palloc乙個物理頁作為頁表項,並將其實體地址填入pde中
(1)獲取pde指標的方法:前20位填充1,後12位填充pde的索引
uint32_t* pde_ptr(uint32_t vaddr)
(2)獲取pte指標的方法:前10位填充1,中間十位填充pde索引,最後12位填充pte索引
uint32_t* pte_ptr(uint32_t vaddr)
實現動態分配記憶體
有些時候我們需要在記憶體主動申請記憶體來儲存我們的資料,實現動態分配記憶體的效果,標頭檔案 include 宣告了個關於記憶體動態分配的函式 malloc 函式 函式原型 void malloc usigned int size 作用 在記憶體的動態儲存區 堆區 中分配乙個長度為size的連續空間。...
記憶體的分配
malloc 動態從記憶體中申請乙個空間 如果申請成功,將返回這個空間的首位址 通過乙個指標接受這個空間的首位址 int p p malloc sizeof int p 234 free p 釋放這個動態申請的空間 1.結構體的定義 struct 結構體名 struct npc 2.建立結構體變數 ...
記憶體的分配
需要使用 include include include 呼叫malloc函式所需的標頭檔案 intmain printf you number is n for i 0 i 1 不同機器對於各型別大小定義不同,因此最好使用sizeof 函式求型別大小 free 釋放引數指向的記憶體空間 函式原型 ...