From 36ad7a106eef6ef6bc3d9d26edbb57e73fbfb05e Mon Sep 17 00:00:00 2001 From: fslongjin Date: Mon, 28 Feb 2022 16:15:44 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BA=86slab=E5=86=85=E5=AD=98=E5=88=86=E9=85=8D=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/Makefile | 7 ++- kernel/main.c | 49 +++++++++++++++- kernel/mm/mm.c | 7 ++- kernel/mm/slab.c | 122 +++++++++++++++++++++++++++++++++------- kernel/mm/slab.h | 3 +- kernel/process/ptrace.h | 15 ----- tools/bochsinit | 1 + 7 files changed, 162 insertions(+), 42 deletions(-) create mode 100644 tools/bochsinit diff --git a/kernel/Makefile b/kernel/Makefile index 7af665d1..7c596ad2 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -15,8 +15,8 @@ all: kernel # cp kernel ../bin/kernel/kernel.elf -kernel: head.o entry.o main.o printk.o trap.o mm.o irq.o 8259A.o process.o syscall.o multiboot2.o cpu.o - ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o mm/mm.o process/process.o syscall/syscall.o driver/multiboot2/multiboot2.o \ +kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o 8259A.o process.o syscall.o multiboot2.o cpu.o + ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o mm/mm.o mm/slab.o process/process.o syscall/syscall.o driver/multiboot2/multiboot2.o \ common/cpu.o \ driver/interrupt/8259A/8259A.o \ -T link.lds @@ -52,6 +52,9 @@ irq.o: exception/irq.c mm.o: mm/mm.c gcc $(CFLAGS) -c mm/mm.c -o mm/mm.o +slab.o: mm/slab.c + gcc $(CFLAGS) -c mm/slab.c -o mm/slab.o + process.o: process/process.c gcc $(CFLAGS) -c process/process.c -o process/process.o syscall.o: syscall/syscall.c diff --git a/kernel/main.c b/kernel/main.c index b74e8e17..f50f54c2 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -9,6 +9,7 @@ #include "exception/trap.h" #include "exception/irq.h" #include "mm/mm.h" +#include "mm/slab.h" #include "process/process.h" #include "syscall/syscall.h" @@ -59,6 +60,51 @@ void test_mm() } */ +void test_slab() +{ + kinfo("Testing SLAB..."); + kinfo("Testing kmalloc()..."); + + for (int i = 1; i < 16; ++i) + { + printk_color(ORANGE, BLACK, "mem_obj_size: %ldbytes\t", kmalloc_cache_group[i].size); + printk_color(ORANGE, BLACK, "bmp(before): %#018lx\t", *kmalloc_cache_group[i].cache_pool->bmp); + + ul *tmp = kmalloc(kmalloc_cache_group[i].size, 0); + if (tmp == NULL) + { + kBUG("Cannot kmalloc such a memory: %ld bytes", kmalloc_cache_group[i].size); + } + + printk_color(ORANGE, BLACK, "bmp(middle): %#018lx\t", *kmalloc_cache_group[i].cache_pool->bmp); + + kfree(tmp); + + printk_color(ORANGE, BLACK, "bmp(after): %#018lx\n", *kmalloc_cache_group[i].cache_pool->bmp); + } + + // 测试自动扩容 + kmalloc(kmalloc_cache_group[15].size, 0); + kmalloc(kmalloc_cache_group[15].size, 0); + kmalloc(kmalloc_cache_group[15].size, 0); + kmalloc(kmalloc_cache_group[15].size, 0); + kmalloc(kmalloc_cache_group[15].size, 0); + kmalloc(kmalloc_cache_group[15].size, 0); + kmalloc(kmalloc_cache_group[15].size, 0); + + + struct slab_obj *slab_obj_ptr = kmalloc_cache_group[15].cache_pool; + int count=0; + do + { + kdebug("bmp(%d): addr=%#018lx\t value=%#018lx", count, slab_obj_ptr->bmp, *slab_obj_ptr->bmp); + + slab_obj_ptr = container_of(list_next(&slab_obj_ptr->list), struct slab_obj, list); + ++count; + } while (slab_obj_ptr != kmalloc_cache_group[15].cache_pool); + + kinfo("SLAB test completed!"); +} // 初始化系统各模块 void system_initialize() { @@ -87,8 +133,9 @@ void system_initialize() cpu_init(); + test_slab(); // 再初始化进程模块。顺序不能调转 - process_init(); + // process_init(); } //操作系统内核从这里开始执行 diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 9b7c2503..c7776f20 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -1,4 +1,5 @@ #include "mm.h" +#include "slab.h" #include "../common/printk.h" #include "../common/kprint.h" #include "../driver/multiboot2/multiboot2.h" @@ -176,7 +177,7 @@ void mm_init() // 初始化内存管理单元结构所占的物理页的结构体 ul mms_max_page = (virt_2_phys(memory_management_struct.end_of_struct) >> PAGE_2M_SHIFT); // 内存管理单元所占据的序号最大的物理页 - + printk("mms_max_page=%ld\n", mms_max_page); for (ul j = 0; j <= mms_max_page; ++j) { page_init(memory_management_struct.pages_struct + j, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT | PAGE_ACTIVE); @@ -187,6 +188,9 @@ void mm_init() flush_tlb(); kinfo("Memory management unit initialize complete!"); + + // 初始化slab内存池 + slab_init(); } /** @@ -204,7 +208,6 @@ unsigned long page_init(struct Page *page, ul flags) if (!page->attr) { // 将bmp对应的标志位置位 - *(memory_management_struct.bmp + ((page->addr_phys >> PAGE_2M_SHIFT) >> 6)) |= 1UL << (page->addr_phys >> PAGE_2M_SHIFT) % 64; page->attr = flags; ++(page->ref_counts); diff --git a/kernel/mm/slab.c b/kernel/mm/slab.c index 2eeed39a..34bc647a 100644 --- a/kernel/mm/slab.c +++ b/kernel/mm/slab.c @@ -325,16 +325,17 @@ ul slab_free(struct slab *slab_pool, void *addr, ul arg) */ ul slab_init() { + kinfo("Initializing SLAB..."); // 将slab的内存池空间放置在mms的后方 ul tmp_addr = memory_management_struct.end_of_struct; for (int i = 0; i < 16; ++i) { - // 将slab内存池对象的空间放置在mms的后面,并且预留4个unsigned long 的空间以防止内存越界 + // 将slab内存池对象的空间放置在mms的后面,并且预留8个unsigned long 的空间以防止内存越界 kmalloc_cache_group[i].cache_pool = (struct slab_obj *)memory_management_struct.end_of_struct; - memory_management_struct.end_of_struct += sizeof(struct slab_obj) + (sizeof(ul) << 2); + memory_management_struct.end_of_struct += sizeof(struct slab_obj) + (sizeof(ul) << 3); - list_init(&(kmalloc_cache_group[i].cache_pool->list)); + list_init(&kmalloc_cache_group[i].cache_pool->list); // 初始化内存池对象 kmalloc_cache_group[i].cache_pool->count_using = 0; @@ -345,8 +346,8 @@ ul slab_init() // 在slab对象后方放置bmp kmalloc_cache_group[i].cache_pool->bmp = (ul *)memory_management_struct.end_of_struct; - // bmp后方预留4个unsigned long的空间防止内存越界,且按照8byte进行对齐 - memory_management_struct.end_of_struct += kmalloc_cache_group[i].cache_pool->bmp_len + ((sizeof(ul) << 2) & (~sizeof(ul) - 1)); + // bmp后方预留8个unsigned long的空间防止内存越界,且按照8byte进行对齐 + memory_management_struct.end_of_struct = (ul)(memory_management_struct.end_of_struct + kmalloc_cache_group[i].cache_pool->bmp_len + (sizeof(ul) << 3)) & (~(sizeof(ul) - 1)); // @todo:此处可优化,直接把所有位设置为0,然后再对部分不存在对应的内存对象的位设置为1 memset(kmalloc_cache_group[i].cache_pool->bmp, 0xff, kmalloc_cache_group[i].cache_pool->bmp_len); @@ -360,18 +361,12 @@ ul slab_init() struct Page *page = NULL; // 将上面初始化内存池组时,所占用的内存页进行初始化 - ul tmp_page_mms_end = virt_2_phys(memory_management_struct.end_of_struct >> PAGE_2M_SHIFT); - for (int i = PAGE_2M_ALIGN(virt_2_phys(tmp_addr)); i < tmp_page_mms_end; ++i) + ul tmp_page_mms_end = virt_2_phys(memory_management_struct.end_of_struct) >> PAGE_2M_SHIFT; + + for (int i = PAGE_2M_ALIGN(virt_2_phys(tmp_addr)) >> PAGE_2M_SHIFT; i <= tmp_page_mms_end; ++i) { page = memory_management_struct.pages_struct + i; - // 下面注释掉的这部分工作貌似在page_init()里面已经做了 - // 在mms的bmp中,置位对应的位 - //*(memory_management_struct.bmp + ((page->addr_phys>>PAGE_2M_SHIFT)>>6)) |= 1UL<<((page->addr_phys >> PAGE_2M_SHIFT)%64); - - //++(page->zone->count_pages_using); - //--(page->zone->count_pages_free); - page_init(page, PAGE_KERNEL_INIT | PAGE_KERNEL | PAGE_PGT_MAPPED); } @@ -382,16 +377,26 @@ ul slab_init() for (int i = 0; i < 16; ++i) { // 获取一个新的空页并添加到空页表,然后返回其虚拟地址 - virt = (ul *)(PAGE_2M_ALIGN(memory_management_struct.end_of_struct + PAGE_2M_SIZE * i)); + virt = (ul *)((memory_management_struct.end_of_struct + PAGE_2M_SIZE * i + PAGE_2M_SIZE - 1) & PAGE_2M_MASK); + page = Virt_To_2M_Page(virt); page_init(page, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT); + + // 这里很神奇,给page赋值之后,list_next就会改变,我找不到原因,于是就直接重新初始化这个list好了 + // @todo: 找到这个bug的原因 kmalloc_cache_group[i].cache_pool->page = page; + list_init(&kmalloc_cache_group[i].cache_pool->list); + kmalloc_cache_group[i].cache_pool->vaddr = virt; } printk_color(ORANGE, BLACK, "3.memory_management_struct.bmp:%#018lx\tzone_struct->count_pages_using:%d\tzone_struct->count_pages_free:%d\n", *memory_management_struct.bmp, memory_management_struct.zones_struct->count_pages_using, memory_management_struct.zones_struct->count_pages_free); + + + kinfo("SLAB initialized successfully!"); + return 0; } @@ -520,6 +525,8 @@ void *kmalloc(unsigned long size, unsigned long flags) } struct slab_obj *slab_obj_ptr = kmalloc_cache_group[index].cache_pool; + + kdebug("count_total_free=%d",kmalloc_cache_group[index].count_total_free); // 内存池没有可用的内存对象,需要进行扩容 if (kmalloc_cache_group[index].count_total_free == 0) @@ -548,10 +555,10 @@ void *kmalloc(unsigned long size, unsigned long flags) break; } while (slab_obj_ptr != kmalloc_cache_group[index].cache_pool); } - // 寻找一块可用的内存对象 int md; - for (int i = 0; i < slab_obj_ptr->count_free; ++i) + kdebug("slab_obj_ptr->count_free=%d", slab_obj_ptr->count_free); + for (int i = 0; i < slab_obj_ptr->bmp_count; ++i) { // 当前bmp全部被使用 if (*slab_obj_ptr->bmp + (i >> 6) == 0xffffffffffffffffUL) @@ -560,8 +567,9 @@ void *kmalloc(unsigned long size, unsigned long flags) continue; } md = i % 64; + // 找到相应的内存对象 - if (*(slab_obj_ptr->bmp + (i >> 6)) & (1UL << md) == 0) + if ((*(slab_obj_ptr->bmp + (i >> 6)) & (1UL << md)) == 0) { *(slab_obj_ptr->bmp + (i >> 6)) |= (1UL << md); ++(slab_obj_ptr->count_using); @@ -570,7 +578,7 @@ void *kmalloc(unsigned long size, unsigned long flags) --kmalloc_cache_group[index].count_total_free; ++kmalloc_cache_group[index].count_total_using; - return (void*)((char*)slab_obj_ptr->vaddr+kmalloc_cache_group[index].size*i); + return (void *)((char *)slab_obj_ptr->vaddr + kmalloc_cache_group[index].size * i); } } @@ -581,10 +589,82 @@ void *kmalloc(unsigned long size, unsigned long flags) /** * @brief 通用内存释放函数 * - * @param address 要释放的内存地址 + * @param address 要释放的内存线性地址 * @return unsigned long */ unsigned long kfree(void *address) { - // @todo: 通用内存释放函数 + struct slab_obj *slab_obj_ptr = NULL; + + // 将线性地址按照2M物理页对齐, 获得所在物理页的起始线性地址 + void *page_base_addr = (void *)((ul)address & PAGE_2M_MASK); + + int index; + + for (int i = 0; i < 16; ++i) + { + slab_obj_ptr = kmalloc_cache_group[i].cache_pool; + + do + { + // 不属于当前slab_obj的管理范围 + if (slab_obj_ptr->vaddr != page_base_addr) + { + slab_obj_ptr = container_of(list_next(&slab_obj_ptr->list), struct slab_obj, list); + } + else + { + + // 计算地址属于哪一个内存对象 + index = (address - slab_obj_ptr->vaddr) / kmalloc_cache_group[i].size; + + + // 复位bmp + *(slab_obj_ptr->bmp + (index >> 6)) ^= 1UL << (index % 64); + + ++(slab_obj_ptr->count_free); + --(slab_obj_ptr->count_using); + ++kmalloc_cache_group[i].count_total_free; + --kmalloc_cache_group[i].count_total_using; + + // 回收空闲的slab_obj + // 条件:当前slab_obj_ptr的使用为0、总空闲内存对象>=当前slab_obj的总对象的2倍 且当前slab_pool不为起始slab_obj + if ((slab_obj_ptr->count_using == 0) && (kmalloc_cache_group[i].count_total_free >= ((slab_obj_ptr->bmp_count) << 1)) && (kmalloc_cache_group[i].cache_pool != slab_obj_ptr)) + { + switch (kmalloc_cache_group[i].size) + { + case 32: + case 64: + case 128: + case 256: + case 512: + // 在这种情况下,slab_obj是被安放在page内部的 + list_del(&slab_obj_ptr->list); + + kmalloc_cache_group[i].count_total_free -= slab_obj_ptr->bmp_count; + page_clean(slab_obj_ptr->page); + free_pages(slab_obj_ptr->page, 1); + break; + + default: + // 在这种情况下,slab_obj是被安放在额外获取的内存对象中的 + list_del(&slab_obj_ptr->list); + kmalloc_cache_group[i].count_total_free -= slab_obj_ptr->bmp_count; + + kfree(slab_obj_ptr->bmp); + + page_clean(slab_obj_ptr->page); + free_pages(slab_obj_ptr->page, 1); + + kfree(slab_obj_ptr); + break; + } + } + return 0; + } + + } while (slab_obj_ptr != kmalloc_cache_group[i].cache_pool); + } + kBUG("kfree(): Can't free memory."); + return ECANNOT_FREE_MEM; } \ No newline at end of file diff --git a/kernel/mm/slab.h b/kernel/mm/slab.h index 67ff3ffe..ef01d8de 100644 --- a/kernel/mm/slab.h +++ b/kernel/mm/slab.h @@ -10,7 +10,8 @@ // SLAB存储池count_using不为空 #define ESLAB_NOTNULL 101 -#define ENOT_IN_SLAB 102 +#define ENOT_IN_SLAB 102 // 地址不在当前slab内存池中 +#define ECANNOT_FREE_MEM 103 // 无法释放内存 struct slab_obj { diff --git a/kernel/process/ptrace.h b/kernel/process/ptrace.h index 7d05a7a0..ba03a2e0 100644 --- a/kernel/process/ptrace.h +++ b/kernel/process/ptrace.h @@ -1,18 +1,3 @@ -/*************************************************** -* 版权声明 -* -* 本操作系统名为:MINE -* 该操作系统未经授权不得以盈利或非盈利为目的进行开发, -* 只允许个人学习以及公开交流使用 -* -* 代码最终所有权及解释权归田宇所有; -* -* 本模块作者: 田宇 -* EMail: 345538255@qq.com -* -* -***************************************************/ - #ifndef __PTRACE_H__ #define __PTRACE_H__ diff --git a/tools/bochsinit b/tools/bochsinit new file mode 100644 index 00000000..f2ad6c76 --- /dev/null +++ b/tools/bochsinit @@ -0,0 +1 @@ +c