From d1c8001c2b0ade41f6f7e48c147c60a82adfbc0c Mon Sep 17 00:00:00 2001 From: yanguangshaonian Date: Tue, 18 Apr 2023 15:07:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E5=86=85=E5=AD=98?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 ++- src/Makefile | 1 + src/boot/loader.asm | 28 +++++++++++++------------- src/include/onix/memory.h | 27 +++++++++++++++++++++++++ src/include/onix/onix.h | 2 ++ src/include/onix/rtc.h | 2 ++ src/kernel/main.c | 6 ++++-- src/kernel/memory.c | 42 +++++++++++++++++++++++++++++++++++++++ src/kernel/rtc.c | 19 +++++++++--------- src/kernel/start.asm | 9 ++++++++- 10 files changed, 112 insertions(+), 27 deletions(-) create mode 100644 src/include/onix/memory.h create mode 100644 src/kernel/memory.c diff --git a/.vscode/settings.json b/.vscode/settings.json index 62a002c..94d98f9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,6 +27,7 @@ "*.inc": "c", "clock.h": "c", "time.h": "c", - "rtc.h": "c" + "rtc.h": "c", + "memory.h": "c" } } \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index a2833f7..6dd215a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -55,6 +55,7 @@ $(BUILD_PATH)/kernel.bin:$(BUILD_PATH)/kernel/start.o \ $(BUILD_PATH)/kernel/clock.o\ $(BUILD_PATH)/kernel/time.o\ $(BUILD_PATH)/kernel/rtc.o\ + $(BUILD_PATH)/kernel/memory.o\ $(shell mkdir -p $(dir $@)) ld -m elf_i386 -static $^ -o $@ -Ttext $(KERNEL_ENTRY_POINT) diff --git a/src/boot/loader.asm b/src/boot/loader.asm index d9c8fed..f086f8d 100644 --- a/src/boot/loader.asm +++ b/src/boot/loader.asm @@ -16,7 +16,7 @@ detect_memory: ; 设置检测内存的buffer位置 mov ax, 0 mov es, ax - mov edi, mem_task_buffer + mov edi, mem_struct_buffer ; 固定签名 mov edx, 0x534d4150 @@ -25,7 +25,7 @@ detect_memory: xor ebx, ebx ; 保存的目的地 - mov di, mem_task_buffer + mov di, mem_struct_buffer .next: ; 子功能号 @@ -40,7 +40,7 @@ detect_memory: ; 计算下一个内存结构体保存的首地址 add di, cx - inc word [mem_task_count] + inc word [mem_struct_count] ; 不为0 说明检查未完成 cmp ebx, 0 @@ -52,13 +52,13 @@ detect_memory: ret ; ; 循环结构体内的值(我们只读取低32位相关的信息, 高32位的暂时不需要) - ; mov cx, [mem_task_count] + ; mov cx, [mem_struct_count] ; ; 初始偏移量 ; mov si, 0 ; .show - ; mov eax, [mem_task_buffer + si] ; 基地址 低32位 - ; mov ebx, [mem_task_buffer + si + 8] ; 内存长度的低32位 - ; mov edx, [mem_task_buffer + si + 16] ; 本段内存类型 1: 可以使用, 2: 内存使用或者被保留中, 其他: 未定义 + ; mov eax, [mem_struct_buffer + si] ; 基地址 低32位 + ; mov ebx, [mem_struct_buffer + si + 8] ; 内存长度的低32位 + ; mov edx, [mem_struct_buffer + si + 16] ; 本段内存类型 1: 可以使用, 2: 内存使用或者被保留中, 其他: 未定义 ; add si, 20 ; ; xchg bx, bx ; bochs 的魔数, 代码执行到这里会停下 @@ -129,6 +129,9 @@ protect_mode: mov cl, 200 call read_disk + mov eax, 0x20220205 ; 内核魔数 + mov ebx, mem_struct_count ; 内存结构体 数量统计 + mov ecx, mem_struct_buffer ; 内存结构体 的起始位置 jmp dword code_selecter:0x10000 ud2 ; 执行到这里直接出错(不可能执行到这里) jmp $ @@ -232,11 +235,11 @@ error: ret .error_msg db "Loader Error!!!", 10, 13, 0 -mem_task_count: - dw 0 +mem_struct_count: ; 一共多少内存结构体 + dd 0 ; 用来存放检测内存结果的结构体 -mem_task_buffer: +mem_struct_buffer: times 20*10 db 0 @@ -273,12 +276,9 @@ gdt_start: db 0b_1_1_0_0_0000 | limit >> 16 ; G_D/B_L_AVL | 段界限16~19 db base >> 24 ; 段基址24~31 gdt_padding: - times 2<<16-($-gdt_start) db 0 + times 2<<15-($-gdt_start) db 0 gdt_end: - - - loading_log: db 'Loader Start', 13, 10, 0 diff --git a/src/include/onix/memory.h b/src/include/onix/memory.h new file mode 100644 index 0000000..370bd51 --- /dev/null +++ b/src/include/onix/memory.h @@ -0,0 +1,27 @@ +#ifndef ONIX_MEMORY_H +#define ONIX_MEMORY_H + +#include +#include +#include +#include + + +#define PAGE_SIZE 0x1000 // 一页的大小 4K +#define MEMORY_BASE 0x100000 // 1M,可用内存开始的位置 + +#define ZONE_VALID 1 // 可用内存区域 +#define ZONE_RESERVED 2 // 不可用内存区域 +#define IDX(addr) (((usize)addr) >> 12) // 获得 addr 的页索引, 每页是4k大小, 2的12次方 是4k, 地址直接除以4096就得到了地址所在页的索引 + + +void memory_init(u32 magic, u32* addr, u8* mem_struct_buffer_addr); + +typedef struct mem_struct +{ + u64 base; // 内存基地址 + u64 size; // 内存长度 + u32 type; // 类型 +} _packed mem_struct; + +#endif \ No newline at end of file diff --git a/src/include/onix/onix.h b/src/include/onix/onix.h index a38c8c3..b38419e 100644 --- a/src/include/onix/onix.h +++ b/src/include/onix/onix.h @@ -18,4 +18,6 @@ void kernel_init(); +#define ONIX_MAGIC 0x20220205 // 内核魔数, 用于校验错误 + #endif \ No newline at end of file diff --git a/src/include/onix/rtc.h b/src/include/onix/rtc.h index 11fdf0e..5456fb2 100644 --- a/src/include/onix/rtc.h +++ b/src/include/onix/rtc.h @@ -36,5 +36,7 @@ void cmos_write(u8 addr, u8 value); void rtc_init(); +void set_alarm(u32 secs); + #endif \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index e1568ca..4737c91 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -22,8 +22,10 @@ void kernel_init(){ // 初始化时间 // time_init(); - // 闹钟中断 - rtc_init(); + // 实时时钟中断 + // rtc_init(); + + asm volatile("sti\n"); diff --git a/src/kernel/memory.c b/src/kernel/memory.c new file mode 100644 index 0000000..9029018 --- /dev/null +++ b/src/kernel/memory.c @@ -0,0 +1,42 @@ + +#include + +static usize memory_base = 0; // 可用内存基地址,应该等于 1M +static usize memory_size = 0; // 可用内存大小 +static usize total_pages = 0; // 所有内存页数 +static usize free_pages = 0; // 空闲内存页数 + +// 找到一块最大的物理页, 且是0x10000为初始位置的 +void memory_init(u32 magic, u32* mem_struct_count_addr, u8* mem_struct_buffer_addr){ + u32 mem_struct_count = *mem_struct_count_addr; + + if(ONIX_MAGIC != magic) { + panic("memory magic error"); + } + + for (usize i = 0; i < mem_struct_count; i++){ + mem_struct* ms = (mem_struct*)(mem_struct_buffer_addr + sizeof(mem_struct) * i); + printk("Memory base 0x%p size 0x%p type %d\n", (u32)ms->base, (u32)ms->size, (u32)ms->type); + + // 找到最大的一块内存 + if (ms->type == ZONE_VALID && ms->size > memory_size) { + memory_base = (u32)ms->base; + memory_size = (u32)ms->size; + } + } + + assert(memory_base == MEMORY_BASE); // 内存开始的位置为 1M + assert((memory_size & 0xfff) == 0); // 要求按页对齐 + + free_pages = IDX(memory_size); + total_pages = free_pages + IDX(memory_base); + + + printk("mem_struct_count %d\n", mem_struct_count); + printk("Memory base 0x%p\n", (u32)memory_base); + printk("Memory size 0x%p\n", (u32)memory_size); + printk("free_pages %d\n", free_pages); + printk("total_pages %d\n", total_pages); + + +} \ No newline at end of file diff --git a/src/kernel/rtc.c b/src/kernel/rtc.c index fec8056..9713716 100644 --- a/src/kernel/rtc.c +++ b/src/kernel/rtc.c @@ -32,9 +32,8 @@ void rtc_handler(int handle_num) time_read(&time); u32 now_time = mktime(&time); if (next_time <= mktime(&time)) { - DEBUGK("rtc handler %d... %d %d \n", counter++, now_time, next_time); + DEBUGK("rtc handler %d... %d %d", counter++, now_time, next_time); next_time = 0xffffffff; - set_alarm(1); } } @@ -72,20 +71,22 @@ void set_alarm(u32 secs) } next_time = mktime(&time); + + printk("set alarm...\n"); + cmos_write(CMOS_B, 0b01000010); // bocsh 中无法打开闹钟中断, 未知bug, 这里使用周期中断 实现的伪闹钟 + cmos_read(CMOS_C); // 读 C 寄存器,以允许 CMOS 中断 } void rtc_init() { - cmos_write(CMOS_B, 0b01000010); // 打开周期中断 - // cmos_write(CMOS_B, 0b00100010); // 打开闹钟中断 - cmos_read(CMOS_C); // 读 C 寄存器,以允许 CMOS 中断 - - // 设置中断频率 - out_8(CMOS_A, (in_8(CMOS_A) & 0xf) | 0b1110); + // cmos_write(CMOS_B, 0b01000010); // 打开周期中断(当达到寄存器 A 中 RS 所设定的时间基准时,允许产生中断, 24小时制) + // // cmos_write(CMOS_B, 0b00100010); // 打开闹钟中断 + // cmos_read(CMOS_C); // 读 C 寄存器,以允许 CMOS 中断 - set_alarm(3); + // // 设置中断频率 + // out_8(CMOS_A, (in_8(CMOS_A) & 0xf) | 0b1110); // 250 ms 触发一次中断 // 设置自定义中断处理函数 set_interrupt_handler(IRQ_RTC, rtc_handler); diff --git a/src/kernel/start.asm b/src/kernel/start.asm index 6f3a257..6bafa45 100644 --- a/src/kernel/start.asm +++ b/src/kernel/start.asm @@ -2,13 +2,20 @@ ; 导入外部符号 extern kernel_init +extern memory_init ; 导出符号 global _start _start: - call kernel_init + push ecx ; 内存结构体的buffer起始位置 + push ebx ; 内存结构体的数量 u32 ptr 起始位置 + push eax ; magic + + call memory_init ; 初始化内存 + + ; call kernel_init jmp $