|
|
@@ -0,0 +1,106 @@
|
|
|
+#include "memory.h"
|
|
|
+#include "../lib/kernel/print.h"
|
|
|
+
|
|
|
+#define PG_SIZE 4096 // 1 页 = 4KB = 4096 字节
|
|
|
+/************************ 位图地址 ****************************************
|
|
|
+ * 0xc009f000 是内核主线程栈顶,0xc009e000 是内核主线程的pcb
|
|
|
+ * 一个页框大小的位图可表示128MB内存,位图位置安排在地址0xc009a000
|
|
|
+ * 0xc009e000 - 0x4000 = 0xc009a000
|
|
|
+ */
|
|
|
+#define MEM_BITMAP_BASE 0xc009a000
|
|
|
+/***********************************************************************/
|
|
|
+/*0xc0000000 是内核从虚拟地址 3G 起,0xc0100000 指跨过低端 1MB 内存,使虚拟地址在逻辑上连续 */
|
|
|
+#define K_HEAP_START 0xc0100000
|
|
|
+
|
|
|
+/* 内存池结构,生成两个实例用于管理内核内存池和用户内存池 */
|
|
|
+struct pool
|
|
|
+{
|
|
|
+ struct bitmap pool_bitmap; // 本内存池用到的位图结构,用于管理物理内存
|
|
|
+ uint32_t phy_addr_start; // 本内存池所管理物理内存的起始地址
|
|
|
+ uint32_t pool_size; // 本内存池字节容量
|
|
|
+};
|
|
|
+
|
|
|
+struct pool kernel_pool, user_pool; // 生成内核内存池和用户内存池
|
|
|
+struct virtual_addr kernel_vaddr; // 此结构是用来给内核分配虚拟地址
|
|
|
+
|
|
|
+/* 初始化内存池 */
|
|
|
+static void mem_pool_init(uint32_t all_mem)
|
|
|
+{
|
|
|
+ put_str(" mem_pool_init start\n");
|
|
|
+ // 页表大小 = 页目录项数 * 每个页目录项占用的字节数
|
|
|
+ // 页目录项数 = 1 页的页目录表 + 第 0 和第 768(内核页目录项)个页目录项指向同一个页表 +
|
|
|
+ // 第 769 ~ 1022 个页目录项指向 254 个页表 = 256 个页目录项
|
|
|
+ //! 最后 1 个页目录项(第 1023 个 pde)指向页目录表自身
|
|
|
+ uint32_t page_table_size = PG_SIZE * 256; // 256 个页目录项 * 4KB = 1MB
|
|
|
+
|
|
|
+ // 1024(0x400) * 1024 = 0x100000 是低端 1MB 内存
|
|
|
+ uint32_t used_mem = page_table_size + 0x100000;
|
|
|
+ uint32_t free_mem = all_mem - used_mem;
|
|
|
+ uint16_t all_free_pages = free_mem / PG_SIZE; // 1 页 = 4KB = 4096 字节
|
|
|
+
|
|
|
+ uint16_t kernel_free_pages = all_free_pages / 2;
|
|
|
+ uint16_t user_free_pages = all_free_pages - kernel_free_pages;
|
|
|
+
|
|
|
+ /* 为了简化操作,余数不处理,坏处是这样做会丢失内存,好像是不用做内存的越界检查,因为位图表的内存少于实际物理内存 */
|
|
|
+ uint32_t kbm_length = kernel_free_pages / 8; // Kernel BitMap 长度,位图中的一位表示一页,以字节为单位
|
|
|
+ uint32_t ubm_length = user_free_pages / 8; // User BitMap 长度
|
|
|
+
|
|
|
+ uint32_t kp_start = used_mem; // Kernel Pool 起始地址,内核内存池的起始地址
|
|
|
+ uint32_t up_start = kp_start + kernel_free_pages * PG_SIZE; // User Pool 起始地址,用户内存池的起始地址
|
|
|
+
|
|
|
+ kernel_pool.phy_addr_start = kp_start;
|
|
|
+ user_pool.phy_addr_start = up_start;
|
|
|
+
|
|
|
+ kernel_pool.pool_size = kernel_free_pages * PG_SIZE;
|
|
|
+ user_pool.pool_size = user_free_pages * PG_SIZE;
|
|
|
+
|
|
|
+ kernel_pool.pool_bitmap.btmp_bytes_len = kbm_length;
|
|
|
+ user_pool.pool_bitmap.btmp_bytes_len = ubm_length;
|
|
|
+
|
|
|
+ /********* 内核内存池和用户内存池的位图 ****************
|
|
|
+ * 位图是全局的数据,长度不固定
|
|
|
+ * 全局或静态的数组需要在编译时知道其长度
|
|
|
+ * 而我们需要根据总内存大小算出需要多少字节
|
|
|
+ * 所以改为指定一块内存来生成位图
|
|
|
+ ************************************************/
|
|
|
+ // 内核使用的最高地址是 0xc009f000,这是主线程的栈地址
|
|
|
+ // 内核的大小预计为 70KB 左右
|
|
|
+ // (32MB = 32 * 1024 * 1024 字节)内存占位图是 1KB
|
|
|
+ // 内核内存池位图的位置安排在地址 0xc009a000
|
|
|
+ kernel_pool.pool_bitmap.bits = (void *)MEM_BITMAP_BASE;
|
|
|
+ // 用户内存池的位图紧跟在内核内存池位图之后
|
|
|
+ user_pool.pool_bitmap.bits = (void *)((uintptr_t)MEM_BITMAP_BASE + kbm_length);
|
|
|
+
|
|
|
+ /********************** 输出内存池信息 ******************************/
|
|
|
+ put_str(" kernel_pool_bitmap_start: ");
|
|
|
+ put_int((uintptr_t)kernel_pool.pool_bitmap.bits);
|
|
|
+ put_str(", kernel_pool_phy_addr_start: ");
|
|
|
+ put_int(kernel_pool.phy_addr_start);
|
|
|
+ put_str("\n");
|
|
|
+ put_str(" user_pool_bitmap_start: ");
|
|
|
+ put_int((uintptr_t)user_pool.pool_bitmap.bits);
|
|
|
+ put_str(", user_pool_phy_addr_start: ");
|
|
|
+ put_int(user_pool.phy_addr_start);
|
|
|
+ put_str("\n");
|
|
|
+
|
|
|
+ bitmap_init(&kernel_pool.pool_bitmap);
|
|
|
+ bitmap_init(&user_pool.pool_bitmap);
|
|
|
+
|
|
|
+ /*********************** 初始化虚拟内存池 ********************************/
|
|
|
+ kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_length; // 虚拟地址位图的长度,按实际物理内存大小生成数组
|
|
|
+ /*位图的数组指向一块未使用的内存,目前定位在内核内存池和用户内存池之后*/
|
|
|
+ kernel_vaddr.vaddr_bitmap.bits = (void *)((uintptr_t)MEM_BITMAP_BASE + kbm_length + ubm_length);
|
|
|
+ kernel_vaddr.vaddr_start = K_HEAP_START;
|
|
|
+ bitmap_init(&kernel_vaddr.vaddr_bitmap);
|
|
|
+
|
|
|
+ put_str(" mem_pool_init end\n");
|
|
|
+}
|
|
|
+
|
|
|
+// 内存管理初始化
|
|
|
+void mem_init(void)
|
|
|
+{
|
|
|
+ put_str("mem_init start\n");
|
|
|
+ uint32_t mem_bytes_total = (*(uint32_t *)(0xb00)); // 从地址 0xb00 处取出总内存数
|
|
|
+ mem_pool_init(mem_bytes_total); // 初始化内存池
|
|
|
+ put_str("mem_init done\n");
|
|
|
+}
|