76,18 → 76,43 |
frame_arch_init(); |
} |
|
/** |
* Find AND LOCK zone that can allocate order frames |
* |
* Assume zone_head_lock is locked. |
*/ |
static zone_t * find_free_zone(__u8 order) |
{ |
link_t *cur; |
zone_t *z; |
|
for (cur = zone_head.next; cur != &zone_head;cur = cur->next) { |
z = list_get_instance(cur, zone_t, link); |
|
spinlock_lock(&z->lock); |
|
/* Check if the zone has 2^order frames area available */ |
if (buddy_system_can_alloc(z->buddy_system, order)) |
return z; |
|
spinlock_unlock(&z->lock); |
} |
return NULL; |
} |
|
/** Allocate power-of-two frames of physical memory. |
* |
* @param flags Flags for host zone selection and address processing. |
* @param order Allocate exactly 2^order frames. |
* @param pzone Pointer to preferred zone pointer, on output it changes |
* to the zone that the frame was really allocated to |
* |
* @return Allocated frame. |
*/ |
__address frame_alloc(int flags, __u8 order, int * status) |
__address frame_alloc(int flags, __u8 order, int * status, zone_t **pzone) |
{ |
ipl_t ipl; |
link_t *cur, *tmp; |
zone_t *z; |
link_t *tmp; |
zone_t *zone = NULL; |
frame_t *frame = NULL; |
__address v; |
99,21 → 124,23 |
/* |
* First, find suitable frame zone. |
*/ |
for (cur = zone_head.next; cur != &zone_head; cur = cur->next) { |
z = list_get_instance(cur, zone_t, link); |
|
spinlock_lock(&z->lock); |
|
/* Check if the zone has 2^order frames area available */ |
if (buddy_system_can_alloc(z->buddy_system, order)) { |
zone = z; |
break; |
} |
|
spinlock_unlock(&z->lock); |
if (pzone && *pzone) { |
spinlock_lock(&(*pzone)->lock); |
if (!buddy_system_can_alloc((*pzone)->buddy_system, order)) |
spinlock_unlock(&(*pzone)->lock); |
else |
zone = *pzone; |
} |
|
if (!zone) { |
zone = find_free_zone(order); |
/* If no memory, reclaim some slab memory, |
if it does not help, reclaim all */ |
if (!zone && !(flags & FRAME_NO_RECLAIM)) |
if (slab_reclaim(0) || slab_reclaim(SLAB_RECLAIM_ALL)) |
zone = find_free_zone(order); |
} |
|
if (!zone) { |
if (flags & FRAME_PANIC) |
panic("Can't allocate frame.\n"); |
|
161,9 → 188,70 |
ASSERT(status != NULL); |
*status = FRAME_OK; |
} |
if (pzone) |
*pzone = zone; |
return v; |
} |
|
/** Convert address to zone pointer |
* |
* Assume zone_head_lock is held |
* |
* @param addr Physical address |
* @param lock If true, lock the zone |
*/ |
static zone_t * addr2zone(__address addr, int lock) |
{ |
link_t *cur; |
zone_t *z = NULL; |
|
for (cur = zone_head.next; cur != &zone_head; cur = cur->next) { |
z = list_get_instance(cur, zone_t, link); |
|
spinlock_lock(&z->lock); |
|
/* |
* Check if addr belongs to z. |
*/ |
if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) { |
if (!lock) |
spinlock_unlock(&z->lock); |
return z; |
} |
|
spinlock_unlock(&z->lock); |
} |
|
panic("Cannot find addr2zone: 0x%X", addr); |
} |
|
/** Return frame_t structure corresponding to address |
* |
* |
*/ |
frame_t * frame_addr2frame(__address addr) |
{ |
ipl_t ipl; |
frame_t *frame; |
zone_t *zone; |
|
if (IS_KA(addr)) |
addr = KA2PA(addr); |
|
/* Disable interrupts to avoid deadlocks with interrupt handlers */ |
ipl = interrupts_disable(); |
spinlock_lock(&zone_head_lock); |
|
zone = addr2zone(addr,0); |
frame = ADDR2FRAME(zone, addr); |
|
spinlock_unlock(&zone_head_lock); |
interrupts_restore(ipl); |
|
return frame; |
} |
|
|
/** Free a frame. |
* |
* Find respective frame structrue for supplied addr. |
175,14 → 263,15 |
void frame_free(__address addr) |
{ |
ipl_t ipl; |
link_t *cur; |
zone_t *z; |
zone_t *zone = NULL; |
zone_t *zone; |
frame_t *frame; |
int order; |
|
ASSERT(addr % FRAME_SIZE == 0); |
|
if (IS_KA(addr)) |
addr = KA2PA(addr); |
|
ipl = interrupts_disable(); |
spinlock_lock(&zone_head_lock); |
|
189,27 → 278,8 |
/* |
* First, find host frame zone for addr. |
*/ |
for (cur = zone_head.next; cur != &zone_head; cur = cur->next) { |
z = list_get_instance(cur, zone_t, link); |
|
spinlock_lock(&z->lock); |
|
if (IS_KA(addr)) |
addr = KA2PA(addr); |
|
/* |
* Check if addr belongs to z. |
*/ |
if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) { |
zone = z; |
break; |
} |
|
spinlock_unlock(&z->lock); |
} |
zone = addr2zone(addr, 1); /* This locks the zone automatically */ |
|
ASSERT(zone != NULL); |
|
frame = ADDR2FRAME(zone, addr); |
|
/* remember frame order */ |