Browse Source

doc: 内存管理api

fslongjin 2 years ago
parent
commit
1b4f812fe4

+ 1 - 1
docs/kernel/core_api/allocate-memory.md

@@ -8,7 +8,7 @@ DragonOS提供了一些用于内存分配的api。您可以使用*kmalloc*来分
 
 
 您可以通过`kmalloc()`函数分配得到32bytes到1MBytes之间的内存对象。并且,这些内存对象具有以下的性质:
 您可以通过`kmalloc()`函数分配得到32bytes到1MBytes之间的内存对象。并且,这些内存对象具有以下的性质:
 
 
-- 内存起始地址及大小按照2次幂对齐。(比如,申请的是80bytes的内存空间,那么内存对象大小为128bytes且内存地址按照128bytes对齐)
+- 内存起始地址及大小按照2次幂对齐。(比如,申请的是80bytes的内存空间,那么获得的内存对象大小为128bytes且内存地址按照128bytes对齐)
 
 
 对于需要大量连续内存的分配,可以使用`alloc_pages()`向页面分配器申请连续的内存页。
 对于需要大量连续内存的分配,可以使用`alloc_pages()`向页面分配器申请连续的内存页。
 
 

+ 2 - 1
docs/kernel/core_api/index.rst

@@ -20,4 +20,5 @@
 .. toctree::
 .. toctree::
    :maxdepth: 1
    :maxdepth: 1
 
 
-   allocate-memory
+   allocate-memory
+   mm-api

+ 220 - 0
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**
+
+  要取消映射的地址空间的长度

+ 0 - 2
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);
     kBUG("Cannot alloc page, ZONE=%d\tnums=%d, total_2M_pages=%d", zone_select, num, total_2M_pages);
-    while (1)
-        ;
     return NULL;
     return NULL;
 }
 }
 
 

+ 2 - 2
kernel/mm/mm.h

@@ -58,10 +58,10 @@
 // 页面在页表中已被映射 mapped=1 unmapped=0
 // 页面在页表中已被映射 mapped=1 unmapped=0
 #define PAGE_PGT_MAPPED (1 << 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)
 #define PAGE_KERNEL_INIT (1 << 1)
 
 
-// 1=设备寄存器映射的内存 0=物理内存
+// 1=设备MMIO映射的内存 0=物理内存
 #define PAGE_DEVICE (1 << 2)
 #define PAGE_DEVICE (1 << 2)
 
 
 // 内核层页 kernel=1 memory=0
 // 内核层页 kernel=1 memory=0

+ 6 - 5
kernel/mm/slab.c

@@ -1,6 +1,5 @@
 #include "slab.h"
 #include "slab.h"
-
-
+#include <common/compiler.h>
 
 
 struct slab kmalloc_cache_group[16] =
 struct slab kmalloc_cache_group[16] =
     {
     {
@@ -396,7 +395,7 @@ ul slab_init()
         page_init(page, PAGE_KERNEL_INIT | PAGE_KERNEL | PAGE_PGT_MAPPED);
         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内存池对象分配内存空间
     // 为slab内存池对象分配内存空间
     ul *virt = NULL;
     ul *virt = NULL;
@@ -417,7 +416,7 @@ ul slab_init()
 
 
         kmalloc_cache_group[i].cache_pool_entry->vaddr = virt;
         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!");
     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;
     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)
     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)
 unsigned long kfree(void *address)
 {
 {
+    if (unlikely(address == NULL))
+        return 0;
     struct slab_obj *slab_obj_ptr = NULL;
     struct slab_obj *slab_obj_ptr = NULL;
 
 
     // 将线性地址按照2M物理页对齐, 获得所在物理页的起始线性地址
     // 将线性地址按照2M物理页对齐, 获得所在物理页的起始线性地址