LAB2-1物理页面管理

目录

        boot_alloc()

        page_init()

        page_alloc()

        page_free()       


        boot_alloc()

        这个简单的物理内存分配器只在 JOS 启动它的虚拟内存系统时使用,page_alloc()才是真正的物理页面分配器。

static void *
boot_alloc(uint32_t n)
{
	static char *nextfree;	// virtual address of next byte of free memory下一个空闲内存的虚拟地址
	char *result;
	//如果这是第一次,则初始化 nextfree。
	// 'end' 是链接器自动生成的符号,指向内核 bss 段的结尾:链接器*未*分配给任何内核代码或全局变量的第一个虚拟地址。
	if (!nextfree) {
		extern char end[];
		nextfree = ROUNDUP((char *) end, PGSIZE);// 向上舍入到最接近的 n 倍数分配了4K个字节的内存
	}
	// 分配一个足够大的块来容纳“n”个字节,然后更新下一个空闲。确保 nextfree 保持对齐为 PGSIZE 的倍数。
	result=nextfree;
	nextfree=ROUNDUP(nextfree+n,PGSIZE);
	if((uint32_t)(nextfree-KERNBASE)>npages*PGSIZE)//如果需要的内存超过了物理内存的总量
		panic("out of memory!\n");
	return result;
}

        page_init()

        初始化页面结构和内存空闲列表。完成此操作后,不能再次使用 boot_alloc。 只通过 page_free_list来进行物理内存的分配与取消。

        根据注释完成的代码:

        (1) 第零页的物理内存留给实模式的IDT以及BIOS系统。

        (2) 剩下的[PGSIZE, npages_basemem * PGSIZE)的基本内存空闲。

      (3)IO口[IOPHYSMEM, EXTPHYSMEM)的内存不能被分配。

      (4) 在extend memory中已经被使用的内存,如内核,该内存可以通过boot_alloc()得到。

size_t npages;			// Amount of physical memory (in pages)物理内存页面总数
static size_t npages_basemem;	// Amount of base memory (in pages)基本内存页面总数
struct PageInfo *pages;		// Physical page state array物理页状态数组,每个元素都是物理页面。
static struct PageInfo *page_free_list;	// Free list of physical pages物理页空闲表
void
page_init(void)
{
	pages[0].pp_ref=1;//IDT、BIOS
	pages[0].pp_link=NULL;

	size_t i;
	for (i = 1; i < npages_basemem; i++) {//BASEMEM
		pages[i].pp_ref = 0;//引用计数设为零
		pages[i].pp_link = page_free_list;//头插,指向下一个空闲链表
		page_free_list = &pages[i];
	}
	for (i ; i < EXTPHYSMEM/PGSIZE; i++) {
		pages[i].pp_ref = 1;
	}
	//扩展内存之外的,有哪些内存被使用了?boot_alloc()
	size_t epuse=(size_t)PADDR(boot_alloc(0))/PGSIZE;
	for(i ; i<epuse;i++){
		pages[i].pp_ref=1;//引用计数设为1,被kernel使用
		pages[i].pp_link=NULL;//不加入空闲链表
	}
	for(i;i<npages;i++){//EXTMEM中的空闲页面
		pages[i].pp_ref = 0;
		pages[i].pp_link = page_free_list;
		page_free_list = &pages[i];
	}

}

        page_alloc()

        分配一个物理页。 if (alloc_flags & ALLOC_ZERO),填充整个返回的物理页带 0字节,且不增加页面的引用计数。

struct PageInfo *
page_alloc(int alloc_flags)
{
	if(!page_free_list)//如果没有空闲页面
		return NULL;
	struct PageInfo* result;//分配的页面
	struct PageInfo* next=page_free_list->pp_link;//空闲页面链表的下一个节点
	page_free_list->pp_link=NULL;//将空闲页面的第一页分配,防止双重释放的错误。
	result=page_free_list;
	page_free_list=next;//更新链表头
	if(alloc_flags&ALLOC_ZERO){//是否将分配的内存填0
		memset(page2kva(result),0,PGSIZE);//因为C函数中的指针都是虚拟地址,因此将分配的页面转化为虚拟地址后再进行memset操作
	}
	// cprintf("xxx%x\n:",page2pa(result));
	return result;
}

        page_free()       

        当物理页面的引用计数达到0时,证明页面不再存在映射,因此将此物理页面释放到空闲页面的链表中。

void
page_free(struct PageInfo *pp)
{
    if(pp->pp_ref!=0||(pp->pp_link))//当pp->pp_link==NULL的时候才证明不属于空闲链表
		panic("page not free");
	pp->pp_link=page_free_list;//插入到空闲页面头
	page_free_list=pp;
	return;

}

        以上就是物理页面管理的全部实现。

上一篇:【求助-pytorch运行报错】CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling `cublasCreate(handle)`


下一篇:linux内存管理(十一)-页回收总览