diff options
Diffstat (limited to 'libddekit/pgtab.c')
-rw-r--r-- | libddekit/pgtab.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c new file mode 100644 index 00000000..81138108 --- /dev/null +++ b/libddekit/pgtab.c @@ -0,0 +1,213 @@ +/* + * \brief Virtual page-table facility + * \author Thomas Friebel <tf13@os.inf.tu-dresden.de> + * \author Christian Helmuth <ch12@os.inf.tu-dresden.de> + * \date 2006-11-01 + * + * This implementation uses l4rm (especially the AVL tree and userptr) to + * manage virt->phys mappings. Each mapping region is represented by one + * pgtab_object that is kept in the l4rm region userptr. + * + * For this to work, dataspaces must be attached to l4rm regions! + */ + +#include <unistd.h> +#include <error.h> +#include <errno.h> +#include <mach.h> +#include <pthread.h> + +#include "ddekit/pgtab.h" +#include "util.h" +#include "config.h" + +/* A structure of recording a region of memory. */ +struct entry +{ + void *virtual; + ddekit_addr_t physical; + int size; + int type; +}; + +static struct entry *regions; +/* The number of memory regions in the array REGIONS */ +static int num_regions; +/* The size of the array REGIONS */ +static int capability; +static pthread_mutex_t lock; +#define INIT_SIZE 128 + +/***************************** + ** Page-table facility API ** + *****************************/ + +static struct entry *get_entry_from_phys (const ddekit_addr_t phys) +{ + int i; + + for (i = 0; i < num_regions; i++) + { + if (regions[i].physical <= phys + && regions[i].physical + regions[i].size > phys) + return ®ions[i]; + } + return NULL; +} + +static struct entry *get_entry_from_virt (const ddekit_addr_t virt) +{ + int i; + + for (i = 0; i < num_regions; i++) + { + if ((ddekit_addr_t) regions[i].virtual <= virt + && ((ddekit_addr_t) regions[i].virtual) + + regions[i].size > virt) + return ®ions[i]; + } + return NULL; +} + +/** + * Get physical address for virtual address + * + * \param virtual virtual address + * \return physical address or 0 + */ +ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual) +{ + struct entry *e; + pthread_mutex_lock (&lock); + e = get_entry_from_virt ((ddekit_addr_t) virtual); + if (e) + { + ddekit_addr_t phys = e->physical + (virtual - e->virtual); + pthread_mutex_unlock (&lock); + return phys; + } + pthread_mutex_unlock (&lock); + + ddekit_printf ("a virtual address %p doesn't exist.\n", virtual); + return -1; +} + +/** + * Get virtual address for physical address + * + * \param physical physical address + * \return virtual address or 0 + */ +ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical) +{ + struct entry *e; + + pthread_mutex_lock (&lock); + e = get_entry_from_phys (physical); + if (e) + { + ddekit_addr_t virt = (ddekit_addr_t) e->virtual + + (physical - e->physical); + pthread_mutex_unlock (&lock); + return virt; + } + pthread_mutex_unlock (&lock); + + + ddekit_printf ("a physical address %p doesn't exist.\n", physical); + return -1; +} + +// TODO +int ddekit_pgtab_get_type(const void *virtual) +{ +#if 0 + /* find pgtab object */ + struct pgtab_object *p = l4rm_get_userptr(virtual); + if (!p) { + /* XXX this is verbose */ + LOG_Error("no virt->phys mapping for %p", virtual); + return -1; + } + + return p->type; +#endif + UNIMPL; + return 0; +} + +int ddekit_pgtab_get_size(const void *virtual) +{ + struct entry *e; + pthread_mutex_lock (&lock); + e = get_entry_from_virt ((ddekit_addr_t) virtual); + if (e) + { + int size = e->size; + pthread_mutex_unlock (&lock); + return size; + } + pthread_mutex_unlock (&lock); + return 0; +} + + +/** + * Clear virtual->physical mapping for VM region + * + * \param virtual virtual start address for region + * \param type pgtab type for region + */ +void ddekit_pgtab_clear_region(void *virtual, int type) +{ + struct entry *e; + + pthread_mutex_lock (&lock); + e = get_entry_from_virt ((ddekit_addr_t) virtual); + if (e) + { + *e = regions[num_regions - 1]; + num_regions--; + } + pthread_mutex_unlock (&lock); +} + + +/** + * Set virtual->physical mapping for VM region + * + * \param virtual virtual start address for region + * \param physical physical start address for region + * \param pages number of pages in region + * \param type pgtab type for region + */ +void ddekit_pgtab_set_region(void *virtual, ddekit_addr_t physical, int pages, int type) +{ + ddekit_pgtab_set_region (virtual, physical, pages * getpagesize (), type); +} + +void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type) +{ + pthread_mutex_lock (&lock); + if (num_regions == capability) + { + capability *= 2; + regions = realloc (regions, capability * sizeof (struct entry)); + if (regions == NULL) + error (2, errno, "realloc"); + } + regions[num_regions].virtual = virt; + regions[num_regions].physical = phys; + regions[num_regions].size = size; + regions[num_regions].type = type; + num_regions++; + pthread_mutex_unlock (&lock); +} + +int pgtab_init () +{ + capability = INIT_SIZE; + regions = malloc (sizeof (struct entry) * capability); + pthread_mutex_init (&lock, NULL); + return 0; +} |