🆕 完成了初始化内存管理单元的代码

This commit is contained in:
fslongjin 2022-01-28 14:46:15 +08:00
parent 134692fa85
commit 8131264e3f
5 changed files with 403 additions and 22 deletions

View File

@ -114,8 +114,9 @@ static inline int strlen(char *s)
inline void *memset(void *dst, unsigned char C, ul Count)
void *memset(void *dst, unsigned char C, ul Count)
{
int d0, d1;
unsigned long tmp = C * 0x0101010101010101UL;
__asm__ __volatile__("cld \n\t"
@ -136,3 +137,10 @@ inline void *memset(void *dst, unsigned char C, ul Count)
: "memory");
return dst;
}
void *memset_c(void *dst, unsigned char c, ul n)
{
unsigned char *s = (unsigned char *)dst;
for(int i=0;i<n;++i)
s[i] = c;
return dst;
}

View File

@ -9,7 +9,9 @@
#include "mm/mm.h"
int *FR_address = (int *)0xffff800000a00000; //帧缓存区的地址
char fxsave_region[512] __attribute__((aligned(16)));
//char fxsave_region[512] __attribute__((aligned(16)));
struct memory_desc memory_management_struct = {{0}, 0};
void show_welcome()
{
@ -75,7 +77,7 @@ void init()
init_sys_vector();
asm volatile(" fxsave %0 " ::"m"(fxsave_region));
//asm volatile(" fxsave %0 " ::"m"(fxsave_region));
// 初始化内存管理单元
printk("[ DragonOS ] Initializing memory manage unit...\n");
mm_init();

View File

@ -2,28 +2,237 @@
#include "../common/printk.h"
ul Total_Memory = 0;
ul total_2M_pages = 0;
void mm_init()
{
printk("[ INFO ] Initializing memory management unit...\n");
// 实模式下获取到的信息的起始地址转换为ARDS指针
struct ARDS *ards_ptr = (struct ARDS *)0xffff800000007e00;
for (int i = 0; i < 32; ++i)
{
printk("Addr = %#10lx,%8lx\tLength = %#10lx,%8lx\tType = %#10lx\n",
ards_ptr->BaseAddrH, ards_ptr->BaseAddrL, ards_ptr->LengthH, ards_ptr->LengthL, ards_ptr->type);
//printk("Addr = %#18lx\tLength = %#18lx\tType = %#10lx\n",
// ards_ptr->BaseAddr, ards_ptr->Length, ards_ptr->type);
//可用的内存
if (ards_ptr->type == 1)
{
Total_Memory += ards_ptr->LengthL;
Total_Memory += ((ul)(ards_ptr->LengthH)) << 32;
}
Total_Memory += ards_ptr->Length;
// 保存信息到mms
memory_management_struct.e820[i].BaseAddr = ards_ptr->BaseAddr;
memory_management_struct.e820[i].Length = ards_ptr->Length;
memory_management_struct.e820[i].type = ards_ptr->type;
memory_management_struct.len_e820 = i;
++ards_ptr;
// 脏数据
if (ards_ptr->type > 4)
if (ards_ptr->type > 4 || ards_ptr->Length == 0 || ards_ptr->type < 1)
break;
}
printk_color(ORANGE, BLACK, "Total amount of RAM DragonOS can use: %ld bytes\n", Total_Memory);
printk("[ INFO ] Total amounts of RAM : %ld bytes\n", Total_Memory);
// 计算有效内存页数
for (int i = 0; i < memory_management_struct.len_e820; ++i)
{
if (memory_management_struct.e820[i].type != 1)
continue;
// 将内存段的起始物理地址按照2M进行对齐
ul addr_start = PAGE_2M_ALIGN(memory_management_struct.e820[i].BaseAddr);
// 将内存段的终止物理地址的低2M区域清空以实现对齐
ul addr_end = ((memory_management_struct.e820[i].BaseAddr + memory_management_struct.e820[i].Length) & PAGE_2M_MASK);
// 内存段不可用
if (addr_end <= addr_start)
continue;
total_2M_pages += ((addr_end - addr_start) >> PAGE_2M_SHIFT);
}
printk("[ INFO ] Total amounts of 2M pages : %ld.\n", total_2M_pages);
// 设置内核程序不同部分的起止地址
memory_management_struct.kernel_code_start = (ul)&_text;
memory_management_struct.kernel_code_end = (ul)&_etext;
memory_management_struct.kernel_data_end = (ul)&_edata;
memory_management_struct.kernel_end = (ul)&_end;
// 物理地址空间的最大地址包含了物理内存、内存空洞、ROM等
ul max_addr = memory_management_struct.e820[memory_management_struct.len_e820].BaseAddr + memory_management_struct.e820[memory_management_struct.len_e820].Length;
// 初始化mms的bitmap
// bmp的指针指向截止位置的4k对齐的上边界防止修改了别的数据
memory_management_struct.bmp = (unsigned long *)((memory_management_struct.kernel_end + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
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);
// 初始化内存页结构
// 将页结构映射于bmp之后
memory_management_struct.pages_struct = (struct Page *)(((unsigned long)memory_management_struct.bmp + memory_management_struct.bmp_len + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
memory_management_struct.count_pages = max_addr >> PAGE_2M_SHIFT;
memory_management_struct.pages_struct_len = ((max_addr >> PAGE_2M_SHIFT) * sizeof(struct Page) + sizeof(long) - 1) & (~(sizeof(long) - 1));
// 将pages_struct全部清空以备后续初始化
memset(memory_management_struct.pages_struct, 0x00, memory_management_struct.pages_struct_len); //init pages memory
// 初始化内存区域
memory_management_struct.zones_struct = (struct Zone *)(((ul)memory_management_struct.pages_struct + memory_management_struct.pages_struct_len + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
// 由于暂时无法计算zone结构体的数量因此先将其设为0
memory_management_struct.count_zones = 0;
// zones-struct 成员变量暂时按照5个来计算
memory_management_struct.zones_struct_len = (5 * sizeof(struct Zone) + sizeof(ul) - 1) & (~(sizeof(ul) - 1));
memset(memory_management_struct.zones_struct, 0x00, memory_management_struct.zones_struct_len);
// ==== 遍历e820数组完成成员变量初始化工作 ===
for (int i = 0; i < memory_management_struct.len_e820; ++i)
{
if (memory_management_struct.e820[i].type != 1) // 不是操作系统可以使用的物理内存
continue;
ul addr_start = PAGE_2M_ALIGN(memory_management_struct.e820[i].BaseAddr);
ul addr_end = (memory_management_struct.e820[i].BaseAddr + memory_management_struct.e820[i].Length) & PAGE_2M_MASK;
if (addr_end <= addr_start)
continue;
// zone init
struct Zone *z = memory_management_struct.zones_struct + memory_management_struct.count_zones;
++memory_management_struct.count_zones;
z->zone_addr_start = addr_start;
z->zone_addr_end = addr_end;
z->zone_length = addr_end - addr_start;
z->count_pages_using = 0;
z->count_pages_free = (addr_end - addr_start) >> PAGE_2M_SHIFT;
z->total_pages_link = 0;
z->attr = 0;
z->gmd_struct = &memory_management_struct;
z->count_pages = (addr_end - addr_start) >> PAGE_2M_SHIFT;
z->pages_group = (struct Page *)(memory_management_struct.pages_struct + (addr_start >> PAGE_2M_SHIFT));
// 初始化页
struct Page *p = z->pages_group;
for (int j = 0; j < z->count_pages; ++j, ++p)
{
p->zone = z;
p->addr_phys = addr_start + PAGE_2M_SIZE * j;
p->attr = 0;
p->ref_counts = 0;
p->age = 0;
// 将bmp中对应的位 复位
*(memory_management_struct.bmp + ((p->addr_phys >> PAGE_2M_SHIFT) >> 6)) ^= (1UL << ((p->addr_phys >> PAGE_2M_SHIFT) % 64));
}
}
// 初始化0~2MB的物理页
// 由于这个区间的内存由多个内存段组成因此不会被以上代码初始化需要我们手动配置page[0]。
memory_management_struct.pages_struct->zone = memory_management_struct.zones_struct;
memory_management_struct.pages_struct->addr_phys = 0UL;
memory_management_struct.pages_struct->attr = 0;
memory_management_struct.pages_struct->ref_counts = 0;
memory_management_struct.pages_struct->age = 0;
// 计算zone结构体的总长度按照64位对齐
memory_management_struct.zones_struct_len = (memory_management_struct.count_zones * sizeof(struct Zone) + sizeof(ul) - 1) & (~(sizeof(ul) - 1));
printk_color(ORANGE, BLACK, "bmp:%#18lx, bmp_len:%#18lx, bits_size:%#18lx\n", memory_management_struct.bmp, memory_management_struct.bmp_len, memory_management_struct.bits_size);
printk_color(ORANGE, BLACK, "pages_struct:%#18lx, count_pages:%#18lx, pages_struct_len:%#18lx\n", memory_management_struct.pages_struct, memory_management_struct.count_pages, memory_management_struct.pages_struct_len);
printk_color(ORANGE, BLACK, "zones_struct:%#18lx, count_zones:%#18lx, zones_struct_len:%#18lx\n", memory_management_struct.zones_struct, memory_management_struct.count_zones, memory_management_struct.zones_struct_len);
ZONE_DMA_INDEX = 0; //need rewrite in the future
ZONE_NORMAL_INDEX = 0; //need rewrite in the future
for (int i = 0; i < memory_management_struct.count_zones; ++i) //need rewrite in the future
{
struct Zone *z = memory_management_struct.zones_struct + i;
printk_color(ORANGE, BLACK, "zone_addr_start:%#18lx, zone_addr_end:%#18lx, zone_length:%#18lx, pages_group:%#18lx, count_pages:%#18lx\n",
z->zone_addr_start, z->zone_addr_end, z->zone_length, z->pages_group, z->count_pages);
// 1GB以上的内存空间不做映射
if (z->zone_addr_start == 0x100000000)
ZONE_UNMAPED_INDEX = i;
}
// 设置内存页管理结构的地址,预留了一段空间,防止内存越界。
memory_management_struct.end_of_struct = (ul)((ul)memory_management_struct.zones_struct + memory_management_struct.zones_struct_len + sizeof(long) * 32) & (~(sizeof(long) - 1));
printk_color(ORANGE, BLACK, "code_start:%#18lx, code_end:%#18lx, data_end:%#18lx, kernel_end:%#18lx, end_of_struct:%#18lx\n",
memory_management_struct.kernel_code_start, memory_management_struct.kernel_code_end, memory_management_struct.kernel_data_end, memory_management_struct.kernel_end, memory_management_struct.end_of_struct);
// 初始化内存管理单元结构所占的物理页的结构体
ul mms_max_page = (virt_2_phys(memory_management_struct.end_of_struct) >> PAGE_2M_SHIFT); // 内存管理单元所占据的序号最大的物理页
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);
}
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));
// 消除一致性页表映射将页目录PML4E的前10项清空
for(int i=0;i<10;++i)
*(phys_2_virt(cr3)+i) = 0UL;
flush_tlb();
printk("[ INFO ] Memory management unit initialized.\n");
}
/**
* @brief
*
* @param page
* @param flags
* struct page
* /flags中含有引用属性或共享属性时struct page和struct zone的被引用计数bmp的相应位
* @return unsigned long
*/
unsigned long page_init(struct Page *page, ul flags)
{
// 全新的页面
if (!page->attr)
{
// 将bmp对应的标志位置位
*(memory_management_struct.bmp + ((page->addr_phys >> PAGE_2M_SHIFT) >> 6)) |= (1UL << ((page->addr_phys >> PAGE_2M_SHIFT) % 64));
page->attr = flags;
++(page->ref_counts);
++(page->zone->count_pages_using);
--(page->zone->count_pages_free);
++(page->zone->total_pages_link);
}
// 不是全新的页面,而是含有引用属性/共享属性
else if ((page->attr & PAGE_REFERENCED) || (page->attr & PAGE_K_SHARE_TO_U) || (flags & PAGE_REFERENCED) || (flags & PAGE_K_SHARE_TO_U))
{
page->attr |= flags;
++(page->ref_counts);
++(page->zone->total_pages_link);
}
else
{
// 将bmp对应的标志位置位
*(memory_management_struct.bmp + ((page->addr_phys >> PAGE_2M_SHIFT) >> 6)) |= (1UL << ((page->addr_phys >> PAGE_2M_SHIFT) % 64));
page->attr |= flags;
}
return 0;
}

View File

@ -1,21 +1,183 @@
#pragma once
#include"../common/glib.h"
#include "../common/glib.h"
// 每个页表的项数
// 64位下每个页表4k每条页表项8B故一个页表有512条
#define PTRS_PER_PGT 512
// 内核层的起始地址
#define KERNEL_BASE_ADDR 0xffff800000000000
#define PAGE_4K_SHIFT 12
#define PAGE_2M_SHIFT 21
#define PAGE_1G_SHIFT 30
// 不同大小的页的容量
#define PAGE_4K_SIZE (1UL << PAGE_4K_SHIFT)
#define PAGE_2M_SIZE (1UL << PAGE_2M_SHIFT)
#define PAGE_1G_SIZE (1UL << PAGE_1G_SHIFT)
// 屏蔽低于x的数值
#define PAGE_4K_MASK (~(PAGE_4K_SIZE - 1))
#define PAGE_2M_MASK (~(PAGE_2M_SIZE - 1))
// 将addr按照x的上边界对齐
#define PAGE_4K_ALIGN(addr) (((unsigned long)(addr) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
#define PAGE_2M_ALIGN(addr) (((unsigned long)(addr) + PAGE_2M_SIZE - 1) & PAGE_2M_MASK)
// 虚拟地址与物理地址转换
#define virt_2_phys(addr) ((unsigned long)(addr)-KERNEL_BASE_ADDR)
#define phys_2_virt(addr) ((unsigned long *)((unsigned long)(addr) + KERNEL_BASE_ADDR))
// ===== 页面属性 =====
// 页面在页表中已被映射
#define PAGE_PGT_MAPPED (1 << 0)
// 内核初始化程序的页
#define PAGE_KERNEL_INIT (1 << 1)
// 引用的页
#define PAGE_REFERENCED (1 << 2)
// 脏页
#define PAGE_DIRTY (1 << 3)
// 使用中的页
#define PAGE_ACTIVE (1 << 4)
// 过时的页
#define PAGE_UP_TO_DATE (1 << 5)
// 设备对应的页
#define PAGE_DEVICE (1 << 6)
// 内核层页
#define PAGE_KERNEL (1 << 7)
// 内核共享给用户态程序的页面
#define PAGE_K_SHARE_TO_U (1 << 8)
// slab内存分配器的页
#define PAGE_SLAB (1 << 9)
// Address Range Descriptor Structure 地址范围描述符
struct ARDS
{
unsigned int BaseAddrL; // 基地址低32位
unsigned int BaseAddrH; // 基地址高32位
unsigned int LengthL; // 内存长度低32位 以字节为单位
unsigned int LengthH; // 内存长度高32位
unsigned int type; // 本段内存的类型
// type=1 表示可以被操作系统使用
// type=2 ARR - 内存使用中或被保留,操作系统不能使用
// 其他 未定义操作系统需要将其视为ARR
ul BaseAddr; // 基地址
ul Length; // 内存长度 以字节为单位
unsigned int type; // 本段内存的类型
// type=1 表示可以被操作系统使用
// type=2 ARR - 内存使用中或被保留,操作系统不能使用
// 其他 未定义操作系统需要将其视为ARR
} __attribute__((packed)); // 修饰该结构体不会生成对齐空间,改用紧凑格式
struct memory_desc
{
struct ARDS e820[32]; // 物理内存段结构数组
ul len_e820; // 物理内存段长度
ul *bmp; // 物理空间页映射位图
ul bmp_len; // bmp的长度
ul bits_size; // 物理地址空间页数量
struct Page *pages_struct;
ul count_pages; // struct page结构体的总数
ul pages_struct_len; // pages_struct链表的长度
struct Zone *zones_struct;
ul count_zones; // zone结构体的数量
ul zones_struct_len; // zones_struct列表的长度
ul kernel_code_start, kernel_code_end; // 内核程序代码段起始地址、结束地址
ul kernel_data_end, kernel_end; // 内核程序数据段结束地址、 内核程序结束地址
ul end_of_struct; // 内存页管理结构的结束地址
};
struct Zone
{
// 指向内存页的指针
struct Page *pages_group;
ul count_pages; // 本区域的struct page结构体总数
// 本内存区域的起始、结束的页对齐地址
ul zone_addr_start;
ul zone_addr_end;
ul zone_length; // 区域长度
// 本区域空间的属性
ul attr;
void mm_init();
struct memory_desc *gmd_struct;
// 本区域正在使用中和空闲中的物理页面数量
ul count_pages_using;
ul count_pages_free;
// 物理页被引用次数
ul total_pages_link;
};
struct Page
{
// 本页所属的内存域结构体
struct Zone *zone;
// 本页对应的物理地址
ul addr_phys;
// 页面属性
ul attr;
// 页面被引用的次数
ul ref_counts;
// 本页的创建时间
ul age;
};
extern struct memory_desc memory_management_struct;
// 导出内核程序的几个段的起止地址
extern char _text;
extern char _etext;
extern char _edata;
extern char _end;
// 每个区域的索引
int ZONE_DMA_INDEX = 0;
int ZONE_NORMAL_INDEX = 0; //low 1GB RAM ,was mapped in pagetable
int ZONE_UNMAPED_INDEX = 0; //above 1GB RAM,unmapped in pagetable
// 初始化内存管理单元
void mm_init();
/**
* @brief
*
* @param page
* @param flags
* struct page
* /flags中含有引用属性或共享属性时struct page和struct zone的被引用计数bmp的相应位
* @return unsigned long
*/
unsigned long page_init(struct Page *page, ul flags);
/**
* @brief CR3寄存器的值
*
* @return unsigned* cr3的值的指针
*/
unsigned long *get_CR3()
{
ul *tmp;
__asm__ __volatile__(
"movq %%cr3, %0\n\t"
: "=r"(tmp)::"memory");
return tmp;
}
/**
* @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);

View File

@ -8,7 +8,7 @@ fi
# 第一个参数如果是--notbuild 那就不构建,直接运行
if [ ! "$1" == "--nobuild" ]; then
echo "开始构建..."
make all
make all -j 16
make clean
fi