物理内存管理

master
阳光少年 1 year ago
parent d1c8001c2b
commit d279b390aa

@ -5,6 +5,7 @@
#include <onix/onix.h>
#include <onix/printk.h>
#include <onix/assert.h>
#include <onix/stdlib.h>
#define PAGE_SIZE 0x1000 // 一页的大小 4K
@ -13,9 +14,11 @@
#define ZONE_VALID 1 // 可用内存区域
#define ZONE_RESERVED 2 // 不可用内存区域
#define IDX(addr) (((usize)addr) >> 12) // 获得 addr 的页索引, 每页是4k大小, 2的12次方 是4k, 地址直接除以4096就得到了地址所在页的索引
#define PAGE(idx) (((usize)addr) << 12) // 和上面相反, 这里是获得某个页的起始位置
void memory_init(u32 magic, u32* addr, u8* mem_struct_buffer_addr);
void memory_init(u32 magic, u32* addr, u8* mem_struct_buffer_addr); // 这个在strat.asm中调用
void memory_map_init(); // c程序调用
typedef struct mem_struct
{
@ -24,4 +27,10 @@ typedef struct mem_struct
u32 type; // 类型
} _packed mem_struct;
// 获得一页空闲的内存
static u32 get_page();
// 释放一页空闲的内存
static void put_page(u32 addr);
#endif

@ -14,6 +14,7 @@
#include <onix/clock.h>>
#include <onix/time.h>>
#include <onix/rtc.h>>
#include <onix/memory.h>>
void kernel_init();

@ -1,9 +1,19 @@
#ifndef ONIX_STDLIB_H
#define ONIX_STDLIB_H
#include <onix/types.h>
#define MAX(a, b) (a < b ? b : a)
#define MIN(a, b) (a < b ? a : b)
void delay (u32 count);
void hang();
u8 bcd_to_bin(u8 value);
u8 bin_to_bcd(u8 value);
// 计算 num 分成 size 的数量
u32 div_round_up(u32 num, u32 size);
#endif

@ -5,10 +5,10 @@
void kernel_init(){
// 初始化控制台
console_init();
// console_init();
// 初始化全局描述符
gdt_init();
// gdt_init();
// 初始化中断
interrupt_init();
@ -17,7 +17,7 @@ void kernel_init(){
// task_init();
// 初始化时钟中断
// clock_init();
clock_init();
// 初始化时间
// time_init();
@ -26,6 +26,9 @@ void kernel_init(){
// rtc_init();
memory_map_init();
memory_test();
asm volatile("sti\n");

@ -1,13 +1,14 @@
#include <onix/memory.h>
static usize memory_base = 0; // 可用内存基地址,应该等于 1M
static usize memory_base = 0; // 可用内存基地址,这个在调用完memory_init之后应该是 0x100000
static usize memory_size = 0; // 可用内存大小
static usize total_pages = 0; // 所有内存页数
static usize free_pages = 0; // 空闲内存页数
// 找到一块最大的物理页, 且是0x10000为初始位置的
// 找到一块最大的物理页, 且是0x100000为初始位置的
void memory_init(u32 magic, u32* mem_struct_count_addr, u8* mem_struct_buffer_addr){
printk("------ memory_init ------\n");
u32 mem_struct_count = *mem_struct_count_addr;
if(ONIX_MAGIC != magic) {
@ -37,6 +38,96 @@ void memory_init(u32 magic, u32* mem_struct_count_addr, u8* mem_struct_buffer_ad
printk("Memory size 0x%p\n", (u32)memory_size);
printk("free_pages %d\n", free_pages);
printk("total_pages %d\n", total_pages);
}
static u32 start_page = 0; // 可分配物理内存起始位置, 应该在管理页的后面
static u8 *memory_map; // 物理内存数组
static u32 memory_map_pages; // 物理内存数组占用的页数
// 初始化用来管理物理内存的 "管理者"数组
// 我们用 1位 表示1页是否被占用, 用来当做管理全部的页
// 这个在可用内存的最开头的位置
void memory_map_init(){
printk("------ memory_map_init ------\n");
// 初始化管理物理内存的数组, 我们用内存起始位置的开头, 来当做 "管理者"
memory_map = (u8*)memory_base;
// 计算管理者 占用的页数, (总页数 / 页大小 得到的就是管理 "总页数" 需要多少个 基础的"页" 保存每个页是否被占用)
memory_map_pages = div_round_up(total_pages, PAGE_SIZE);
printk("memory_map_pages: %d\n", memory_map_pages);
// 这些页已经被"管理者" 占用了, 需要去掉
free_pages -= memory_map_pages;
// 初始化 "管理者"
memset(memory_map, 0, PAGE_SIZE * memory_map_pages);
// 我们可用的只有0x100000之后的物理内存 且0x100000之后的前n页, 被我们的"管理者"所占用
// 这里设置 已经被占用的页的状态
start_page = IDX(MEMORY_BASE) + memory_map_pages;
for (usize i = 0; i < start_page; i++){
memory_map[i] = 1;
}
printk("free_pages %d\n", free_pages);
printk("total_pages %d\n", total_pages);
}
// 获得一页空闲的内存
static u32 get_page(){
for (usize i = start_page; i < total_pages; i++){
if (memory_map[i] == 0) {
memory_map[i] = 1;
// 不应该存在空闲页, 但是free_pages为0的情况
if (free_pages == 0) {
panic("free page size error");
}
// 得到页的初始位置
usize page = ((usize)i) << 12;
printk("get page is os: 0x%p\n", page);
free_pages -= 1;
return page;
}
}
// 同样的 也没有空闲页了
panic("Out of Memory");
}
// 释放一页空闲的内存
static void put_page(u32 addr){
// 禁止非页的起始位置传入进来
assert((addr & 0xfff) == 0);
usize idx = IDX(addr);
// 禁止idx小于start_page的页的起始地址传入进来, 禁止超过最大页
assert(idx >= start_page && idx < total_pages);
// 保证最少一个引用,这个也
assert(memory_map[idx] >= 1);
memory_map[idx] -= 1;
// 如果减去一之后被引用的数量为0, 说明这页内存没人使用, 空闲页+1
if (memory_map[idx] == 0) {
free_pages += 1;
}
// 保证free_page > 0
assert(free_pages > 0 && free_pages < total_pages);
printk("put page is os: 0x%p\n", addr);
}
void memory_test(){
usize size = 5;
usize pages[size];
for (usize i = 0; i < size; i++){
pages[i] = get_page();
}
for (usize i = 0; i < size; i++){
put_page(pages[i]);
}
}

@ -2,7 +2,9 @@
; 导入外部符号
extern kernel_init
extern console_init
extern memory_init
extern gdt_init
; 导出符号
global _start
@ -13,9 +15,11 @@ _start:
push ebx ; 内存结构体的数量 u32 ptr 起始位置
push eax ; magic
call console_init ; 控制台初始化
call gdt_init ; 全局描述符初始化
call memory_init ; 初始化内存
call kernel_init
; call kernel_init
jmp $

@ -16,4 +16,10 @@ u8 bcd_to_bin(u8 value){
}
u8 bin_to_bcd(u8 value){
return (value / 10) * 0x10 + (value % 10);
}
// 计算 num 分成 size 的数量
u32 div_round_up(u32 num, u32 size){
return (num + size - 1) / size;
}
Loading…
Cancel
Save