12.7规划内存空间的分配
1MB以下给操作系统内核区使用,位图的uint8数组放在kernel后面(怎么找到kernel后面这个地址很有技巧)
1MB以上的内存给进程使用
我们需要知道可用内存的细节
//memory.c
//打印空闲区域的信息,分块打印
static void show_mem_info (boot_info_t * boot_info) {
log_printf("mem region:");
for (int i = 0; i < boot_info->ram_region_count; i++) {
log_printf("[%d]: 0x%x - 0x%x", i,
boot_info->ram_region_cfg[i].start,
boot_info->ram_region_cfg[i].size);
}
log_printf("\n");
}
/**
* @brief 获取整个可用的物理内存大小
*/
static uint32_t total_mem_size(boot_info_t * boot_info) {
int mem_size = 0;
// 简单起见,暂不考虑中间有空洞的情况
for (int i = 0; i < boot_info->ram_region_count; i++) {
mem_size += boot_info->ram_region_cfg[i].size;
}
return mem_size;
}
对空闲区域的内存进行位图化
/**
* @brief 初始化内存管理系统
*/
void memory_init (boot_info_t * boot_info) {
// 位图存放的位置
extern uint8_t * mem_free_start; //从source\kernel\kernel.lds中取出kernel末尾的地址,如下代码
log_printf("mem init.");
show_mem_info(boot_info);
// 在内核数据后面放物理页位图
uint8_t * mem_free = (uint8_t *)&mem_free_start; // 这个地方又加个&让我着实不太了解,这个地方是链接器要求的,先取地址再取值
// 计算1MB以上空间的空闲内存容量,并对齐的页边界
uint32_t mem_up1MB_free = total_mem_size(boot_info) - MEM_EXT_START; //1MB内存的地址
mem_up1MB_free = down2(mem_up1MB_free, MEM_PAGE_SIZE); // 需要对齐到4KB页大小
log_printf("Free memory: 0x%x, size: 0x%x", MEM_EXT_START, mem_up1MB_free);
// 4GB大小需要总共4*1024*1024*1024/4096/8=128KB的位图, 使用1MB的RAM空间中足够
// 该部分的内存仅跟在mem_free_start开始放置
addr_alloc_init(&paddr_alloc, mem_free, MEM_EXT_START, mem_up1MB_free, MEM_PAGE_SIZE);
mem_free += bitmap_byte_count(paddr_alloc.size / MEM_PAGE_SIZE);
// 到这里,mem_free应该比EBDA地址要小
ASSERT(mem_free < (uint8_t *)MEM_EBDA_START);
}
source\kernel\kernel.lds
SECTIONS
{
. = 0x10000;
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
PROVIDE(mem_free_start = .); //取出.bss后面的地址,这和链接器提供的功能有关
}
memory.h
#define MEM_EBDA_START 0x00080000 //那个不可访问区域(显存等保留区域)的起始地址
#define MEM_EXT_START (1024*1024) //1MB
#define MEM_PAGE_SIZE 4096 // 和页表大小一致,4KB
klib.h
// 对齐函数写成内联函数
// 向上对齐到页边界,向上对齐
static inline uint32_t up2 (uint32_t size, uint32_t bound) {
return (size + bound - 1) & ~(bound - 1);
}
// 向下对齐到界边界
static inline uint32_t down2 (uint32_t size, uint32_t bound) { //转换为bound的整数倍,向下取整
return size & ~(bound - 1);
}