Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
		
							parent
							
								
									bd3dace0ab
								
							
						
					
					
						commit
						b58c6e5f49
					
				
							
								
								
									
										296
									
								
								kernel/pagetable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								kernel/pagetable.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,296 @@ | ||||||
|  | /*
 | ||||||
|  | Copyright (C) 2015-2019 The University of Notre Dame | ||||||
|  | This software is distributed under the GNU General Public License. | ||||||
|  | See the file LICENSE for details. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #include "pagetable.h" | ||||||
|  | #include "page.h" | ||||||
|  | #include "string.h" | ||||||
|  | #include "kernelcore.h" | ||||||
|  | 
 | ||||||
|  | #define ENTRIES_PER_TABLE (PAGE_SIZE/4) | ||||||
|  | 
 | ||||||
|  | struct pageentry { | ||||||
|  | 	unsigned present:1;	// 1 = present
 | ||||||
|  | 	unsigned readwrite:1;	// 1 = writable
 | ||||||
|  | 	unsigned user:1;	// 1 = user mode
 | ||||||
|  | 	unsigned writethrough:1;	// 1 = write through
 | ||||||
|  | 
 | ||||||
|  | 	unsigned nocache:1;	// 1 = no caching
 | ||||||
|  | 	unsigned accessed:1;	// 1 = accessed
 | ||||||
|  | 	unsigned dirty:1;	// 1 = dirty
 | ||||||
|  | 	unsigned pagesize:1;	// leave to zero
 | ||||||
|  | 
 | ||||||
|  | 	unsigned globalpage:1;	// 1 if not to be flushed
 | ||||||
|  | 	unsigned avail:3; | ||||||
|  | 
 | ||||||
|  | 	unsigned addr:20; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct pagetable { | ||||||
|  | 	struct pageentry entry[ENTRIES_PER_TABLE]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct pagetable *pagetable_create() | ||||||
|  | { | ||||||
|  | 	return page_alloc(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_init(struct pagetable *p) | ||||||
|  | { | ||||||
|  | 	unsigned i, stop; | ||||||
|  | 	stop = total_memory * 1024 * 1024; | ||||||
|  | 	for(i = 0; i < stop; i += PAGE_SIZE) { | ||||||
|  | 		pagetable_map(p, i, i, PAGE_FLAG_KERNEL | PAGE_FLAG_READWRITE); | ||||||
|  | 	} | ||||||
|  | 	stop = (unsigned) video_buffer + video_xres * video_yres * 3; | ||||||
|  | 	for(i = (unsigned) video_buffer; i <= stop; i += PAGE_SIZE) { | ||||||
|  | 		pagetable_map(p, i, i, PAGE_FLAG_KERNEL | PAGE_FLAG_READWRITE); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int pagetable_getmap(struct pagetable *p, unsigned vaddr, unsigned *paddr, int *flags) | ||||||
|  | { | ||||||
|  | 	struct pagetable *q; | ||||||
|  | 	struct pageentry *e; | ||||||
|  | 
 | ||||||
|  | 	unsigned a = vaddr >> 22; | ||||||
|  | 	unsigned b = (vaddr >> 12) & 0x3ff; | ||||||
|  | 
 | ||||||
|  | 	e = &p->entry[a]; | ||||||
|  | 	if(!e->present) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	q = (struct pagetable *) (e->addr << 12); | ||||||
|  | 
 | ||||||
|  | 	e = &q->entry[b]; | ||||||
|  | 	if(!e->present) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	*paddr = e->addr << 12; | ||||||
|  | 
 | ||||||
|  | 	if(flags) { | ||||||
|  | 		*flags = 0; | ||||||
|  | 		if(e->readwrite) | ||||||
|  | 			*flags |= PAGE_FLAG_READWRITE; | ||||||
|  | 		if(e->avail & 0x01) | ||||||
|  | 			*flags |= PAGE_FLAG_ALLOC; | ||||||
|  | 		if(!e->user) | ||||||
|  | 			*flags |= PAGE_FLAG_KERNEL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int pagetable_map(struct pagetable *p, unsigned vaddr, unsigned paddr, int flags) | ||||||
|  | { | ||||||
|  | 	struct pagetable *q; | ||||||
|  | 	struct pageentry *e; | ||||||
|  | 
 | ||||||
|  | 	unsigned a = vaddr >> 22; | ||||||
|  | 	unsigned b = (vaddr >> 12) & 0x3ff; | ||||||
|  | 
 | ||||||
|  | 	if(flags & PAGE_FLAG_ALLOC) { | ||||||
|  | 		paddr = (unsigned) page_alloc(flags & PAGE_FLAG_CLEAR); | ||||||
|  | 		if(!paddr) | ||||||
|  | 			return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	e = &p->entry[a]; | ||||||
|  | 
 | ||||||
|  | 	if(!e->present) { | ||||||
|  | 		q = pagetable_create(); | ||||||
|  | 		if(!q) | ||||||
|  | 			return 0; | ||||||
|  | 		e->present = 1; | ||||||
|  | 		e->readwrite = 1; | ||||||
|  | 		e->user = (flags & PAGE_FLAG_KERNEL) ? 0 : 1; | ||||||
|  | 		e->writethrough = 0; | ||||||
|  | 		e->nocache = 0; | ||||||
|  | 		e->accessed = 0; | ||||||
|  | 		e->dirty = 0; | ||||||
|  | 		e->pagesize = 0; | ||||||
|  | 		e->globalpage = (flags & PAGE_FLAG_KERNEL) ? 1 : 0; | ||||||
|  | 		e->avail = 0; | ||||||
|  | 		e->addr = (((unsigned) q) >> 12); | ||||||
|  | 	} else { | ||||||
|  | 		q = (struct pagetable *) (((unsigned) e->addr) << 12); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	e = &q->entry[b]; | ||||||
|  | 
 | ||||||
|  | 	e->present = 1; | ||||||
|  | 	e->readwrite = (flags & PAGE_FLAG_READWRITE) ? 1 : 0; | ||||||
|  | 	e->user = (flags & PAGE_FLAG_KERNEL) ? 0 : 1; | ||||||
|  | 	e->writethrough = 0; | ||||||
|  | 	e->nocache = 0; | ||||||
|  | 	e->accessed = 0; | ||||||
|  | 	e->dirty = 0; | ||||||
|  | 	e->pagesize = 0; | ||||||
|  | 	e->globalpage = !e->user; | ||||||
|  | 	e->avail = (flags & PAGE_FLAG_ALLOC) ? 1 : 0; | ||||||
|  | 	e->addr = (paddr >> 12); | ||||||
|  | 
 | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_unmap(struct pagetable *p, unsigned vaddr) | ||||||
|  | { | ||||||
|  | 	struct pagetable *q; | ||||||
|  | 	struct pageentry *e; | ||||||
|  | 
 | ||||||
|  | 	unsigned a = vaddr >> 22; | ||||||
|  | 	unsigned b = vaddr >> 12 & 0x3ff; | ||||||
|  | 
 | ||||||
|  | 	e = &p->entry[a]; | ||||||
|  | 	if(e->present) { | ||||||
|  | 		q = (struct pagetable *) (e->addr << 12); | ||||||
|  | 		e = &q->entry[b]; | ||||||
|  | 		e->present = 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_delete(struct pagetable *p) | ||||||
|  | { | ||||||
|  | 	unsigned i, j; | ||||||
|  | 
 | ||||||
|  | 	struct pageentry *e; | ||||||
|  | 	struct pagetable *q; | ||||||
|  | 
 | ||||||
|  | 	for(i = 0; i < ENTRIES_PER_TABLE; i++) { | ||||||
|  | 		e = &p->entry[i]; | ||||||
|  | 		if(e->present) { | ||||||
|  | 			q = (struct pagetable *) (e->addr << 12); | ||||||
|  | 			for(j = 0; j < ENTRIES_PER_TABLE; j++) { | ||||||
|  | 				e = &q->entry[j]; | ||||||
|  | 				if(e->present && e->avail) { | ||||||
|  | 					void *paddr; | ||||||
|  | 					paddr = (void *) (e->addr << 12); | ||||||
|  | 					page_free(paddr); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			page_free(q); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	page_free(p); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_alloc(struct pagetable *p, unsigned vaddr, unsigned length, int flags) | ||||||
|  | { | ||||||
|  | 	unsigned npages = length / PAGE_SIZE; | ||||||
|  | 
 | ||||||
|  | 	if(length % PAGE_SIZE) | ||||||
|  | 		npages++; | ||||||
|  | 
 | ||||||
|  | 	vaddr &= 0xfffff000; | ||||||
|  | 
 | ||||||
|  | 	while(npages > 0) { | ||||||
|  | 		unsigned paddr; | ||||||
|  | 		if(!pagetable_getmap(p, vaddr, &paddr, 0)) { | ||||||
|  | 			pagetable_map(p, vaddr, 0, flags | PAGE_FLAG_ALLOC); | ||||||
|  | 		} | ||||||
|  | 		vaddr += PAGE_SIZE; | ||||||
|  | 		npages--; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_free(struct pagetable *p, unsigned vaddr, unsigned length) | ||||||
|  | { | ||||||
|  | 	unsigned npages = length / PAGE_SIZE; | ||||||
|  | 
 | ||||||
|  | 	if(length % PAGE_SIZE) | ||||||
|  | 		npages++; | ||||||
|  | 
 | ||||||
|  | 	vaddr &= 0xfffff000; | ||||||
|  | 
 | ||||||
|  | 	while(npages > 0) { | ||||||
|  | 		unsigned paddr; | ||||||
|  | 		int flags; | ||||||
|  | 		if(pagetable_getmap(p, vaddr, &paddr, &flags)) { | ||||||
|  | 			pagetable_unmap(p, vaddr); | ||||||
|  | 			if(flags & PAGE_FLAG_ALLOC) | ||||||
|  | 				page_free((void *) paddr); | ||||||
|  | 		} | ||||||
|  | 		vaddr += PAGE_SIZE; | ||||||
|  | 		npages--; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct pagetable *pagetable_load(struct pagetable *p) | ||||||
|  | { | ||||||
|  | 	struct pagetable *oldp; | ||||||
|  |       asm("mov %%cr3, %0":"=r"(oldp)); | ||||||
|  | 	asm("mov %0, %%cr3"::"r"(p)); | ||||||
|  | 	return oldp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_refresh() | ||||||
|  | { | ||||||
|  | 	asm("mov %cr3, %eax"); | ||||||
|  | 	asm("mov %eax, %cr3"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_enable() | ||||||
|  | { | ||||||
|  | 	asm("movl %cr0, %eax"); | ||||||
|  | 	asm("orl $0x80000000, %eax"); | ||||||
|  | 	asm("movl %eax, %cr0"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct pagetable *pagetable_duplicate(struct pagetable *sp) | ||||||
|  | { | ||||||
|  | 	unsigned i, j; | ||||||
|  | 
 | ||||||
|  | 	struct pageentry *e; | ||||||
|  | 	struct pagetable *q; | ||||||
|  | 
 | ||||||
|  | 	struct pageentry *newe; | ||||||
|  | 	struct pagetable *newq; | ||||||
|  | 	struct pagetable *newp = pagetable_create(); | ||||||
|  | 	if(!newp) | ||||||
|  | 		goto cleanup; | ||||||
|  | 
 | ||||||
|  | 	for(i = 0; i < ENTRIES_PER_TABLE; i++) { | ||||||
|  | 		e = &sp->entry[i]; | ||||||
|  | 		newe = &newp->entry[i]; | ||||||
|  | 		if(e->present) { | ||||||
|  | 			q = (struct pagetable *) (e->addr << 12); | ||||||
|  | 			newq = pagetable_create(); | ||||||
|  | 			if(!newq) | ||||||
|  | 				goto cleanup; | ||||||
|  | 			memcpy(newe, e, sizeof(struct pageentry)); | ||||||
|  | 			newe->addr = (((unsigned) newq) >> 12); | ||||||
|  | 			for(j = 0; j < ENTRIES_PER_TABLE; j++) { | ||||||
|  | 				e = &q->entry[j]; | ||||||
|  | 				newe = &newq->entry[j]; | ||||||
|  | 				memcpy(newe, e, sizeof(struct pageentry)); | ||||||
|  | 				if(e->present) { | ||||||
|  | 					void *paddr; | ||||||
|  | 					paddr = (void *) (e->addr << 12); | ||||||
|  | 					void *new_paddr = 0; | ||||||
|  | 					if(e->avail) { | ||||||
|  | 						new_paddr = page_alloc(0); | ||||||
|  | 						if(!new_paddr) | ||||||
|  | 							goto cleanup; | ||||||
|  | 						memcpy(new_paddr, paddr, PAGE_SIZE); | ||||||
|  | 					} else { | ||||||
|  | 						new_paddr = paddr; | ||||||
|  | 					} | ||||||
|  | 					newe->addr = (((unsigned) new_paddr) >> 12); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return newp; | ||||||
|  |       cleanup: | ||||||
|  | 	printf("Pagetable duplicate errors\n"); | ||||||
|  | 	if(newp) { | ||||||
|  | 		pagetable_delete(newp); | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pagetable_copy(struct pagetable *sp, unsigned saddr, struct pagetable *tp, unsigned taddr, unsigned length); | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user