diff --git a/docs/kernel/core_api/allocate-memory.md b/docs/kernel/core_api/allocate-memory.md index 15ba347c..96cfc416 100644 --- a/docs/kernel/core_api/allocate-memory.md +++ b/docs/kernel/core_api/allocate-memory.md @@ -8,7 +8,7 @@ DragonOS提供了一些用于内存分配的api。您可以使用*kmalloc*来分 您可以通过`kmalloc()`函数分配得到32bytes到1MBytes之间的内存对象。并且,这些内存对象具有以下的性质: -- 内存起始地址及大小按照2次幂对齐。(比如,申请的是80bytes的内存空间,那么内存对象大小为128bytes且内存地址按照128bytes对齐) +- 内存起始地址及大小按照2次幂对齐。(比如,申请的是80bytes的内存空间,那么获得的内存对象大小为128bytes且内存地址按照128bytes对齐) 对于需要大量连续内存的分配,可以使用`alloc_pages()`向页面分配器申请连续的内存页。 diff --git a/docs/kernel/core_api/index.rst b/docs/kernel/core_api/index.rst index 5d88dff5..90f15e26 100644 --- a/docs/kernel/core_api/index.rst +++ b/docs/kernel/core_api/index.rst @@ -20,4 +20,5 @@ .. toctree:: :maxdepth: 1 - allocate-memory \ No newline at end of file + allocate-memory + mm-api \ No newline at end of file diff --git a/docs/kernel/core_api/mm-api.md b/docs/kernel/core_api/mm-api.md new file mode 100644 index 00000000..f34294c4 --- /dev/null +++ b/docs/kernel/core_api/mm-api.md @@ -0,0 +1,220 @@ +# 内存管理API + +## SLAB内存池 + +SLAB内存池提供小内存对象的分配功能。 + +### `void *kmalloc(unsigned long size, unsigned long flags)` + +  获取小块的内存。 + +#### 描述 +  kmalloc用于获取那些小于2M内存页大小的内存对象。可分配的内存对象大小为32bytes~1MBytes. 且分配的内存块大小、起始地址按照2的n次幂进行对齐。(比如,申请的是80bytes的内存空间,那么获得的内存对象大小为128bytes且内存地址按照128bytes对齐) + +##### 参数 + +**size** + +  内存对象的大小 + +**flags** + +  标志位(暂时未实现,默认填0) + +### `unsigned long kfree(void *address)` + +  释放从slab分配的内存。 + +#### 描述 +  该函数用于释放通过kmalloc申请的内存。如果`address`为NULL,则函数被调用后,无事发生。 +  请不要通过这个函数释放那些不是从`kmalloc()`申请的内存,否则将会导致系统崩溃。 + +##### 参数 + +**address** + +  指向内存对象的起始地址的指针 + +## 物理页管理 + +DragonOS支持对物理页的直接操作 + +### `struct Page *alloc_pages(unsigned int zone_select, int num, ul flags)` + +#### 描述 + +  从物理页管理单元中申请一段连续的物理页 + +#### 参数 + +**zone_select** + +  要申请的物理页所位于的内存区域 + +可选值: + +- `ZONE_DMA` DMA映射专用区域 +- `ZONE_NORMAL` 正常的物理内存区域,已在页表高地址处映射 +- `ZONE_UNMAPPED_IN_PGT` 尚未在页表中映射的区域 + +**num** + +  要申请的连续物理页的数目,该值应当小于64 + +**flags** + +  分配的页面要被设置成的属性 + +可选值: +- `PAGE_PGT_MAPPED` 页面在页表中已被映射 +- `PAGE_KERNEL_INIT` 内核初始化所占用的页 +- `PAGE_DEVICE` 设备MMIO映射的内存 +- `PAGE_KERNEL` 内核层页 +- `PAGE_SHARED` 共享页 + +#### 返回值 + +##### 成功 + +  成功申请则返回指向起始页面的Page结构体的指针 + +##### 失败 + +  当ZONE错误或内存不足时,返回`NULL` + + +### `void free_pages(struct Page *page, int number)` + +#### 描述 + +  从物理页管理单元中释放一段连续的物理页。 + +#### 参数 + +**page** + +  要释放的第一个物理页的Page结构体 + +**number** + +  要释放的连续内存页的数量。该值应小于64 + +## 页表管理 + +### `int mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool use4k)` + +#### 描述 + +  将一段物理地址映射到当前页表的指定虚拟地址处 + +#### 参数 + +**virt_addr_start** + +  虚拟地址的起始地址 + +**phys_addr_start** + +  物理地址的起始地址 + +**length** + +  要映射的地址空间的长度 + +**flags** + +  页表项的属性 + +**use4k** + +  使用4级页表,将地址区域映射为若干4K页 + +### `int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user, bool flush, bool use4k)` + + +#### 描述 + +  将一段物理地址映射到指定页表的指定虚拟地址处 + +#### 参数 + +**proc_page_table_addr** + +  指定的顶层页表的起始地址 + +**is_phys** + +  该顶层页表地址是否为物理地址 + +**virt_addr_start** + +  虚拟地址的起始地址 + +**phys_addr_start** + +  物理地址的起始地址 + +**length** + +  要映射的地址空间的长度 + +**flags** + +  页表项的属性 + +**user** + +  页面是否为用户态可访问 + +**flush** + +  完成映射后,是否刷新TLB + +**use4k** + +  使用4级页表,将地址区域映射为若干4K页 + +#### 返回值 + +- 映射成功:0 +- 映射失败:-EFAULT + +### `void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul length)` + +#### 描述 + +  取消给定页表中的指定地址空间的页表项映射。 + +#### 参数 + +**proc_page_table_addr** + +  指定的顶层页表的基地址 + +**is_phys** + +  该顶层页表地址是否为物理地址 + +**virt_addr_start** + +  虚拟地址的起始地址 + +**length** + +  要取消映射的地址空间的长度 + +### `mm_unmap(virt_addr, length)` + +#### 描述 + +  该宏定义用于取消当前进程的页表中的指定地址空间的页表项映射。 + +#### 参数 + +**virt_addr** + +  虚拟地址的起始地址 + +**length** + +  要取消映射的地址空间的长度 diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index a3d4cf6a..e5e15a6f 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -372,8 +372,6 @@ struct Page *alloc_pages(unsigned int zone_select, int num, ul flags) } } kBUG("Cannot alloc page, ZONE=%d\tnums=%d, total_2M_pages=%d", zone_select, num, total_2M_pages); - while (1) - ; return NULL; } diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index 4dea1fb2..0786a942 100644 --- a/kernel/mm/mm.h +++ b/kernel/mm/mm.h @@ -58,10 +58,10 @@ // 页面在页表中已被映射 mapped=1 unmapped=0 #define PAGE_PGT_MAPPED (1 << 0) -// 内核初始化程序的页 init-code=1 normal-code/data=0 +// 内核初始化所占用的页 init-code=1 normal-code/data=0 #define PAGE_KERNEL_INIT (1 << 1) -// 1=设备寄存器映射的内存 0=物理内存 +// 1=设备MMIO映射的内存 0=物理内存 #define PAGE_DEVICE (1 << 2) // 内核层页 kernel=1 memory=0 diff --git a/kernel/mm/slab.c b/kernel/mm/slab.c index 4aa20194..9f13df84 100644 --- a/kernel/mm/slab.c +++ b/kernel/mm/slab.c @@ -1,6 +1,5 @@ #include "slab.h" - - +#include struct slab kmalloc_cache_group[16] = { @@ -396,7 +395,7 @@ ul slab_init() page_init(page, PAGE_KERNEL_INIT | PAGE_KERNEL | PAGE_PGT_MAPPED); } - //kdebug("2.memory_management_struct.bmp:%#018lx\tzone_struct->count_pages_using:%d\tzone_struct->count_pages_free:%d", *memory_management_struct.bmp, memory_management_struct.zones_struct->count_pages_using, memory_management_struct.zones_struct->count_pages_free); + // kdebug("2.memory_management_struct.bmp:%#018lx\tzone_struct->count_pages_using:%d\tzone_struct->count_pages_free:%d", *memory_management_struct.bmp, memory_management_struct.zones_struct->count_pages_using, memory_management_struct.zones_struct->count_pages_free); // 为slab内存池对象分配内存空间 ul *virt = NULL; @@ -417,7 +416,7 @@ ul slab_init() kmalloc_cache_group[i].cache_pool_entry->vaddr = virt; } - //kdebug("3.memory_management_struct.bmp:%#018lx\tzone_struct->count_pages_using:%d\tzone_struct->count_pages_free:%d", *memory_management_struct.bmp, memory_management_struct.zones_struct->count_pages_using, memory_management_struct.zones_struct->count_pages_free); + // kdebug("3.memory_management_struct.bmp:%#018lx\tzone_struct->count_pages_using:%d\tzone_struct->count_pages_free:%d", *memory_management_struct.bmp, memory_management_struct.zones_struct->count_pages_using, memory_management_struct.zones_struct->count_pages_free); kinfo("SLAB initialized successfully!"); @@ -550,7 +549,7 @@ void *kmalloc(unsigned long size, unsigned long flags) struct slab_obj *slab_obj_ptr = kmalloc_cache_group[index].cache_pool_entry; - //kdebug("count_total_free=%d", kmalloc_cache_group[index].count_total_free); + // kdebug("count_total_free=%d", kmalloc_cache_group[index].count_total_free); // 内存池没有可用的内存对象,需要进行扩容 if (kmalloc_cache_group[index].count_total_free == 0) @@ -617,6 +616,8 @@ void *kmalloc(unsigned long size, unsigned long flags) */ unsigned long kfree(void *address) { + if (unlikely(address == NULL)) + return 0; struct slab_obj *slab_obj_ptr = NULL; // 将线性地址按照2M物理页对齐, 获得所在物理页的起始线性地址