⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmap.c~

📁 jos lab3代码
💻 C~
📖 第 1 页 / 共 2 页
字号:
/* See COPYRIGHT for copyright information. */#include <inc/x86.h>#include <inc/mmu.h>#include <inc/error.h>#include <inc/string.h>#include <inc/assert.h>#include <kern/pmap.h>#include <kern/kclock.h>#include <kern/env.h>// These variables are set by i386_detect_memory()static physaddr_t maxpa;	// Maximum physical addresssize_t npage;			// Amount of physical memory (in pages)static size_t basemem;		// Amount of base memory (in bytes)static size_t extmem;		// Amount of extended memory (in bytes)// These variables are set in i386_vm_init()pde_t* boot_pgdir;		// Virtual address of boot time page directoryphysaddr_t boot_cr3;		// Physical address of boot time page directorystatic char* boot_freemem;	// Pointer to next byte of free memstruct Page* pages;		// Virtual address of physical page arraystatic struct Page_list page_free_list;	// Free list of physical pages// Global descriptor table.//// The kernel and user segments are identical (except for the DPL).// To load the SS register, the CPL must equal the DPL.  Thus,// we must duplicate the segments for the user and the kernel.//struct Segdesc gdt[] ={	// 0x0 - unused (always faults -- for trapping NULL far pointers)	SEG_NULL,	// 0x8 - kernel code segment	[GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),	// 0x10 - kernel data segment	[GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),	// 0x18 - user code segment	[GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),	// 0x20 - user data segment	[GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),	// 0x28 - tss, initialized in idt_init()	[GD_TSS >> 3] = SEG_NULL};struct Pseudodesc gdt_pd = {	sizeof(gdt) - 1, (unsigned long) gdt};static intnvram_read(int r){	return mc146818_read(r) | (mc146818_read(r + 1) << 8);}voidi386_detect_memory(void){	// CMOS tells us how many kilobytes there are	basemem = ROUNDDOWN(nvram_read(NVRAM_BASELO)*1024, PGSIZE);	extmem = ROUNDDOWN(nvram_read(NVRAM_EXTLO)*1024, PGSIZE);	// Calculate the maximum physical address based on whether	// or not there is any extended memory.  See comment in <inc/mmu.h>.	if (extmem)		maxpa = EXTPHYSMEM + extmem;	else		maxpa = basemem;	npage = maxpa / PGSIZE;	cprintf("Physical memory: %dK available, ", (int)(maxpa/1024));	cprintf("base = %dK, extended = %dK\n", (int)(basemem/1024), (int)(extmem/1024));}// --------------------------------------------------------------// Set up initial memory mappings and turn on MMU.// --------------------------------------------------------------static void check_boot_pgdir(void);static void check_page_alloc();static void page_check(void);static void boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm);//// A simple physical memory allocator, used only a few times// in the process of setting up the virtual memory system.// page_alloc() is the real allocator.//// Allocate n bytes of physical memory aligned on an // align-byte boundary.  Align must be a power of two.// Return kernel virtual address.  Returned memory is uninitialized.//// If we're out of memory, boot_alloc should panic.// This function may ONLY be used during initialization,// before the page_free_list has been set up.// static void*boot_alloc(uint32_t n, uint32_t align){		extern char end[];	void *v;	// Initialize boot_freemem 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 -	// i.e., the first virtual address that the linker	// did _not_ assign to any kernel code or global variables.	if (boot_freemem == 0)		boot_freemem = end;		// LAB 2: Your code here:	//	Step 1: round boot_freemem up to be aligned properly	//	Step 2: save current value of boot_freemem as allocated chunk	char* temp_boot_freemem=ROUNDUP(boot_freemem,align);	//	Step 3: increase boot_freemem to record allocation	 boot_freemem=temp_boot_freemem+n;	//	Step 4: return allocated chunk	return (void *)temp_boot_freemem;}// Set up a two-level page table://    boot_pgdir is its linear (virtual) address of the root//    boot_cr3 is the physical adresss of the root// Then turn on paging.  Then effectively turn off segmentation.// (i.e., the segment base addrs are set to zero).// // This function only sets up the kernel part of the address space// (ie. addresses >= UTOP).  The user part of the address space// will be setup later.//// From UTOP to ULIM, the user is allowed to read but not write.// Above ULIM the user cannot read (or write). voidi386_vm_init(void){	pde_t* pgdir;	uint32_t cr0;	size_t n;	// Delete this line:	//panic("i386_vm_init: This function is not finished\n");	//////////////////////////////////////////////////////////////////////	// create initial page directory.	pgdir = boot_alloc(PGSIZE, PGSIZE);	memset(pgdir, 0, PGSIZE);	boot_pgdir = pgdir;	boot_cr3 = PADDR(pgdir);	//////////////////////////////////////////////////////////////////////	// Recursively insert PD in itself as a page table, to form	// a virtual page table at virtual address VPT.	// (For now, you don't have understand the greater purpose of the	// following two lines.)	// Permissions: kernel RW, user NONE	pgdir[PDX(VPT)] = PADDR(pgdir)|PTE_W|PTE_P;	// same for UVPT	// Permissions: kernel R, user R 	pgdir[PDX(UVPT)] = PADDR(pgdir)|PTE_U|PTE_P;	//////////////////////////////////////////////////////////////////////	// Make 'pages' point to an array of size 'npage' of 'struct Page'.	// The kernel uses this structure to keep track of physical pages;	// 'npage' equals the number of physical pages in memory.  User-level	// programs will get read-only access to the array as well.	// You must allocate the array yourself.	// Your code goes here: 	 pages = boot_alloc(npage * sizeof(struct Page), PGSIZE);			//////////////////////////////////////////////////////////////////////	// Make 'envs' point to an array of size 'NENV' of 'struct Env'.	// LAB 3: Your code here.	envs=boot_alloc(NENV*sizeof(struct Env),PGSIZE);	//////////////////////////////////////////////////////////////////////	// Now that we've allocated the initial kernel data structures, we set	// up the list of free physical pages. Once we've done so, all further	// memory management will go through the page_* functions. In	// particular, we can now map memory using boot_map_segment or page_insert	page_init();        check_page_alloc();		page_check();	//////////////////////////////////////////////////////////////////////	// Now we set up virtual memory 		//////////////////////////////////////////////////////////////////////	// Map 'pages' read-only by the user at linear address UPAGES	// (ie. perm = PTE_U | PTE_P)	// Permissions:	//    - pages -- kernel RW, user NONE	//    - the read-only version mapped at UPAGES -- kernel R, user R	// Your code goes here://<<<<<<< pmap.c 	boot_map_segment(pgdir, UPAGES, npage * sizeof(struct Page), PADDR(pages), PTE_U | PTE_P);//=======	//////////////////////////////////////////////////////////////////////	// Map the 'envs' array read-only by the user at linear address UENVS	// (ie. perm = PTE_U | PTE_P).	// Permissions:	//    - envs itself -- kernel RW, user NONE	//    - the image of envs mapped at UENVS  -- kernel R, user R//>>>>>>> 1.1.1.3	boot_map_segment(pgdir,UENVS,NENV*sizeof(struct Env),PADDR(envs),PTE_U|PTE_P);	//////////////////////////////////////////////////////////////////////	// Map the kernel stack (symbol name "bootstack").  The complete VA	// range of the stack, [KSTACKTOP-PTSIZE, KSTACKTOP), breaks into two	// pieces:	//     * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory	//     * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed => faults	//     Permissions: kernel RW, user NONE	// Your code goes here:	boot_map_segment(pgdir, KSTACKTOP - KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W|PTE_P);	//////////////////////////////////////////////////////////////////////	// Map all of physical memory at KERNBASE. 	// Ie.  the VA range [KERNBASE, 2^32) should map to	//      the PA range [0, 2^32 - KERNBASE)	// We might not have 2^32 - KERNBASE bytes of physical memory, but	// we just set up the amapping anyway.	// Permissions: kernel RW, user NONE	// Your code goes here: 	 boot_map_segment(pgdir, KERNBASE, (0xFFFFFFFF)-KERNBASE + 1, 0, PTE_W|PTE_P);	// Check that the initial page directory has been set up correctly.	check_boot_pgdir();	//////////////////////////////////////////////////////////////////////	// On x86, segmentation maps a VA to a LA (linear addr) and	// paging maps the LA to a PA.  I.e. VA => LA => PA.  If paging is	// turned off the LA is used as the PA.  Note: there is no way to	// turn off segmentation.  The closest thing is to set the base	// address to 0, so the VA => LA mapping is the identity.	// Current mapping: VA KERNBASE+x => PA x.	//     (segmentation base=-KERNBASE and paging is off)	// From here on down we must maintain this VA KERNBASE + x => PA x	// mapping, even though we are turning on paging and reconfiguring	// segmentation.	// Map VA 0:4MB same as VA KERNBASE, i.e. to PA 0:4MB.	// (Limits our kernel to <4MB)	pgdir[0] = pgdir[PDX(KERNBASE)];	// Install page table.	lcr3(boot_cr3);	// Turn on paging.	cr0 = rcr0();	cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_TS|CR0_EM|CR0_MP;	cr0 &= ~(CR0_TS|CR0_EM);	lcr0(cr0);	// Current mapping: KERNBASE+x => x => x.	// (x < 4MB so uses paging pgdir[0])	// Reload all segment registers.	asm volatile("lgdt gdt_pd");	asm volatile("movw %%ax,%%gs" :: "a" (GD_UD|3));	asm volatile("movw %%ax,%%fs" :: "a" (GD_UD|3));	asm volatile("movw %%ax,%%es" :: "a" (GD_KD));	asm volatile("movw %%ax,%%ds" :: "a" (GD_KD));	asm volatile("movw %%ax,%%ss" :: "a" (GD_KD));	asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KT));  // reload cs	asm volatile("lldt %%ax" :: "a" (0));	// Final mapping: KERNBASE+x => KERNBASE+x => x.	// This mapping was only used after paging was turned on but	// before the segment registers were reloaded.	pgdir[0] = 0;	// Flush the TLB for good measure, to kill the pgdir[0] mapping.	lcr3(boot_cr3);}//// Check the physical page allocator (page_alloc(), page_free(),// and page_init()).//static voidcheck_page_alloc(){	struct Page *pp, *pp0, *pp1, *pp2;	struct Page_list fl;			        // if there's a page that shouldn't be on        // the free list, try to make sure it        // eventually causes trouble.	LIST_FOREACH(pp0, &page_free_list, pp_link)		memset(page2kva(pp0), 0x97, 128);		// should be able to allocate three pages	pp0 = pp1 = pp2 = 0;	assert(page_alloc(&pp0) == 0);	assert(page_alloc(&pp1) == 0);	assert(page_alloc(&pp2) == 0);	assert(pp0);	assert(pp1 && pp1 != pp0);	assert(pp2 && pp2 != pp1 && pp2 != pp0);        assert(page2pa(pp0) < npage*PGSIZE);        assert(page2pa(pp1) < npage*PGSIZE);        assert(page2pa(pp2) < npage*PGSIZE);	// temporarily steal the rest of the free pages	fl = page_free_list;	LIST_INIT(&page_free_list);	// should be no free memory	assert(page_alloc(&pp) == -E_NO_MEM);        // free and re-allocate?        page_free(pp0);        page_free(pp1);        page_free(pp2);	pp0 = pp1 = pp2 = 0;	assert(page_alloc(&pp0) == 0);	assert(page_alloc(&pp1) == 0);	assert(page_alloc(&pp2) == 0);	assert(pp0);	assert(pp1 && pp1 != pp0);	assert(pp2 && pp2 != pp1 && pp2 != pp0);	assert(page_alloc(&pp) == -E_NO_MEM);		// give free list back	page_free_list = fl;	// free the pages we took	page_free(pp0);	page_free(pp1);	page_free(pp2);	cprintf("check_page_alloc() succeeded!\n");}//// Checks that the kernel part of virtual address space// has been setup roughly correctly(by i386_vm_init()).//// This function doesn't test every corner case,// in fact it doesn't test the permission bits at all,// but it is a pretty good sanity check. //static physaddr_t check_va2pa(pde_t *pgdir, uintptr_t va);static voidcheck_boot_pgdir(void){	uint32_t i, n;	pde_t *pgdir;	pgdir = boot_pgdir;	// check pages array	n = ROUNDUP(npage*sizeof(struct Page), PGSIZE);	for (i = 0; i < n; i += PGSIZE)		assert(check_va2pa(pgdir, UPAGES + i) == PADDR(pages) + i);		// check envs array (new test for lab 3)	n = ROUNDUP(NENV*sizeof(struct Env), PGSIZE);	for (i = 0; i < n; i += PGSIZE)		assert(check_va2pa(pgdir, UENVS + i) == PADDR(envs) + i);	// check phys mem	for (i = 0; i < npage; i += PGSIZE)		assert(check_va2pa(pgdir, KERNBASE + i) == i);	// check kernel stack	for (i = 0; i < KSTKSIZE; i += PGSIZE)		assert(check_va2pa(pgdir, KSTACKTOP - KSTKSIZE + i) == PADDR(bootstack) + i);	// check for zero/non-zero in PDEs	for (i = 0; i < NPDENTRIES; i++) {		switch (i) {		case PDX(VPT):		case PDX(UVPT):		case PDX(KSTACKTOP-1):		case PDX(UPAGES):		case PDX(UENVS):			assert(pgdir[i]);			break;		default:			if (i >= PDX(KERNBASE))				assert(pgdir[i]);			else				assert(pgdir[i] == 0);			break;		}	}	cprintf("check_boot_pgdir() succeeded!\n");}// This function returns the physical address of the page containing 'va',// defined by the page directory 'pgdir'.  The hardware normally performs// this functionality for us!  We define our own version to help check// the check_boot_pgdir() function; it shouldn't be used elsewhere.static physaddr_tcheck_va2pa(pde_t *pgdir, uintptr_t va){	pte_t *p;	pgdir = &pgdir[PDX(va)];	if (!(*pgdir & PTE_P))		return ~0;	p = (pte_t*) KADDR(PTE_ADDR(*pgdir));	if (!(p[PTX(va)] & PTE_P))		return ~0;	return PTE_ADDR(p[PTX(va)]);}		// --------------------------------------------------------------// Tracking of physical pages.// The 'pages' array has one 'struct Page' entry per physical page.// Pages are reference counted, and free pages are kept on a linked list.// --------------------------------------------------------------//  // Initialize page structure and memory free list.// After this point, ONLY use the functions below// to allocate and deallocate physical memory via the page_free_list,// and NEVER use boot_alloc()//voidpage_init(void){	// The example code here marks all pages as free.	// However this is not truly the case.  What memory is free?	//  1) Mark page 0 as in use.	//     This way we preserve the real-mode IDT and BIOS structures	//     in case we ever need them.  (Currently we don't, but...)	//  2) Mark the rest of base memory as free.	//  3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM).	//     Mark it as in use so that it can never be allocated.      	//  4) Then extended memory [EXTPHYSMEM, ...).

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -