开机后的-内存管理

内存管理

内存管理有两个部分,
1)物理内存管理:主要是内核要有一个物理内存分配器,内核可以分配内存并且在后面不用了释放它。

2)虚拟内存管理:它负责内核和用户软件使用的虚拟地址映射到物理内存。X86硬件内存管理单元(MMU)通过咨询一系列页表来执行这个映射when指令使用内存时。
虚拟内存映射

物理内存管理

boot_alloc()
这个函数仅仅只使用在初始化期间,在page_free_list设置之前。

static void *
boot_alloc(uint32_t n)
{
	static char *nextfree;	// virtual address of next byte of free memory
	char *result;

	// Initialize nextfree if this is the first time.
	// 'end' is a magic symbol automatically generated by the linker,
	// which points to the end of the kernel's bss segment:
	// the first virtual address that the linker did *not* assign
	// to any kernel code or global variables.
	if (!nextfree) {
		extern char end[];
		nextfree = ROUNDUP((char *) end, PGSIZE);
	}

	// Allocate a chunk large enough to hold 'n' bytes, then update
	// nextfree.  Make sure nextfree is kept aligned
	// to a multiple of PGSIZE.
	//
	// LAB 2: Your code here.
	result=nextfree;
	nextfree=ROUNDUP((char*)result+n,PGSIZE);
	cprintf("boot_alloc memory at%x,next alloc at%x\n",result,nextfree);

	return result;
}

在下面这行代码运行之前我们使用的是pgdir是在计算机启动那篇文章最后那部分提到的entry_pgdir;那个是我们静态初始化了一个页目录,那个目录我们只映射了4MB内存;

kern_pgdir = (pde_t *) boot_alloc(PGSIZE);

分配4096个字节的内存,有1024条目录项,用来作为一个完整的内核页目录,这个页目录作为一个页表插入对于的页目录slot位置,

kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P;

用boot_alloc继续分配 64*8=512byte ,用来抽象物理页,进行管理。(因为我们物理内存大小这里模拟的是256MB,所以有64个页)

pages=(struct PageInfo*)boot_alloc(sizeof(struct PageInfo)*npages) ;

void
page_init(void)
我们使用page_init()初始化我们上面分配的pageInfo数组。
因为每个pageInfo对应一个物理页,在前一篇文章中我们页提到过 物理地址空间存在一个hole,所以
1)初始化的时候要将hole对应的PageInfo标注为已用,
2)最开始的一页我们已经在用了,也要标记为已用,

其他的页我们通过循环加入到空闲链表中
最后我们还会提供两个函数,`

struct PageInfo *
page_alloc(int alloc_flags)


void
page_free(struct PageInfo *pp)

void
page_decref(struct PageInfo* pp)

前两个函数用来从空闲链表中申请,释放PageInfo*;后面一个就是用来减少对应物理页的引用数。

这就是整个物理内存管理了

虚拟内存管理

虚拟内存管理就是对页表进行管理,硬件MMU通过页表实现了虚拟内存到物理内存的映射。
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
给一个页目录指针,返回一个指针指向页表entry的虚拟地址

pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
	// Fill this function in
	pde_t*pde_ptr=pgdir+PDX(va); //*pde_ptr一个页表的起始地址
	if(!(*pde_ptr&PTE_P)){
		if(create){
			struct PageInfo*pp=page_alloc(ALLOC_ZERO);
			if(pp==NULL){
				return NULL;
			}
			 pp->pp_ref++;
			*pde_ptr=(page2pa(pp))|PTE_P|PTE_U|PTE_W;

		}
		else{
			return NULL;
		}
	}
	return (pte_t*)KADDR(PTE_ADDR(*pde_ptr))+PTX(va);
}

1)先在页目录中找到对应的entry,取出页目录中的值,看二级页表是否存在,
2)如果存在,(注意,页目录和页表中存储的都是物理地址)
提出去出物理地址后,将其转换为虚拟地址,将虚拟地址转换成pte_t*类型,加上在页表上的偏移量,得到了va所在的pte_t的虚拟地址。
3)不存在,根据creat 标志确定释放为其创建二级页表

static void
boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm)
映射虚拟地址[va,va+size),到物理地址[pa,pa+size)

static void
boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm)
{
	// Fill this function in
	size_t pgs=size/PGSIZE;
	if(size%PGSIZE!=0){
		pgs++;
	}
	for(size_t i=0;i<pgs;i++){
		pte_t *pte=pgdir_walk(pgdir,(void*)va,1);
		if(pte==NULL){
			panic("boot_map_region():out of memory");
		}
		*pte=pa|PTE_P|perm;
		va+=PGSIZE;
		pa+=PGSIZE;
	}
}

简单来说就是把物理地址填充进入对应一级页目录和二级页表。
page_lookup()
page_remove()
page_insert()

根据pgdir和va返回对应物理页的PageInfo*;

struct PageInfo *
page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
{
	// Fill this function in
	pde_t *pte=pgdir_walk(pgdir,(void*)va,0);
	if(pte==NULL)
	{
		return NULL;
	}
	if(!(*pte)&PTE_P){
		return NULL;
	}
	if(pte_store){
		*pte_store=pte;
	}
	return pa2page(PTE_ADDR(*pte));
	
}

将一个物理页pp映射到va处,va处原来有直接移除

int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
	// Fill this function in
	pte_t *pte=pgdir_walk(pgdir,(void*)va,1);//如果va对应页表还没分配,则创建一个页表,并且将对应页目录项设置为页表地址|权限
	if(!pte){
		return -E_NO_MEM;
	}
	pp->pp_ref++;
	if((*pte)&PTE_P){
			page_remove(pgdir,va);
		}
	physaddr_t pa=page2pa(pp);
	*pte=pa|perm|PTE_P;
	pgdir[PDX(va)] |=perm;
	return 0;
}

移除va处的物理页,并且将页表条目设置为0;

void
page_remove(pde_t *pgdir, void *va)
{
	// Fill this function in

	pde_t*pte_store; 
	struct PageInfo*pp=page_lookup(pgdir,va,&pte_store);
	if(pp==NULL){
		return;
	}
	page_decref(pp);
	*pte_store=0;
	tlb_invalidate(pgdir,va);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值