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