Browse Source

:new: 基本完成了slab内存分配器

fslongjin 3 years ago
parent
commit
36ad7a106e
7 changed files with 162 additions and 42 deletions
  1. 5 2
      kernel/Makefile
  2. 48 1
      kernel/main.c
  3. 5 2
      kernel/mm/mm.c
  4. 101 21
      kernel/mm/slab.c
  5. 2 1
      kernel/mm/slab.h
  6. 0 15
      kernel/process/ptrace.h
  7. 1 0
      tools/bochsinit

+ 5 - 2
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

+ 48 - 1
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();
 }
 
 //操作系统内核从这里开始执行

+ 5 - 2
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);

+ 101 - 21
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;
 }

+ 2 - 1
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
 {

+ 0 - 15
kernel/process/ptrace.h

@@ -1,18 +1,3 @@
-/***************************************************
-*		版权声明
-*
-*	本操作系统名为:MINE
-*	该操作系统未经授权不得以盈利或非盈利为目的进行开发,
-*	只允许个人学习以及公开交流使用
-*
-*	代码最终所有权及解释权归田宇所有;
-*
-*	本模块作者:	田宇
-*	EMail:		345538255@qq.com
-*
-*
-***************************************************/
-
 #ifndef __PTRACE_H__
 
 #define __PTRACE_H__

+ 1 - 0
tools/bochsinit

@@ -0,0 +1 @@
+c