Goto sanos source index
//
// pdir.c
//
// Page directory
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <os/krnl.h>
pte_t *pdir = (pte_t *) PAGEDIR_ADDRESS; // Page directory
pte_t *ptab = (pte_t *) PTBASE; // Page tables
void flushtlb()
{
__asm { mov eax, cr3 }
__asm { mov cr3, eax }
}
void invlpage(void *addr)
{
if (cpu.family < CPU_FAMILY_486)
{
__asm { mov eax, cr3 }
__asm { mov cr3, eax }
}
else
{
__asm { mov eax, addr }
__asm { invlpg [eax] }
}
}
void map_page(void *vaddr, unsigned long pfn, unsigned long flags)
{
// Allocate page table if not already done
if ((pdir[PDEIDX(vaddr)] & PT_PRESENT) == 0)
{
if (USERSPACE(vaddr))
pdir[PDEIDX(vaddr)] = PTOB(alloc_pageframe('PTAB')) | PT_PRESENT | PT_WRITABLE | PT_USER;
else
pdir[PDEIDX(vaddr)] = PTOB(alloc_pageframe('PTAB')) | PT_PRESENT | PT_WRITABLE;
memset(ptab + PDEIDX(vaddr) * PTES_PER_PAGE, 0, PAGESIZE);
}
// Map page frame into address space
ptab[PTABIDX(vaddr)] = PTOB(pfn) | flags;
}
void unmap_page(void *vaddr)
{
ptab[PTABIDX(vaddr)] = 0;
invlpage(vaddr);
}
unsigned long virt2phys(void *vaddr)
{
return ((ptab[PTABIDX(vaddr)] & PT_PFNMASK) + PGOFF(vaddr));
}
pte_t get_page_flags(void *vaddr)
{
return ptab[PTABIDX(vaddr)] & PT_FLAGMASK;
}
void set_page_flags(void *vaddr, unsigned long flags)
{
ptab[PTABIDX(vaddr)] = (ptab[PTABIDX(vaddr)] & PT_PFNMASK) | flags;
invlpage(vaddr);
}
int page_guarded(void *vaddr)
{
if ((pdir[PDEIDX(vaddr)] & PT_PRESENT) == 0) return 0;
if ((ptab[PTABIDX(vaddr)] & PT_GUARD) == 0) return 0;
return 1;
}
int page_mapped(void *vaddr)
{
if ((pdir[PDEIDX(vaddr)] & PT_PRESENT) == 0) return 0;
if ((ptab[PTABIDX(vaddr)] & PT_PRESENT) == 0) return 0;
return 1;
}
void unguard_page(void *vaddr)
{
ptab[PTABIDX(vaddr)] = (ptab[PTABIDX(vaddr)] & ~PT_GUARD) | PT_USER;
invlpage(vaddr);
}
int mem_mapped(void *vaddr, int size)
{
int len;
unsigned long addr;
unsigned long next;
addr = (unsigned long) vaddr;
next = (addr & ~PAGESIZE) + PAGESIZE;
while (1)
{
if ((pdir[PDEIDX(addr)] & PT_PRESENT) == 0) return 0;
if ((ptab[PTABIDX(addr)] & PT_PRESENT) == 0) return 0;
len = next - addr;
if (size > len)
{
size -= len;
addr = next;
next += PAGESIZE;
}
else
break;
}
return 1;
}
int str_mapped(char *s)
{
while (1)
{
if ((pdir[PDEIDX(s)] & PT_PRESENT) == 0) return 0;
if ((ptab[PTABIDX(s)] & PT_PRESENT) == 0) return 0;
while (1)
{
if (!*s) return 1;
s++;
if (PGOFF(s) == 0) break;
}
}
}
void init_pdir()
{
unsigned long i;
// Clear identity mapping of the first 4 MB made by the os loader
for (i = 0; i < PTES_PER_PAGE; i++) ptab[i] = 0;
}
int pdir_proc(struct proc_file *pf, void *arg)
{
char *vaddr;
pte_t pte;
int lines = 0;
int ma = 0;
int us = 0;
int su = 0;
int ro = 0;
int rw = 0;
int ac = 0;
int dt = 0;
pprintf(pf, "virtaddr physaddr flags\n");
pprintf(pf, "-------- -------- ----- \n");
vaddr = NULL;
while (1)
{
if ((pdir[PDEIDX(vaddr)] & PT_PRESENT) == 0)
vaddr += PTES_PER_PAGE * PAGESIZE;
else
{
pte = ptab[PTABIDX(vaddr)];
if (pte & PT_PRESENT)
{
ma++;
if (pte & PT_WRITABLE)
rw++;
else
ro++;
if (pte & PT_USER)
us++;
else
su++;
if (pte & PT_ACCESSED) ac++;
if (pte & PT_DIRTY) dt++;
pprintf(pf, "%08x %08x %c%c%c%c\n",
vaddr, PAGEADDR(pte),
(pte & PT_WRITABLE) ? 'w' : 'r',
(pte & PT_USER) ? 'u' : 's',
(pte & PT_ACCESSED) ? 'a' : ' ',
(pte & PT_DIRTY) ? 'd' : ' ');
}
vaddr += PAGESIZE;
}
if (!vaddr) break;
}
pprintf(pf, "\ntotal: %d user: %d sys: %d r/w: %d r/o: %d accessed: %d dirty: %d\n", ma, us, su, rw, ro, ac, dt);
return 0;
}
int pdir_stat(void *addr, int len, struct pdirstat *buf)
{
char *vaddr;
char *end;
pte_t pte;
memset(buf, 0, sizeof(struct pdirstat));
vaddr = (char *) addr;
end = vaddr + len;
while (vaddr < end)
{
if ((pdir[PDEIDX(vaddr)] & PT_PRESENT) == 0)
{
vaddr += PTES_PER_PAGE * PAGESIZE;
vaddr = (char *) ((unsigned long) vaddr & ~(PTES_PER_PAGE * PAGESIZE - 1));
}
else
{
pte = ptab[PTABIDX(vaddr)];
if (pte & PT_PRESENT)
{
buf->present++;
if (pte & PT_WRITABLE)
buf->readwrite++;
else
buf->readonly++;
if (pte & PT_USER)
buf->user++;
else
buf->kernel++;
if (pte & PT_ACCESSED) buf->accessed++;
if (pte & PT_DIRTY) buf->dirty++;
}
vaddr += PAGESIZE;
}
}
return 0;
}