2009-02-08 Vesa Jääskeläinen <chaac@nic.fi>
* kern/mm.c: Add more comments.
This commit is contained in:
parent
e5698dc684
commit
2b40d6bb9f
2 changed files with 79 additions and 22 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
2009-02-08 Vesa Jääskeläinen <chaac@nic.fi>
|
||||||
|
|
||||||
|
* kern/mm.c: Add more comments.
|
||||||
|
|
||||||
2009-02-08 Robert Millan <rmh@aybabtu.com>
|
2009-02-08 Robert Millan <rmh@aybabtu.com>
|
||||||
|
|
||||||
Patch from Javier Martín.
|
Patch from Javier Martín.
|
||||||
|
|
97
kern/mm.c
97
kern/mm.c
|
@ -129,7 +129,7 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
|
||||||
|
|
||||||
if (! *r)
|
if (! *r)
|
||||||
grub_fatal ("out of range pointer %p", ptr);
|
grub_fatal ("out of range pointer %p", ptr);
|
||||||
|
|
||||||
*p = (grub_mm_header_t) ptr - 1;
|
*p = (grub_mm_header_t) ptr - 1;
|
||||||
if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
|
if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
|
||||||
grub_fatal ("alloc magic is broken at %p", *p);
|
grub_fatal ("alloc magic is broken at %p", *p);
|
||||||
|
@ -155,7 +155,7 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||||
r = (grub_mm_region_t) (((grub_addr_t) addr + GRUB_MM_ALIGN - 1)
|
r = (grub_mm_region_t) (((grub_addr_t) addr + GRUB_MM_ALIGN - 1)
|
||||||
& (~(GRUB_MM_ALIGN - 1)));
|
& (~(GRUB_MM_ALIGN - 1)));
|
||||||
size -= (char *) r - (char *) addr + sizeof (*r);
|
size -= (char *) r - (char *) addr + sizeof (*r);
|
||||||
|
|
||||||
h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN);
|
h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN);
|
||||||
h->next = h;
|
h->next = h;
|
||||||
h->magic = GRUB_MM_FREE_MAGIC;
|
h->magic = GRUB_MM_FREE_MAGIC;
|
||||||
|
@ -170,22 +170,26 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||||
for (p = &base, q = *p; q; p = &(q->next), q = *p)
|
for (p = &base, q = *p; q; p = &(q->next), q = *p)
|
||||||
if (q->size > r->size)
|
if (q->size > r->size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
*p = r;
|
*p = r;
|
||||||
r->next = q;
|
r->next = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate the number of units N with the alignment ALIGN from the ring
|
/* Allocate the number of units N with the alignment ALIGN from the ring
|
||||||
buffer starting from *FIRST. ALIGN must be a power of two. Return a
|
buffer starting from *FIRST. ALIGN must be a power of two. Both N and
|
||||||
non-NULL if successful, otherwise return NULL. */
|
ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful,
|
||||||
|
otherwise return NULL. */
|
||||||
static void *
|
static void *
|
||||||
grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||||
{
|
{
|
||||||
grub_mm_header_t p, q;
|
grub_mm_header_t p, q;
|
||||||
|
|
||||||
|
/* When everything is allocated side effect is that *first will have alloc
|
||||||
|
magic marked, meaning that there is no room in this region. */
|
||||||
if ((*first)->magic == GRUB_MM_ALLOC_MAGIC)
|
if ((*first)->magic == GRUB_MM_ALLOC_MAGIC)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Try to search free slot for allocation in this memory region. */
|
||||||
for (q = *first, p = q->next; ; q = p, p = p->next)
|
for (q = *first, p = q->next; ; q = p, p = p->next)
|
||||||
{
|
{
|
||||||
grub_off_t extra;
|
grub_off_t extra;
|
||||||
|
@ -204,11 +208,37 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||||
{
|
{
|
||||||
if (extra == 0 && p->size == n)
|
if (extra == 0 && p->size == n)
|
||||||
{
|
{
|
||||||
|
/* There is no special alignment requirement and memory block
|
||||||
|
is complete match.
|
||||||
|
|
||||||
|
1. Just mark memory block as allocated and remove it from
|
||||||
|
free list.
|
||||||
|
|
||||||
|
Result:
|
||||||
|
+---------------+ previous block's next
|
||||||
|
| alloc, size=n | |
|
||||||
|
+---------------+ v
|
||||||
|
*/
|
||||||
q->next = p->next;
|
q->next = p->next;
|
||||||
p->magic = GRUB_MM_ALLOC_MAGIC;
|
p->magic = GRUB_MM_ALLOC_MAGIC;
|
||||||
}
|
}
|
||||||
else if (extra == 0 || p->size == n + extra)
|
else if (extra == 0 || p->size == n + extra)
|
||||||
{
|
{
|
||||||
|
/* There might be alignment requirement, when taking it into
|
||||||
|
account memory block fits in.
|
||||||
|
|
||||||
|
1. Allocate new area at end of memory block.
|
||||||
|
2. Reduce size of available blocks from original node.
|
||||||
|
3. Mark new area as allocated and "remove" it from free
|
||||||
|
list.
|
||||||
|
|
||||||
|
Result:
|
||||||
|
+---------------+
|
||||||
|
| free, size-=n | next --+
|
||||||
|
+---------------+ |
|
||||||
|
| alloc, size=n | |
|
||||||
|
+---------------+ v
|
||||||
|
*/
|
||||||
p->size -= n;
|
p->size -= n;
|
||||||
p += p->size;
|
p += p->size;
|
||||||
p->size = n;
|
p->size = n;
|
||||||
|
@ -216,13 +246,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* There is alignment requirement and there is room in memory
|
||||||
|
block. Split memory block to three pieces.
|
||||||
|
|
||||||
|
1. Create new memory block right after section being
|
||||||
|
allocated. Mark it as free.
|
||||||
|
2. Add new memory block to free chain.
|
||||||
|
3. Mark current memory block having only extra blocks.
|
||||||
|
4. Advance to aligned block and mark that as allocated and
|
||||||
|
"remove" it from free list.
|
||||||
|
|
||||||
|
Result:
|
||||||
|
+------------------------------+
|
||||||
|
| free, size=extra | next --+
|
||||||
|
+------------------------------+ |
|
||||||
|
| alloc, size=n | |
|
||||||
|
+------------------------------+ |
|
||||||
|
| free, size=orig.size-extra-n | <------+, next --+
|
||||||
|
+------------------------------+ v
|
||||||
|
*/
|
||||||
grub_mm_header_t r;
|
grub_mm_header_t r;
|
||||||
|
|
||||||
r = p + extra + n;
|
r = p + extra + n;
|
||||||
r->magic = GRUB_MM_FREE_MAGIC;
|
r->magic = GRUB_MM_FREE_MAGIC;
|
||||||
r->size = p->size - extra - n;
|
r->size = p->size - extra - n;
|
||||||
r->next = p->next;
|
r->next = p->next;
|
||||||
|
|
||||||
p->size = extra;
|
p->size = extra;
|
||||||
p->next = r;
|
p->next = r;
|
||||||
p += extra;
|
p += extra;
|
||||||
|
@ -230,11 +279,15 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||||
p->magic = GRUB_MM_ALLOC_MAGIC;
|
p->magic = GRUB_MM_ALLOC_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark find as a start marker for next allocation to fasten it.
|
||||||
|
This will have side effect of fragmenting memory as small
|
||||||
|
pieces before this will be un-used. */
|
||||||
*first = q;
|
*first = q;
|
||||||
|
|
||||||
return p + 1;
|
return p + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search was completed without result. */
|
||||||
if (p == *first)
|
if (p == *first)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -249,17 +302,17 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
||||||
grub_mm_region_t r;
|
grub_mm_region_t r;
|
||||||
grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
|
grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
align = (align >> GRUB_MM_ALIGN_LOG2);
|
align = (align >> GRUB_MM_ALIGN_LOG2);
|
||||||
if (align == 0)
|
if (align == 0)
|
||||||
align = 1;
|
align = 1;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
|
|
||||||
for (r = base; r; r = r->next)
|
for (r = base; r; r = r->next)
|
||||||
{
|
{
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
p = grub_real_malloc (&(r->first), n, align);
|
p = grub_real_malloc (&(r->first), n, align);
|
||||||
if (p)
|
if (p)
|
||||||
return p;
|
return p;
|
||||||
|
@ -273,7 +326,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
||||||
grub_disk_cache_invalidate_all ();
|
grub_disk_cache_invalidate_all ();
|
||||||
count++;
|
count++;
|
||||||
goto again;
|
goto again;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
/* Unload unneeded modules. */
|
/* Unload unneeded modules. */
|
||||||
grub_dl_unload_unneeded ();
|
grub_dl_unload_unneeded ();
|
||||||
|
@ -283,7 +336,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -326,12 +379,12 @@ grub_free (void *ptr)
|
||||||
}
|
}
|
||||||
while (q != r->first);
|
while (q != r->first);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (q = r->first; q >= p || q->next <= p; q = q->next)
|
for (q = r->first; q >= p || q->next <= p; q = q->next)
|
||||||
{
|
{
|
||||||
if (q->magic != GRUB_MM_FREE_MAGIC)
|
if (q->magic != GRUB_MM_FREE_MAGIC)
|
||||||
grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic);
|
grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic);
|
||||||
|
|
||||||
if (q >= q->next && (q < p || q->next > p))
|
if (q >= q->next && (q < p || q->next > p))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +392,7 @@ grub_free (void *ptr)
|
||||||
p->magic = GRUB_MM_FREE_MAGIC;
|
p->magic = GRUB_MM_FREE_MAGIC;
|
||||||
p->next = q->next;
|
p->next = q->next;
|
||||||
q->next = p;
|
q->next = p;
|
||||||
|
|
||||||
if (p + p->size == p->next)
|
if (p + p->size == p->next)
|
||||||
{
|
{
|
||||||
if (p->next == q)
|
if (p->next == q)
|
||||||
|
@ -349,7 +402,7 @@ grub_free (void *ptr)
|
||||||
p->size += p->next->size;
|
p->size += p->next->size;
|
||||||
p->next = p->next->next;
|
p->next = p->next->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q + q->size == p)
|
if (q + q->size == p)
|
||||||
{
|
{
|
||||||
p->magic = 0;
|
p->magic = 0;
|
||||||
|
@ -370,7 +423,7 @@ grub_realloc (void *ptr, grub_size_t size)
|
||||||
grub_mm_region_t r;
|
grub_mm_region_t r;
|
||||||
void *q;
|
void *q;
|
||||||
grub_size_t n;
|
grub_size_t n;
|
||||||
|
|
||||||
if (! ptr)
|
if (! ptr)
|
||||||
return grub_malloc (size);
|
return grub_malloc (size);
|
||||||
|
|
||||||
|
@ -383,14 +436,14 @@ grub_realloc (void *ptr, grub_size_t size)
|
||||||
/* FIXME: Not optimal. */
|
/* FIXME: Not optimal. */
|
||||||
n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
|
n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
|
||||||
get_header_from_pointer (ptr, &p, &r);
|
get_header_from_pointer (ptr, &p, &r);
|
||||||
|
|
||||||
if (p->size >= n)
|
if (p->size >= n)
|
||||||
return ptr;
|
return ptr;
|
||||||
|
|
||||||
q = grub_malloc (size);
|
q = grub_malloc (size);
|
||||||
if (! q)
|
if (! q)
|
||||||
return q;
|
return q;
|
||||||
|
|
||||||
grub_memcpy (q, ptr, size);
|
grub_memcpy (q, ptr, size);
|
||||||
grub_free (ptr);
|
grub_free (ptr);
|
||||||
return q;
|
return q;
|
||||||
|
@ -434,7 +487,7 @@ grub_mm_dump (unsigned lineno)
|
||||||
for (r = base; r; r = r->next)
|
for (r = base; r; r = r->next)
|
||||||
{
|
{
|
||||||
grub_mm_header_t p;
|
grub_mm_header_t p;
|
||||||
|
|
||||||
for (p = (grub_mm_header_t) ((r->addr + GRUB_MM_ALIGN - 1)
|
for (p = (grub_mm_header_t) ((r->addr + GRUB_MM_ALIGN - 1)
|
||||||
& (~(GRUB_MM_ALIGN - 1)));
|
& (~(GRUB_MM_ALIGN - 1)));
|
||||||
(grub_addr_t) p < r->addr + r->size;
|
(grub_addr_t) p < r->addr + r->size;
|
||||||
|
@ -493,7 +546,7 @@ grub_debug_memalign (const char *file, int line, grub_size_t align,
|
||||||
grub_size_t size)
|
grub_size_t size)
|
||||||
{
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
|
|
||||||
if (grub_mm_debug)
|
if (grub_mm_debug)
|
||||||
grub_printf ("%s:%d: memalign (0x%x, 0x%x) = ",
|
grub_printf ("%s:%d: memalign (0x%x, 0x%x) = ",
|
||||||
file, line, align, size);
|
file, line, align, size);
|
||||||
|
|
Loading…
Reference in a new issue