*/
#include "linux/mm.h"
-#include "linux/ghash.h"
+#include "linux/rbtree.h"
#include "linux/slab.h"
#include "linux/vmalloc.h"
#include "linux/bootmem.h"
#include "kern.h"
#include "init.h"
-#if 0
-static pgd_t physmem_pgd[PTRS_PER_PGD];
-
-static struct phys_desc *lookup_mapping(void *addr)
-{
- pgd = &physmem_pgd[pgd_index(addr)];
- if(pgd_none(pgd))
- return(NULL);
-
- pmd = pmd_offset(pgd, addr);
- if(pmd_none(pmd))
- return(NULL);
-
- pte = pte_offset_kernel(pmd, addr);
- return((struct phys_desc *) pte_val(pte));
-}
-
-static struct add_mapping(void *addr, struct phys_desc *new)
-{
-}
-#endif
-
-#define PHYS_HASHSIZE (8192)
-
-struct phys_desc;
-
-DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc);
-
struct phys_desc {
- struct virtmem_ptrs virt_ptrs;
+ struct rb_node rb;
int fd;
__u64 offset;
void *virt;
struct list_head list;
};
-struct virtmem_table virtmem_hash;
+static struct rb_root phys_mappings = RB_ROOT;
-static int virt_cmp(void *virt1, void *virt2)
+static struct rb_node **find_rb(void *virt)
{
- return(virt1 != virt2);
+ struct rb_node **n = &phys_mappings.rb_node;
+ struct phys_desc *d;
+
+ while(*n != NULL){
+ d = rb_entry(n, struct phys_desc, rb);
+ if(d->virt == virt)
+ return(n);
+
+ if(d->virt > virt)
+ n = &(*n)->rb_left;
+ else
+ n = &(*n)->rb_right;
+ }
+
+ return(n);
}
-static int virt_hash(void *virt)
+static struct phys_desc *find_phys_mapping(void *virt)
{
- unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT;
- return(addr % PHYS_HASHSIZE);
+ struct rb_node **n = find_rb(virt);
+
+ if(*n == NULL)
+ return(NULL);
+
+ return(rb_entry(n, struct phys_desc, rb));
}
-DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp,
- virt_hash);
+static void insert_phys_mapping(struct phys_desc *desc)
+{
+ struct rb_node **n = find_rb(desc->virt);
+
+ if(*n != NULL)
+ panic("Physical remapping for %p already present",
+ desc->virt);
+
+ rb_link_node(&desc->rb, (*n)->rb_parent, n);
+ rb_insert_color(&desc->rb, &phys_mappings);
+}
LIST_HEAD(descriptor_mappings);
return(-ENOMEM);
phys = __pa(virt);
- if(find_virtmem_hash(&virtmem_hash, virt) != NULL)
+ desc = find_phys_mapping(virt);
+ if(desc != NULL)
panic("Address 0x%p is already substituted\n", virt);
err = -ENOMEM;
goto out;
*desc = ((struct phys_desc)
- { .virt_ptrs = { NULL, NULL },
- .fd = fd,
+ { .fd = fd,
.offset = offset,
.virt = virt,
.phys = __pa(virt),
.list = LIST_HEAD_INIT(desc->list) });
- insert_virtmem_hash(&virtmem_hash, desc);
+ insert_phys_mapping(desc);
list_add(&desc->list, &fd_maps->pages);
if(!err)
goto out;
- remove_virtmem_hash(&virtmem_hash, desc);
+ rb_erase(&desc->rb, &phys_mappings);
kfree(desc);
out:
return(err);
void *virt = desc->virt;
int err;
- remove_virtmem_hash(&virtmem_hash, desc);
+ rb_erase(&desc->rb, &phys_mappings);
list_del(&desc->list);
kfree(desc);
struct phys_desc *desc;
virt = (void *) ((unsigned long) virt & PAGE_MASK);
- desc = find_virtmem_hash(&virtmem_hash, virt);
+ desc = find_phys_mapping(virt);
if(desc == NULL)
return(0);
int is_remapped(void *virt)
{
- return(find_virtmem_hash(&virtmem_hash, virt) != NULL);
+ struct phys_desc *desc = find_phys_mapping(virt);
+
+ return(desc != NULL);
}
/* Changed during early boot */
int phys_mapping(unsigned long phys, __u64 *offset_out)
{
- struct phys_desc *desc = find_virtmem_hash(&virtmem_hash,
- __va(phys & PAGE_MASK));
+ struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
int fd = -1;
if(desc != NULL){
+++ /dev/null
-/*
- * include/linux/ghash.h -- generic hashing with fuzzy retrieval
- *
- * (C) 1997 Thomas Schoebel-Theuer
- *
- * The algorithms implemented here seem to be a completely new invention,
- * and I'll publish the fundamentals in a paper.
- */
-
-#ifndef _GHASH_H
-#define _GHASH_H
-/* HASHSIZE _must_ be a power of two!!! */
-
-
-#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \
-\
-struct NAME##_table {\
- TYPE * hashtable[HASHSIZE];\
- TYPE * sorted_list;\
- int nr_entries;\
-};\
-\
-struct NAME##_ptrs {\
- TYPE * next_hash;\
- TYPE * prev_hash;\
- TYPE * next_sorted;\
- TYPE * prev_sorted;\
-};
-
-#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
-\
-LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
-{\
- int ix = HASHFN(elem->KEY);\
- TYPE ** base = &tbl->hashtable[ix];\
- TYPE * ptr = *base;\
- TYPE * prev = NULL;\
-\
- tbl->nr_entries++;\
- while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
- base = &ptr->PTRS.next_hash;\
- prev = ptr;\
- ptr = *base;\
- }\
- elem->PTRS.next_hash = ptr;\
- elem->PTRS.prev_hash = prev;\
- if(ptr) {\
- ptr->PTRS.prev_hash = elem;\
- }\
- *base = elem;\
-\
- ptr = prev;\
- if(!ptr) {\
- ptr = tbl->sorted_list;\
- prev = NULL;\
- } else {\
- prev = ptr->PTRS.prev_sorted;\
- }\
- while(ptr) {\
- TYPE * next = ptr->PTRS.next_hash;\
- if(next && KEYCMP(next->KEY, elem->KEY)) {\
- prev = ptr;\
- ptr = next;\
- } else if(KEYCMP(ptr->KEY, elem->KEY)) {\
- prev = ptr;\
- ptr = ptr->PTRS.next_sorted;\
- } else\
- break;\
- }\
- elem->PTRS.next_sorted = ptr;\
- elem->PTRS.prev_sorted = prev;\
- if(ptr) {\
- ptr->PTRS.prev_sorted = elem;\
- }\
- if(prev) {\
- prev->PTRS.next_sorted = elem;\
- } else {\
- tbl->sorted_list = elem;\
- }\
-}\
-\
-LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
-{\
- TYPE * next = elem->PTRS.next_hash;\
- TYPE * prev = elem->PTRS.prev_hash;\
-\
- tbl->nr_entries--;\
- if(next)\
- next->PTRS.prev_hash = prev;\
- if(prev)\
- prev->PTRS.next_hash = next;\
- else {\
- int ix = HASHFN(elem->KEY);\
- tbl->hashtable[ix] = next;\
- }\
-\
- next = elem->PTRS.next_sorted;\
- prev = elem->PTRS.prev_sorted;\
- if(next)\
- next->PTRS.prev_sorted = prev;\
- if(prev)\
- prev->PTRS.next_sorted = next;\
- else\
- tbl->sorted_list = next;\
-}\
-\
-LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
-{\
- int ix = hashfn(pos);\
- TYPE * ptr = tbl->hashtable[ix];\
- while(ptr && KEYCMP(ptr->KEY, pos))\
- ptr = ptr->PTRS.next_hash;\
- if(ptr && !KEYEQ(ptr->KEY, pos))\
- ptr = NULL;\
- return ptr;\
-}\
-\
-LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\
-{\
- int ix;\
- int offset;\
- TYPE * ptr;\
- TYPE * next;\
-\
- ptr = tbl->sorted_list;\
- if(!ptr || KEYCMP(pos, ptr->KEY))\
- return NULL;\
- ix = HASHFN(pos);\
- offset = HASHSIZE;\
- do {\
- offset >>= 1;\
- next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\
- if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\
- && KEYCMP(ptr->KEY, next->KEY))\
- ptr = next;\
- } while(offset);\
-\
- for(;;) {\
- next = ptr->PTRS.next_hash;\
- if(next) {\
- if(KEYCMP(next->KEY, pos)) {\
- ptr = next;\
- continue;\
- }\
- }\
- next = ptr->PTRS.next_sorted;\
- if(next && KEYCMP(next->KEY, pos)) {\
- ptr = next;\
- continue;\
- }\
- return ptr;\
- }\
- return NULL;\
-}
-
-/* LINKAGE - empty or "static", depending on whether you want the definitions to
- * be public or not
- * NAME - a string to stick in names to make this hash table type distinct from
- * any others
- * HASHSIZE - number of buckets
- * TYPE - type of data contained in the buckets - must be a structure, one
- * field is of type NAME_ptrs, another is the hash key
- * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that
- * field
- * KEYTYPE - type of the key field within TYPE
- * KEY - name of the key field within TYPE
- * KEYCMP - pointer to function that compares KEYTYPEs to each other - the
- * prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal,
- * non-zero for not equal
- * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE),
- * it returns a number in the range 0 ... HASHSIZE - 1
- * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call
- * DEF_HASH.
- */
-
-#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
-\
-struct NAME##_table {\
- TYPE * hashtable[HASHSIZE];\
- int nr_entries;\
-};\
-\
-struct NAME##_ptrs {\
- TYPE * next_hash;\
- TYPE * prev_hash;\
-};
-
-#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\
-\
-LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
-{\
- int ix = HASHFN(elem->KEY);\
- TYPE ** base = &tbl->hashtable[ix];\
- TYPE * ptr = *base;\
- TYPE * prev = NULL;\
-\
- tbl->nr_entries++;\
- while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
- base = &ptr->PTRS.next_hash;\
- prev = ptr;\
- ptr = *base;\
- }\
- elem->PTRS.next_hash = ptr;\
- elem->PTRS.prev_hash = prev;\
- if(ptr) {\
- ptr->PTRS.prev_hash = elem;\
- }\
- *base = elem;\
-}\
-\
-LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
-{\
- TYPE * next = elem->PTRS.next_hash;\
- TYPE * prev = elem->PTRS.prev_hash;\
-\
- tbl->nr_entries--;\
- if(next)\
- next->PTRS.prev_hash = prev;\
- if(prev)\
- prev->PTRS.next_hash = next;\
- else {\
- int ix = HASHFN(elem->KEY);\
- tbl->hashtable[ix] = next;\
- }\
-}\
-\
-LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
-{\
- int ix = HASHFN(pos);\
- TYPE * ptr = tbl->hashtable[ix];\
- while(ptr && KEYCMP(ptr->KEY, pos))\
- ptr = ptr->PTRS.next_hash;\
- return ptr;\
-}
-
-#endif