minix/lib/libddekit/src/pgtab.c
2011-02-25 12:40:31 +00:00

313 lines
9 KiB
C

/*
* @author: Dirk Vogt
* @date 2010-02-10
*
* This file implements a local pagetable, to prevent IPC on physical
* address lookups. For now it's implement in a signle linked list.
*
* As soon as the DDE will use a premeptive thread mechanism access to
* the page table has to be sznchronized.
*/
#include "common.h"
#include <ddekit/pgtab.h>
#include <ddekit/memory.h>
#include <ddekit/lock.h>
#ifdef DDEBUG_LEVEL_PGTAB
#undef DDEBUG
#define DDEBUG DDEBUG_LEVEL_PGTAB
#endif
#include "util.h"
#include "debug.h"
FORWARD _PROTOTYPE( void lock_pgtab, (void));
FORWARD _PROTOTYPE( void unlock_pgtab, (void));
FORWARD _PROTOTYPE( struct dde_pgtab_region * allocate_region, (void));
FORWARD _PROTOTYPE( void free_region, (struct dde_pgtab_region *r));
FORWARD _PROTOTYPE( void add_region, (struct dde_pgtab_region *r));
FORWARD _PROTOTYPE( void rm_region, (struct dde_pgtab_region *r));
FORWARD _PROTOTYPE( struct dde_pgtab_region * find_region_virt, (ddekit_addr_t va));
FORWARD _PROTOTYPE( struct dde_pgtab_region * find_region_phys, (ddekit_addr_t pa));
struct dde_pgtab_region {
ddekit_addr_t vm_start;
ddekit_addr_t phy_start;
unsigned size;
unsigned type; /* do we really have to keep track of the type here? */
struct dde_pgtab_region *next;
struct dde_pgtab_region *prev;
};
PRIVATE struct dde_pgtab_region head = {0,0,0,0,&head,&head};
PRIVATE ddekit_lock_t lock;
/*
* INTERNAL HELPERS
*/
/****************************************************************************/
/* lock_pgtab */
/****************************************************************************/
PRIVATE void lock_pgtab()
{
ddekit_lock_lock(&lock);
}
/****************************************************************************/
/* unlock_pgtab */
/****************************************************************************/
PRIVATE void unlock_pgtab()
{
ddekit_lock_unlock(&lock);
}
/****************************************************************************/
/* dde_pgtab_region */
/****************************************************************************/
PRIVATE struct dde_pgtab_region * allocate_region()
{
struct dde_pgtab_region * res;
res = (struct dde_pgtab_region *)
ddekit_simple_malloc(sizeof(struct dde_pgtab_region));
if (!res)
{
DDEBUG_MSG_ERR("Could not allocate region");
}
return res;
}
/****************************************************************************/
/* free_region */
/****************************************************************************/
PRIVATE void free_region(struct dde_pgtab_region *r)
{
ddekit_simple_free(r);
}
/****************************************************************************/
/* add_region */
/****************************************************************************/
PRIVATE void add_region (struct dde_pgtab_region *r)
{
r->next = head.next;
head.next = r;
r->prev = &head;
if (r->next) {
r->next->prev = r;
}
}
/****************************************************************************/
/* rm_region */
/****************************************************************************/
PRIVATE void rm_region(struct dde_pgtab_region *r)
{
if (r->next) {
r->next->prev = r->prev;
}
if (r->prev) {
r->prev->next = r->next;
}
r->next = 0;
r->prev = 0;
}
/****************************************************************************/
/* find_region_virt */
/****************************************************************************/
PRIVATE struct dde_pgtab_region * find_region_virt(ddekit_addr_t va)
{
struct dde_pgtab_region * r;
for( r = head.next; r != &head ; r = r->next ) {
if ( (r->vm_start <= va) && (va < (r->vm_start + r->size) ) ) {
break;
}
}
if (r == &head) {
DDEBUG_MSG_VERBOSE("No virt->phys mapping found for %x", va);
r = 0;
}
return r;
}
/****************************************************************************/
/* find_region_phys */
/****************************************************************************/
PRIVATE struct dde_pgtab_region * find_region_phys(ddekit_addr_t pa)
{
struct dde_pgtab_region * r;
for( r = head.next; r != &head ; r = r->next ) {
if ( (r->phy_start <= pa) && (pa < (r->phy_start + r->size) ) )
break;
}
if (r == &head) {
r=0;
DDEBUG_MSG_VERBOSE("No phys->virt mapping found for %x", pa);
}
return r;
}
/****************************************************************************/
/* ddekit_pgtab_do_fo_each_region */
/****************************************************************************/
PUBLIC void ddekit_pgtab_do_fo_each_region(void (*func) (unsigned, unsigned)) {
struct dde_pgtab_region * r;
for( r = head.next; r != &head ; r = r->next ) {
ddekit_printf("%p",r->vm_start);
func(r->vm_start, r->size);
}
}
/*
* Interface implementation
*/
/****************************************************************************/
/* ddekit_pgtab_set_region */
/****************************************************************************/
PUBLIC void ddekit_pgtab_set_region(void *virt, ddekit_addr_t phys, int pages, int type)
{
ddekit_pgtab_set_region_with_size(virt, phys, (4096)*pages, type);
}
/****************************************************************************/
/* ddekit_pgtab_set_region_with_size */
/****************************************************************************/
PUBLIC void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type)
{
struct dde_pgtab_region * r;
lock_pgtab();
r = allocate_region();
r->vm_start = (ddekit_addr_t) virt;
r->phy_start = phys;
r->size = size;
r->type = type;
add_region(r);
unlock_pgtab();
}
/****************************************************************************/
/* ddekit_pgtab_clear_region */
/****************************************************************************/
PUBLIC void ddekit_pgtab_clear_region(void *virt, int type) {
struct dde_pgtab_region *r;
lock_pgtab();
r = find_region_virt((ddekit_addr_t)virt);
if (r)
{
rm_region(r);
free_region(r);
}
unlock_pgtab();
}
/****************************************************************************/
/* ddekit_pgtab_get_physaddr */
/****************************************************************************/
PUBLIC ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virt)
{
struct dde_pgtab_region *r;
ddekit_addr_t ret = 0;
lock_pgtab();
r = find_region_virt((ddekit_addr_t)virt);
unlock_pgtab();
if (r != NULL) {
ret = ((ddekit_addr_t) virt - r->vm_start) + r->phy_start;
DDEBUG_MSG_VERBOSE("pa: %p -> %p\n", virt, ret);
}
return ret;
}
/****************************************************************************/
/* ddekit_pgtab_get_virtaddr */
/****************************************************************************/
PUBLIC ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical)
{
struct dde_pgtab_region *r;
lock_pgtab();
r = find_region_phys((ddekit_addr_t)physical);
unlock_pgtab();
if (r != NULL)
{
return ((ddekit_addr_t) physical - r->phy_start) + r->vm_start;
}
return 0;
}
/****************************************************************************/
/* ddekit_pgtab_get_size */
/****************************************************************************/
PUBLIC int ddekit_pgtab_get_type(const void *virt)
{
/*
* needed for dde fbsd
*/
struct dde_pgtab_region *r;
lock_pgtab();
r = find_region_virt((ddekit_addr_t)virt);
unlock_pgtab();
return r->type;
}
/****************************************************************************/
/* ddekit_pgtab_get_size */
/****************************************************************************/
PUBLIC int ddekit_pgtab_get_size(const void *virt)
{
/*
* needed for fbsd
*/
struct dde_pgtab_region *r;
lock_pgtab();
r = find_region_virt((ddekit_addr_t)virt);
unlock_pgtab();
if(r)
return r->size;
else
return 0;
}
/****************************************************************************/
/* ddekit_pgtab_init */
/****************************************************************************/
PUBLIC void ddekit_pgtab_init() {
/* called by ddekit_init() */
ddekit_lock_init(&lock);
}