diff --git a/src/include/onix/memory.h b/src/include/onix/memory.h index 370bd51..27f830c 100644 --- a/src/include/onix/memory.h +++ b/src/include/onix/memory.h @@ -5,6 +5,7 @@ #include #include #include +#include #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 \ No newline at end of file diff --git a/src/include/onix/onix.h b/src/include/onix/onix.h index b38419e..383e2bb 100644 --- a/src/include/onix/onix.h +++ b/src/include/onix/onix.h @@ -14,6 +14,7 @@ #include > #include > #include > +#include > void kernel_init(); diff --git a/src/include/onix/stdlib.h b/src/include/onix/stdlib.h index d0e8d0a..e050939 100644 --- a/src/include/onix/stdlib.h +++ b/src/include/onix/stdlib.h @@ -1,9 +1,19 @@ #ifndef ONIX_STDLIB_H #define ONIX_STDLIB_H #include + + +#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 \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index 4737c91..a63fb97 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -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"); diff --git a/src/kernel/memory.c b/src/kernel/memory.c index 9029018..5a1a221 100644 --- a/src/kernel/memory.c +++ b/src/kernel/memory.c @@ -1,13 +1,14 @@ #include -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]); + } } \ No newline at end of file diff --git a/src/kernel/start.asm b/src/kernel/start.asm index 6bafa45..6316af0 100644 --- a/src/kernel/start.asm +++ b/src/kernel/start.asm @@ -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 $ diff --git a/src/lib/stdlib.c b/src/lib/stdlib.c index d329865..8eb6b56 100644 --- a/src/lib/stdlib.c +++ b/src/lib/stdlib.c @@ -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; } \ No newline at end of file