#ifndef SDI2_PAGER_PAGEMAPPINGLIST_H
#define SDI2_PAGER_PAGEMAPPINGLIST_H
#include <assert.h>
#include "SlabAllocator.h"
struct PageMappingEntry
{
struct PageMappingEntry *prev, *next;
L4_Fpage_t userpage;
L4_Fpage_t backing;
};
class PageMappingList
{
private:
typedef SlabAllocator<PageMappingEntry> slaballoc_t;
slaballoc_t::Pool* slaballoc;
struct PageMappingEntry *head;
static inline L4_Word_t __L4_EndAddress(L4_Fpage_t f)
{
return f.raw | ((1UL << f.X.s) - 1);
}
static inline L4_Word_t __L4_NextAddress(L4_Fpage_t f)
{
return L4_Address(f) + L4_Size(f);
}
public:
explicit inline PageMappingList(slaballoc_t::Pool *usedallocator = NULL)
: slaballoc(usedallocator), head(NULL)
{
}
inline ~PageMappingList()
{
clear();
}
inline void setSlabAllocator(slaballoc_t::Pool &sa)
{
slaballoc = &sa;
}
inline void clear()
{
if (!head) return;
class PageMappingEntry* iter = head;
while(iter->next != iter)
{
class PageMappingEntry* iternext = iter->next;
slaballoc->freeobj(iter);
iter = iternext;
}
slaballoc->freeobj(iter);
head = NULL;
}
inline void test() const
{
if (!head) return;
class PageMappingEntry* iter = head;
assert(iter->prev == iter);
while(iter->next != iter)
{
assert(iter->next->prev == iter);
assert(L4_Address(iter->userpage) <= L4_Address(iter->next->userpage));
assert(L4_Address(iter->userpage) + L4_Size(iter->userpage) <= L4_Address(iter->next->userpage));
assert(L4_SizeLog2(iter->userpage) == L4_SizeLog2(iter->backing));
iter = iter->next;
}
}
inline const struct PageMappingEntry* begin() const
{ return head; }
inline struct PageMappingEntry* insert(L4_Fpage_t _userpage, L4_Fpage_t _backing)
{
test();
PageMappingEntry *newnode = slaballoc->allocate();
if (!newnode) {
assert(0);
return NULL;
}
newnode->userpage = _userpage;
newnode->backing = _backing;
if (!head)
{
newnode->next = newnode;
newnode->prev = newnode;
head = newnode;
return head;
}
else
{
PageMappingEntry *iter = head;
L4_Word_t findaddr = L4_Address(newnode->userpage);
while(findaddr >= L4_Address(iter->userpage))
{
if (iter->next == iter)
{
iter->next = newnode;
newnode->next = newnode;
newnode->prev = iter;
test();
return newnode;
}
iter = iter->next;
}
if (iter->prev == iter)
{
assert(head == iter);
newnode->prev = newnode;
newnode->next = iter;
iter->prev = newnode;
head = newnode;
}
else
{
iter->prev->next = newnode;
newnode->next = iter;
newnode->prev = iter->prev;
iter->prev = newnode;
}
test();
return newnode;
}
}
inline void remove(struct PageMappingEntry *e)
{
if (e->prev == e)
{
assert(head == e);
if (e->next == head) {
head = NULL;
}
else {
head = e->next;
head->prev = head;
}
}
else if (e->next == e)
{
e->prev->next = e->prev;
}
else
{
e->prev->next = e->next;
e->next->prev = e->prev;
}
slaballoc->freeobj(e);
}
inline struct PageMappingEntry *findAddress(L4_Word_t a)
{
if (!head) return NULL;
PageMappingEntry *iter = head;
while(a >= L4_Address(iter->next->userpage))
{
if (iter->next == iter)
break;
iter = iter->next;
}
assert(__L4_EndAddress(iter->userpage) ==
L4_Address(iter->userpage) + L4_Size(iter->userpage) - 1);
if (a < L4_Address(iter->userpage)
|| a > __L4_EndAddress(iter->userpage))
return NULL;
return iter;
}
inline L4_Word_t findSpace(const L4_Word_t firstaddr, L4_Word_t fpagesize) const
{
assert((firstaddr & (fpagesize-1)) == 0);
if (!head) return firstaddr;
const PageMappingEntry *iter = head;
while(firstaddr > L4_Address(iter->userpage))
{
if (iter->next == iter)
break;
iter = iter->next;
}
while(1)
{
L4_Word_t prevend = (iter->prev != iter) ? __L4_NextAddress(iter->prev->userpage) : firstaddr;
if (prevend < firstaddr) prevend = firstaddr;
L4_Word_t nextbegin = L4_Address(iter->userpage);
if ((prevend & (fpagesize-1)) != 0)
{
prevend |= (fpagesize-1);
prevend++;
}
assert((prevend & (fpagesize-1)) == 0);
nextbegin &= ~(fpagesize-1);
if (prevend <= nextbegin && prevend + fpagesize <= nextbegin)
return prevend;
if (iter->next == iter) break;
iter = iter->next;
}
{
L4_Word_t lastend = __L4_NextAddress(iter->userpage);
if (lastend < firstaddr) lastend = firstaddr;
if ((lastend & (fpagesize-1)) != 0)
{
lastend |= (fpagesize-1);
lastend++;
}
assert((lastend & (fpagesize-1)) == 0);
return lastend;
}
}
inline void dump() const
{
if (!head) {
printf("PageMappingList is empty\n");
return;
}
PageMappingEntry *iter = head;
printf("PageMappingList dump:\n");
while(1)
{
printPageMappingEntry(iter);
if (iter->next == iter) break;
iter = iter->next;
}
}
static inline void printPageMappingEntry(PageMappingEntry *pme)
{
if (!pme) {
printf("pme: (null)\n");
}
else {
printf("pme: addr 0x%08lx - 0x%08lx size %d => 0x%08x size %d\n",
L4_Address(pme->userpage),
__L4_EndAddress(pme->userpage),
static_cast<unsigned int>(L4_Size(pme->userpage)),
static_cast<unsigned int>(L4_Address(pme->backing)),
static_cast<unsigned int>(L4_Size(pme->backing)));
}
}
};
#endif