xv6 内核内存
内核内存初始化过程
在main.c种 kinit()和 kvminit()是初始化物理内存和虚拟内存的主要代码
void
main()
{
consoleinit();
printfinit();
printf("\n");
printf("xv6 kernel is booting\n");
printf("\n");
kinit(); // 物理内存的初始化
kvminit(); // 创建页表,并分配一些
kvminithart(); // 保存页表地址,开始使用虚拟地址
//.....省略其他初始化过程
scheduler();
}
物理地址的范围 0x80000000开始 共128M
// 物理地址的范围 0x80000000开始 共128M
//提供给内核使用
#define KERNBASE 0x80000000L
#define PHYSTOP (KERNBASE + 128*1024*1024)
kinit:初始化物理内存
初始化物理内存,构成页的链表,每页4096字节,方便管理分配和回收
#define PGSIZE 4096
void
kinit()
{
initlock(&kmem.lock, "kmem");//加锁
freerange(end, (void*)PHYSTOP);
}
void
freerange(void *pa_start, void *pa_end)
{
char *p;
p = (char*)PGROUNDUP((uint64)pa_start);
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
kfree(p);
}
void
kfree(void *pa)
{
struct run *r;
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run*)pa;
acquire(&kmem.lock);
r->next = kmem.freelist;
kmem.freelist = r;
release(&kmem.lock);
}
kvminit:初始化页表
初始化页表;
初始化一些固定配置的虚拟地址和页表的映射;
pagetable_t
kvmmake(void)
{
pagetable_t kpgtbl;
//分配一个物理页,并返回物理页的地址,用来存放页表
kpgtbl = (pagetable_t) kalloc();
memset(kpgtbl, 0, PGSIZE);
//分配一个物理页 uart registers
kvmmap(kpgtbl, UART0, UART0, PGSIZE, PTE_R | PTE_W);
// virtio mmio disk interface
kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
// PLIC
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
// map kernel text executable and read-only.
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
// map kernel data and the physical RAM we'll make use of.
kvmmap(kpgtbl, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);
// map the trampoline for trap entry/exit to
// the highest virtual address in the kernel.
kvmmap(kpgtbl, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);
// allocate and map a kernel stack for each process.
proc_mapstacks(kpgtbl);
return kpgtbl;
}
因为一个页表项是代表一页的,所以需要通过虚拟地址的起始位置和size来判断需要几个页表项; 页表项的值就需要通过物理地址来构建,物理页号和权限(*pte = PA2PTE(pa) | perm | PTE_V);
void
kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm)
{
if(mappages(kpgtbl, va, sz, pa, perm) != 0)
panic("kvmmap");
}
// Create PTEs for virtual addresses starting at va that refer to
// physical addresses starting at pa. va and size might not
// be page-aligned. Returns 0 on success, -1 if walk() couldn't
// allocate a needed page-table page.
int
mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
{
uint64 a, last;
pte_t *pte;
if(size == 0)
panic("mappages: size");
a = PGROUNDDOWN(va);
last = PGROUNDDOWN(va + size - 1);
for(;;){
if((pte = walk(pagetable, a, 1)) == 0)
return -1;
if(*pte & PTE_V)
panic("mappages: remap");
*pte = PA2PTE(pa) | perm | PTE_V;
if(a == last)
break;
a += PGSIZE;
pa += PGSIZE;
}
return 0;
}