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 map_page(void *vaddr, unsigned long pfn, unsigned long flags)
{
// Allocate page table if not already done
if ((GET_PDE(vaddr) & PT_PRESENT) == 0)
{
unsigned long pdfn;
pdfn = alloc_pageframe('PTAB');
if (USERSPACE(vaddr))
SET_PDE(vaddr, PTOB(pdfn) | PT_PRESENT | PT_WRITABLE | PT_USER);
else
SET_PDE(vaddr, PTOB(pdfn) | PT_PRESENT | PT_WRITABLE);
memset(ptab + PDEIDX(vaddr) * PTES_PER_PAGE, 0, PAGESIZE);
register_page_table(pdfn);
}
// Map page frame into address space
SET_PTE(vaddr, PTOB(pfn) | flags);
}
void unmap_page(void *vaddr)
{
SET_PTE(vaddr, 0);
invlpage(vaddr);
}
unsigned long virt2phys(void *vaddr)
{
return ((GET_PTE(vaddr) & PT_PFNMASK) + PGOFF(vaddr));
}
unsigned long virt2pfn(void *vaddr)
{
return BTOP(GET_PTE(vaddr) & PT_PFNMASK);
}
pte_t get_page_flags(void *vaddr)
{
return GET_PTE(vaddr) & PT_FLAGMASK;
}
void set_page_flags(void *vaddr, unsigned long flags)
{
SET_PTE(vaddr, (GET_PTE(vaddr) & PT_PFNMASK) | flags);
invlpage(vaddr);
}
int page_guarded(void *vaddr)
{
if ((GET_PDE(vaddr) & PT_PRESENT) == 0) return 0;
if ((GET_PTE(vaddr) & PT_GUARD) == 0) return 0;
return 1;
}
int page_mapped(void *vaddr)
{
if ((GET_PDE(vaddr) & PT_PRESENT) == 0) return 0;
if ((GET_PTE(vaddr) & PT_PRESENT) == 0) return 0;
return 1;
}
void unguard_page(void *vaddr)
{
SET_PTE(vaddr, (GET_PTE(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 ((GET_PDE(addr) & PT_PRESENT) == 0) return 0;
if ((GET_PTE(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 ((GET_PDE(s) & PT_PRESENT) == 0) return 0;
if ((GET_PTE(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++) SET_PTE(PTOB(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 ((GET_PDE(vaddr) & PT_PRESENT) == 0)
vaddr += PTES_PER_PAGE * PAGESIZE;
else
{
pte = GET_PTE(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;
}
static print_virtmem(struct proc_file *pf, char *start, char *end, unsigned long tag)
{
char tagname[5];
tag2str(tag, tagname);
pprintf(pf, "%08x %08x %8dK %-4s\n", start, end - 1, (end - start) / 1024, tagname);
}
int virtmem_proc(struct proc_file *pf, void *arg)
{
char *vaddr;
char *start;
unsigned long curtag;
int total = 0;
pprintf(pf, "start end size type\n");
pprintf(pf, "-------- -------- --------- ----\n");
start = vaddr = NULL;
curtag = 0;
while (1)
{
if ((GET_PDE(vaddr) & PT_PRESENT) == 0)
{
if (start != NULL)
{
print_virtmem(pf, start, vaddr, curtag);
start = NULL;
}
vaddr += PTES_PER_PAGE * PAGESIZE;
}
else
{
pte_t pte = GET_PTE(vaddr);
unsigned long tag = pfdb[pte >> PT_PFNSHIFT].tag;
if (pte & PT_PRESENT)
{
if (start == NULL)
{
start = vaddr;
curtag = tag;
}
else if (tag != curtag)
{
print_virtmem(pf, start, vaddr, curtag);
start = vaddr;
curtag = tag;
}
total += PAGESIZE;
}
else
{
if (start != NULL)
{
print_virtmem(pf, start, vaddr, curtag);
start = NULL;
}
}
vaddr += PAGESIZE;
}
if (!vaddr) break;
}
if (start) print_virtmem(pf, start, vaddr, curtag);
pprintf(pf, "total %8dK\n", total / 1024);
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 ((GET_PDE(vaddr) & PT_PRESENT) == 0)
{
vaddr += PTES_PER_PAGE * PAGESIZE;
vaddr = (char *) ((unsigned long) vaddr & ~(PTES_PER_PAGE * PAGESIZE - 1));
}
else
{
pte = GET_PTE(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;
}