313 lines
9 KiB
C
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);
|
|
}
|
|
|