version 1.1.1.1, 2008/06/03 10:38:46 |
version 1.1.1.1.2.1, 2008/08/13 17:12:32 |
|
|
|
|
/* |
/* |
* page_alloc - allocate continuous pages of the specified size. |
* page_alloc - allocate continuous pages of the specified size. |
* @size: number of bytes to allocate |
|
* |
* |
* This routine returns the physical address of a new free page block, |
* This routine returns the physical address of a new free page |
* or returns NULL on failure. The requested size is automatically |
* block, or returns NULL on failure. The requested size is |
* round up to the page boundary. |
* automatically round up to the page boundary. The allocated |
* The allocated memory is _not_ filled with 0. |
* memory is _not_ filled with 0. |
*/ |
*/ |
void * |
void * |
page_alloc(size_t size) |
page_alloc(size_t size) |
|
|
blk = blk->next; |
blk = blk->next; |
if (blk == &page_head) { |
if (blk == &page_head) { |
sched_unlock(); |
sched_unlock(); |
printk("page_alloc: out of memory\n"); |
DPRINTF(("page_alloc: out of memory\n")); |
return NULL; /* Not found. */ |
return NULL; /* Not found. */ |
} |
} |
} while (blk->size < size); |
} while (blk->size < size); |
|
|
blk->prev->next = blk->next; |
blk->prev->next = blk->next; |
blk->next->prev = blk->prev; |
blk->next->prev = blk->prev; |
} else { |
} else { |
tmp = (struct page_block *)((u_long)blk + size); |
tmp = (struct page_block *)((char *)blk + size); |
tmp->size = blk->size - size; |
tmp->size = blk->size - size; |
tmp->prev = blk->prev; |
tmp->prev = blk->prev; |
tmp->next = blk->next; |
tmp->next = blk->next; |
|
|
} |
} |
used_bytes += size; |
used_bytes += size; |
sched_unlock(); |
sched_unlock(); |
|
|
return virt_to_phys(blk); |
return virt_to_phys(blk); |
} |
} |
|
|
/* |
/* |
* Free page block. |
* Free page block. |
* |
* |
* This allocator does not maintain the size of allocated page block. |
* This allocator does not maintain the size of allocated page |
* The caller must provide the size information of the block. |
* block. The caller must provide the size information of the |
|
* block. |
*/ |
*/ |
void |
void |
page_free(void *addr, size_t size) |
page_free(void *addr, size_t size) |
|
|
sched_lock(); |
sched_lock(); |
|
|
size = (size_t)PAGE_ALIGN(size); |
size = (size_t)PAGE_ALIGN(size); |
blk = phys_to_virt(addr); |
blk = (struct page_block *)phys_to_virt(addr); |
|
|
/* |
/* |
* Find the target position in list. |
* Find the target position in list. |
|
|
if (prev->next == &page_head) |
if (prev->next == &page_head) |
break; |
break; |
} |
} |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (prev != &page_head) |
if (prev != &page_head) |
ASSERT((u_long)prev + prev->size <= (u_long)blk); |
ASSERT((char *)prev + prev->size <= (char *)blk); |
if (prev->next != &page_head) |
if (prev->next != &page_head) |
ASSERT((u_long)blk + size <= (u_long)prev->next); |
ASSERT((char *)blk + size <= (char *)prev->next); |
#endif /* DEBUG */ |
#endif /* DEBUG */ |
|
|
/* |
/* |
|
|
* is made on block. |
* is made on block. |
*/ |
*/ |
if (blk->next != &page_head && |
if (blk->next != &page_head && |
((u_long)blk + blk->size) == (u_long)blk->next) { |
((char *)blk + blk->size) == (char *)blk->next) { |
blk->size += blk->next->size; |
blk->size += blk->next->size; |
blk->next = blk->next->next; |
blk->next = blk->next->next; |
blk->next->prev = blk; |
blk->next->prev = blk; |
} |
} |
if (blk->prev != &page_head && |
if (blk->prev != &page_head && |
(u_long)blk->prev + blk->prev->size == (u_long)blk) { |
(char *)blk->prev + blk->prev->size == (char *)blk) { |
blk->prev->size += blk->size; |
blk->prev->size += blk->size; |
blk->prev->next = blk->next; |
blk->prev->next = blk->next; |
blk->next->prev = blk->prev; |
blk->next->prev = blk->prev; |
|
|
page_reserve(void *addr, size_t size) |
page_reserve(void *addr, size_t size) |
{ |
{ |
struct page_block *blk, *tmp; |
struct page_block *blk, *tmp; |
u_long end; |
char *end; |
|
|
if (size == 0) |
if (size == 0) |
return 0; |
return 0; |
|
|
addr = phys_to_virt(addr); |
addr = phys_to_virt(addr); |
end = PAGE_ALIGN((u_long)addr + size); |
end = (char *)PAGE_ALIGN((char *)addr + size); |
addr = (void *)PAGE_TRUNC(addr); |
addr = (void *)PAGE_TRUNC(addr); |
size = (size_t)(end - (u_long)addr); |
size = (size_t)(end - (char *)addr); |
|
|
/* |
/* |
* Find the block which includes specified block. |
* Find the block which includes specified block. |
|
|
blk = page_head.next; |
blk = page_head.next; |
for (;;) { |
for (;;) { |
if (blk == &page_head) |
if (blk == &page_head) |
panic("page_reserve"); |
panic("failed to reserve pages"); |
if ((u_long)blk <= (u_long)addr |
if ((char *)blk <= (char *)addr |
&& end <= (u_long)blk + blk->size) |
&& end <= (char *)blk + blk->size) |
break; |
break; |
blk = blk->next; |
blk = blk->next; |
} |
} |
if ((u_long)blk == (u_long)addr && blk->size == size) { |
if ((char *)blk == (char *)addr && blk->size == size) { |
/* |
/* |
* Unlink the block from free list. |
* Unlink the block from free list. |
*/ |
*/ |
|
|
/* |
/* |
* Split this block. |
* Split this block. |
*/ |
*/ |
if ((u_long)blk + blk->size != end) { |
if ((char *)blk + blk->size != end) { |
tmp = (struct page_block *)end; |
tmp = (struct page_block *)end; |
tmp->size = (size_t)((u_long)blk + blk->size - end); |
tmp->size = (size_t)((char *)blk + blk->size - end); |
tmp->next = blk->next; |
tmp->next = blk->next; |
tmp->prev = blk; |
tmp->prev = blk; |
|
|
|
|
blk->next->prev = tmp; |
blk->next->prev = tmp; |
blk->next = tmp; |
blk->next = tmp; |
} |
} |
if ((u_long)blk == (u_long)addr) { |
if ((char *)blk == (char *)addr) { |
blk->prev->next = blk->next; |
blk->prev->next = blk->next; |
blk->next->prev = blk->prev; |
blk->next->prev = blk->prev; |
} else |
} else |
blk->size = (size_t)((u_long)addr - (u_long)blk); |
blk->size = (size_t)((char *)addr - (char *)blk); |
} |
} |
used_bytes += size; |
used_bytes += size; |
return 0; |
return 0; |
|
|
*free = total_bytes - used_bytes; |
*free = total_bytes - used_bytes; |
} |
} |
|
|
#if defined(DEBUG) && defined(CONFIG_KDUMP) |
|
void |
|
page_dump(void) |
|
{ |
|
struct page_block *blk; |
|
void *addr; |
|
struct mem_map *mem; |
|
struct module *img; |
|
int i; |
|
|
|
printk("Page dump:\n"); |
|
printk(" free pages:\n"); |
|
printk(" start end size\n"); |
|
printk(" -------- -------- --------\n"); |
|
|
|
blk = page_head.next; |
|
do { |
|
addr = virt_to_phys(blk); |
|
printk(" %08x - %08x %8x\n", addr, (u_long)addr + blk->size, |
|
blk->size); |
|
blk = blk->next; |
|
} while (blk != &page_head); |
|
printk(" used=%dK free=%dK total=%dK\n\n", |
|
used_bytes / 1024, (total_bytes - used_bytes) / 1024, |
|
total_bytes / 1024); |
|
|
|
img = (struct module *)&boot_info->kernel; |
|
printk(" kernel: %08x - %08x (%dK)\n", |
|
img->phys, img->phys + img->size, img->size / 1024); |
|
|
|
img = (struct module *)&boot_info->driver; |
|
printk(" driver: %08x - %08x (%dK)\n", |
|
img->phys, img->phys + img->size, img->size / 1024); |
|
|
|
for (i = 0; i < NRESMEM; i++) { |
|
mem = &boot_info->reserved[i]; |
|
if (mem->size != 0) { |
|
printk(" reserved: %08x - %08x (%dK)\n", |
|
mem->start, mem->start + mem->size, |
|
mem->size / 1024); |
|
} |
|
} |
|
#ifdef CONFIG_RAMDISK |
|
mem = (struct mem_map *)&boot_info->ram_disk; |
|
printk(" RAM disk: %08x - %08x (%dK)\n", |
|
mem->start, mem->start + mem->size, mem->size / 1024); |
|
#endif |
|
} |
|
#endif |
|
|
|
/* |
/* |
* Initialize page allocator. |
* Initialize page allocator. |
* page_init() must be called prior to other memory manager's |
* page_init() must be called prior to other memory manager's |
|
|
struct mem_map *mem; |
struct mem_map *mem; |
int i; |
int i; |
|
|
printk("Memory: base=%x size=%dK\n", boot_info->main_mem.start, |
DPRINTF(("Memory: base=%x size=%dK\n", boot_info->main_mem.start, |
boot_info->main_mem.size / 1024); |
boot_info->main_mem.size / 1024)); |
|
|
/* |
/* |
* First, create one block containing all memory pages. |
* First, create one block containing all memory pages. |