🆕 基本完成了slab内存分配器

This commit is contained in:
fslongjin 2022-02-28 16:15:44 +08:00
parent 828621dbbc
commit 36ad7a106e
7 changed files with 162 additions and 42 deletions

View File

@ -15,8 +15,8 @@ all: kernel
# cp kernel ../bin/kernel/kernel.elf # 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 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 process/process.o syscall/syscall.o driver/multiboot2/multiboot2.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 \ common/cpu.o \
driver/interrupt/8259A/8259A.o \ driver/interrupt/8259A/8259A.o \
-T link.lds -T link.lds
@ -52,6 +52,9 @@ irq.o: exception/irq.c
mm.o: mm/mm.c mm.o: mm/mm.c
gcc $(CFLAGS) -c mm/mm.c -o mm/mm.o 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 process.o: process/process.c
gcc $(CFLAGS) -c process/process.c -o process/process.o gcc $(CFLAGS) -c process/process.c -o process/process.o
syscall.o: syscall/syscall.c syscall.o: syscall/syscall.c

View File

@ -9,6 +9,7 @@
#include "exception/trap.h" #include "exception/trap.h"
#include "exception/irq.h" #include "exception/irq.h"
#include "mm/mm.h" #include "mm/mm.h"
#include "mm/slab.h"
#include "process/process.h" #include "process/process.h"
#include "syscall/syscall.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() void system_initialize()
{ {
@ -87,8 +133,9 @@ void system_initialize()
cpu_init(); cpu_init();
test_slab();
// 再初始化进程模块。顺序不能调转 // 再初始化进程模块。顺序不能调转
process_init(); // process_init();
} }
//操作系统内核从这里开始执行 //操作系统内核从这里开始执行

View File

@ -1,4 +1,5 @@
#include "mm.h" #include "mm.h"
#include "slab.h"
#include "../common/printk.h" #include "../common/printk.h"
#include "../common/kprint.h" #include "../common/kprint.h"
#include "../driver/multiboot2/multiboot2.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); // 内存管理单元所占据的序号最大的物理页 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) 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); 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(); flush_tlb();
kinfo("Memory management unit initialize complete!"); 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) if (!page->attr)
{ {
// 将bmp对应的标志位置位 // 将bmp对应的标志位置位
*(memory_management_struct.bmp + ((page->addr_phys >> PAGE_2M_SHIFT) >> 6)) |= 1UL << (page->addr_phys >> PAGE_2M_SHIFT) % 64; *(memory_management_struct.bmp + ((page->addr_phys >> PAGE_2M_SHIFT) >> 6)) |= 1UL << (page->addr_phys >> PAGE_2M_SHIFT) % 64;
page->attr = flags; page->attr = flags;
++(page->ref_counts); ++(page->ref_counts);

View File

@ -325,16 +325,17 @@ ul slab_free(struct slab *slab_pool, void *addr, ul arg)
*/ */
ul slab_init() ul slab_init()
{ {
kinfo("Initializing SLAB...");
// 将slab的内存池空间放置在mms的后方 // 将slab的内存池空间放置在mms的后方
ul tmp_addr = memory_management_struct.end_of_struct; ul tmp_addr = memory_management_struct.end_of_struct;
for (int i = 0; i < 16; ++i) 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; 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; kmalloc_cache_group[i].cache_pool->count_using = 0;
@ -345,8 +346,8 @@ ul slab_init()
// 在slab对象后方放置bmp // 在slab对象后方放置bmp
kmalloc_cache_group[i].cache_pool->bmp = (ul *)memory_management_struct.end_of_struct; kmalloc_cache_group[i].cache_pool->bmp = (ul *)memory_management_struct.end_of_struct;
// bmp后方预留4个unsigned long的空间防止内存越界,且按照8byte进行对齐 // bmp后方预留8个unsigned long的空间防止内存越界,且按照8byte进行对齐
memory_management_struct.end_of_struct += kmalloc_cache_group[i].cache_pool->bmp_len + ((sizeof(ul) << 2) & (~sizeof(ul) - 1)); 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 // @todo此处可优化直接把所有位设置为0然后再对部分不存在对应的内存对象的位设置为1
memset(kmalloc_cache_group[i].cache_pool->bmp, 0xff, kmalloc_cache_group[i].cache_pool->bmp_len); 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; struct Page *page = NULL;
// 将上面初始化内存池组时,所占用的内存页进行初始化 // 将上面初始化内存池组时,所占用的内存页进行初始化
ul tmp_page_mms_end = virt_2_phys(memory_management_struct.end_of_struct >> PAGE_2M_SHIFT); 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)
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 = 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); 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) 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 = Virt_To_2M_Page(virt);
page_init(page, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT); 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; 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; 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); 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; 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; 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) if (kmalloc_cache_group[index].count_total_free == 0)
@ -548,10 +555,10 @@ void *kmalloc(unsigned long size, unsigned long flags)
break; break;
} while (slab_obj_ptr != kmalloc_cache_group[index].cache_pool); } while (slab_obj_ptr != kmalloc_cache_group[index].cache_pool);
} }
// 寻找一块可用的内存对象 // 寻找一块可用的内存对象
int md; 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全部被使用 // 当前bmp全部被使用
if (*slab_obj_ptr->bmp + (i >> 6) == 0xffffffffffffffffUL) if (*slab_obj_ptr->bmp + (i >> 6) == 0xffffffffffffffffUL)
@ -560,8 +567,9 @@ void *kmalloc(unsigned long size, unsigned long flags)
continue; continue;
} }
md = i % 64; 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->bmp + (i >> 6)) |= (1UL << md);
++(slab_obj_ptr->count_using); ++(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_free;
++kmalloc_cache_group[index].count_total_using; ++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 * @brief
* *
* @param address * @param address 线
* @return unsigned long * @return unsigned long
*/ */
unsigned long kfree(void *address) 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;
} }

View File

@ -10,7 +10,8 @@
// SLAB存储池count_using不为空 // SLAB存储池count_using不为空
#define ESLAB_NOTNULL 101 #define ESLAB_NOTNULL 101
#define ENOT_IN_SLAB 102 #define ENOT_IN_SLAB 102 // 地址不在当前slab内存池中
#define ECANNOT_FREE_MEM 103 // 无法释放内存
struct slab_obj struct slab_obj
{ {

View File

@ -1,18 +1,3 @@
/***************************************************
*
*
* MINE
*
* 使
*
*
*
*
* EMail: 345538255@qq.com
*
*
***************************************************/
#ifndef __PTRACE_H__ #ifndef __PTRACE_H__
#define __PTRACE_H__ #define __PTRACE_H__

1
tools/bochsinit Normal file
View File

@ -0,0 +1 @@
c