🆕 完成了简单的内存管理单元,能分配内存页面

This commit is contained in:
fslongjin 2022-01-28 16:31:40 +08:00
parent 8131264e3f
commit 98e62e1e19
4 changed files with 195 additions and 23 deletions

59
kernel/common/kprint.h Normal file
View File

@ -0,0 +1,59 @@
/**
* @file kprint.h
* @author longjin
* @brief
* @date 2022-01-28
*
* @copyright Copyright (c) 2022 longjin
*
*/
#pragma once
#include "printk.h"
#define kinfo(...) \
do \
{ \
printk("[ INFO ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0);
#define kdebug(...) \
do \
{ \
printk("[ DEBUG ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0);
#define kwarn(...) \
do \
{ \
printk("[ "); \
printk_color(YELLOW, BLACK, "WARN"); \
printk(" ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0);
#define kerror(...) \
do \
{ \
printk("[ "); \
printk_color(RED, BLACK, "ERROR"); \
printk(" ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0);
#define kterminated(...) \
do \
{ \
printk("[ "); \
printk_color(RED, BLACK, "TERMINATED"); \
printk(" ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0);

View File

@ -7,6 +7,7 @@
#include "exception/gate.h"
#include "exception/trap.h"
#include "mm/mm.h"
#include "common/kprint.h"
int *FR_address = (int *)0xffff800000a00000; //帧缓存区的地址
//char fxsave_region[512] __attribute__((aligned(16)));
@ -61,6 +62,23 @@ void test_printk()
printk("\nTest base 16 : %d --> %#X\n", 255, 255);
}
// 测试内存管理单元
void test_mm()
{
kinfo("Testing memory management unit...");
printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *memory_management_struct.bmp, *memory_management_struct.bmp + 1);
kinfo("Try to allocate 64 memory pages.");
struct Page *page = alloc_pages(ZONE_NORMAL, 64, PAGE_PGT_MAPPED | PAGE_ACTIVE | PAGE_KERNEL);
for (int i = 0; i <= 65; ++i)
{
printk("page%d\tattr:%#018lx\tphys_addr:%#018lx\t", i, page->attr, page->addr_phys);
++page;
if (((i + 1) % 2) == 0)
printk("\n");
}
printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *memory_management_struct.bmp, *memory_management_struct.bmp + 1);
}
void init()
{
// 初始化printk
@ -76,7 +94,6 @@ void init()
// 初始化中断描述符表
init_sys_vector();
//asm volatile(" fxsave %0 " ::"m"(fxsave_region));
// 初始化内存管理单元
printk("[ DragonOS ] Initializing memory manage unit...\n");
@ -87,7 +104,8 @@ void Start_Kernel(void)
{
init();
show_welcome();
//show_welcome();
test_mm();
//test_printk();

View File

@ -67,7 +67,6 @@ void mm_init()
memory_management_struct.bits_size = max_addr >> PAGE_2M_SHIFT; // 物理地址空间的最大页面数
memory_management_struct.bmp_len = ((unsigned long)((max_addr >> PAGE_2M_SHIFT) + sizeof(unsigned long) * 8 - 1) / 8) & (~(sizeof(unsigned long) - 1)); // bmp由多少个unsigned long变量组成
// 初始化bitmap 先将整个bmp空间全部置位。稍后再将可用物理内存页复位。
memset(memory_management_struct.bmp, 0xff, memory_management_struct.bmp_len);
@ -179,23 +178,22 @@ void mm_init()
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);
}
ul* cr3 = get_CR3();
ul *cr3 = get_CR3();
printk_color(INDIGO, BLACK, "cr3:\t%#018lx\n", cr3);
printk_color(INDIGO, BLACK, "*cr3:\t%#018lx\n", *(phys_2_virt(cr3))&(~0xff));
printk_color(INDIGO, BLACK, "**cr3:\t%#018lx\n", *phys_2_virt(*(phys_2_virt(cr3))&(~0xff))&(~0xff));
printk_color(INDIGO, BLACK, "*cr3:\t%#018lx\n", *(phys_2_virt(cr3)) & (~0xff));
printk_color(INDIGO, BLACK, "**cr3:\t%#018lx\n", *phys_2_virt(*(phys_2_virt(cr3)) & (~0xff)) & (~0xff));
// 消除一致性页表映射将页目录PML4E的前10项清空
for(int i=0;i<10;++i)
*(phys_2_virt(cr3)+i) = 0UL;
for (int i = 0; i < 10; ++i)
*(phys_2_virt(cr3) + i) = 0UL;
flush_tlb();
printk("[ INFO ] Memory management unit initialized.\n");
}
/**
@ -235,4 +233,81 @@ unsigned long page_init(struct Page *page, ul flags)
page->attr |= flags;
}
return 0;
}
/**
* @brief num个struct page
*
* @param zone_select , dma, mapped in pgt, unmapped in pgt
* @param num num<=64
* @param flags flag
* @return struct Page*
*/
struct Page *alloc_pages(unsigned int zone_select, int num, ul flags)
{
ul zone_start = 0, zone_end = 0;
switch (zone_select)
{
case ZONE_DMA:
// DMA区域
zone_start = 0;
zone_end = ZONE_DMA_INDEX;
break;
case ZONE_NORMAL:
zone_start = ZONE_DMA_INDEX;
zone_end = ZONE_NORMAL_INDEX;
break;
case ZONE_UNMAPPED_IN_PGT:
zone_start = ZONE_NORMAL_INDEX;
zone_end = ZONE_UNMAPED_INDEX;
break;
default:
printk("[ ");
printk_color(YELLOW, BLACK, "WARN");
printk(" ] In alloc_pages: param: zone_select incorrect.\n");
// 返回空
return NULL;
break;
}
for (int i = zone_start; i <= zone_end; ++i)
{
if ((memory_management_struct.zones_struct + i)->count_pages_free < num)
continue;
struct Zone *z = memory_management_struct.zones_struct + i;
// 区域对应的起止页号以及区域拥有的页面数
ul page_start = (z->zone_addr_start >> PAGE_2M_SHIFT);
ul page_end = (z->zone_addr_end >> PAGE_2M_SHIFT);
ul page_num = (z->zone_length >> PAGE_2M_SHIFT);
ul tmp = 64 - page_start % 64;
for (ul j = page_start; j <= page_end; j += ((j % 64) ? tmp : 64))
{
// 按照bmp中的每一个元素进行查找
// 先将p定位到bmp的起始元素
ul *p = memory_management_struct.bmp + (j >> 6);
ul shift = j % 64;
for (int k = shift; k < 64 - shift; ++k)
{
// 寻找连续num个空页
if (!(((*p >> k) | (*(p + 1) << (64 - k))) & (num == 64 ? 0xffffffffffffffffUL : ((1 << num) - 1))))
{
ul start_page_num = j + k - shift; // 计算得到要开始获取的内存页的页号(书上的公式有问题,这个是改过之后的版本)
for(int l=0;l<num;++l)
{
struct Page* x = memory_management_struct.pages_struct+start_page_num+l;
page_init(x, flags);
}
// 成功分配了页面,返回第一个页面的指针
return (struct Page*)(memory_management_struct.pages_struct+start_page_num);
}
}
}
}
}

View File

@ -30,6 +30,14 @@
#define virt_2_phys(addr) ((unsigned long)(addr)-KERNEL_BASE_ADDR)
#define phys_2_virt(addr) ((unsigned long *)((unsigned long)(addr) + KERNEL_BASE_ADDR))
// ===== 内存区域属性 =====
// DMA区域
#define ZONE_DMA (1<<0)
// 已在页表中映射的区域
#define ZONE_NORMAL (1<<1)
// 未在页表中映射的区域
#define ZONE_UNMAPPED_IN_PGT (1<<2)
// ===== 页面属性 =====
// 页面在页表中已被映射
#define PAGE_PGT_MAPPED (1 << 0)
@ -52,6 +60,23 @@
// slab内存分配器的页
#define PAGE_SLAB (1 << 9)
/**
* @brief TLB的宏定义
* cr3的操作都会刷新TLBTLB
*/
#define flush_tlb() \
do \
{ \
ul tmp; \
__asm__ __volatile__( \
"movq %%cr3, %0\n\t" \
"movq %0, %%cr3\n\t" \
: "=r"(tmp)::"memory"); \
\
} while (0);
// Address Range Descriptor Structure 地址范围描述符
struct ARDS
{
@ -168,16 +193,11 @@ unsigned long *get_CR3()
}
/**
* @brief TLB的宏定义
* cr3的操作都会刷新TLBTLB
* @brief num个struct page
*
* @param zone_select , dma, mapped in pgt, unmapped in pgt
* @param num num<=64
* @param flags flag
* @return struct Page*
*/
#define flush_tlb() \
do \
{ \
ul tmp; \
__asm__ __volatile__( \
"movq %%cr3, %0\n\t" \
"movq %0, %%cr3\n\t" \
: "=r"(tmp)::"memory"); \
\
} while (0);
struct Page* alloc_pages(unsigned int zone_select, int num, ul flags);