mirror of
https://git.proxmox.com/git/grub2
synced 2025-05-18 02:18:19 +00:00

* include/pupa/i386/pc/linux.h: New file. * loader/i386/pc/linux.c: Likewise. * loader/i386/pc/chainloader.c (pupa_chainloader_boot_sector): Removed. (pupa_chainloader_unload): Return PUPA_ERR_NONE. (pupa_rescue_cmd_chainloader): Read the image to 0x7C00 instead of PUPA_CHAINLOADER_BOOT_SECTOR. * kern/i386/pc/startup.S: Include pupa/machine/linux.h. (pupa_linux_prot_size): New variable. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): New function. (pupa_linux_boot_bzimage): Likewise. * kern/i386/pc/init.c (struct mem_region): New structure. (MAX_REGIONS): New macro. (mem_regions): New variable. (num_regions): Likewise. (pupa_os_area_addr): Likewise. (pupa_os_area_size): Likewise. (pupa_lower_mem): Likewise. (pupa_upper_mem): Likewise. (add_mem_region): New function. (compact_mem_regions): Likewise. (pupa_machine_init): Set PUPA_LOWER_MEM and PUPA_UPPER_MEM to the size of the conventional memory and that of so-called upper memory (before the first memory hole). Instead of adding each found region to free memory, use add_mem_region and add them after removing overlaps. Also, add only 1/4 of the upper memory to free memory. The rest is used for loading OS images. Maybe this is ad hoc, but this makes it much easier to relocate OS images when booting. * kern/rescue.c (pupa_rescue_cmd_module): Removed. (pupa_enter_rescue_mode): Don't register initrd and module. * kern/mm.c: Include pupa/dl.h. * kern/main.c: Include pupa/file.h and pupa/device.h. * kern/loader.c (pupa_loader_load_module_func): Removed. (pupa_loader_load_module): Likewise. * kern/dl.c (pupa_dl_load): Use the suffix ``.mod'' instead of ``.o''. * include/pupa/i386/pc/loader.h (pupa_linux_prot_size): Declared. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): Likewise. (pupa_linux_boot_bzimage): Likewise. * include/pupa/i386/pc/init.h (pupa_lower_mem): Declared. (pupa_upper_mem): Likewise. (pupa_gate_a20): Don't export, because turning off Gate A20 in a module is too dangerous. * include/pupa/loader.h (pupa_os_area_addr): Declared. (pupa_os_area_size): Likewise. (pupa_loader_set): Remove the first argument. Loader doesn't manage modules or initrd any longer. (pupa_loader_load_module): Removed. * conf/i386-pc.rmk (pkgdata_MODULES): Added linux.mod. (linux_mod_SOURCES): New variable. (linux_mod_CFLAGS): Likewise.
369 lines
8.0 KiB
C
369 lines
8.0 KiB
C
/* mm.c - functions for memory manager */
|
||
/*
|
||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||
*
|
||
* PUPA is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with PUPA; if not, write to the Free Software
|
||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
*/
|
||
|
||
#include <config.h>
|
||
#include <pupa/mm.h>
|
||
#include <pupa/misc.h>
|
||
#include <pupa/err.h>
|
||
#include <pupa/types.h>
|
||
#include <pupa/disk.h>
|
||
#include <pupa/dl.h>
|
||
|
||
/* Magic words. */
|
||
#define PUPA_MM_FREE_MAGIC 0x2d3c2808
|
||
#define PUPA_MM_ALLOC_MAGIC 0x6db08fa4
|
||
|
||
typedef struct pupa_mm_header
|
||
{
|
||
struct pupa_mm_header *next;
|
||
pupa_size_t size;
|
||
pupa_size_t magic;
|
||
#if PUPA_CPU_SIZEOF_VOID_P == 4
|
||
char padding[4];
|
||
#elif PUPA_CPU_SIZEOF_VOID_P == 8
|
||
char padding[8];
|
||
#else
|
||
# error "unknown word size"
|
||
#endif
|
||
}
|
||
*pupa_mm_header_t;
|
||
|
||
#if PUPA_CPU_SIZEOF_VOID_P == 4
|
||
# define PUPA_MM_ALIGN_LOG2 4
|
||
#elif PUPA_CPU_SIZEOF_VOID_P == 8
|
||
# define PUPA_MM_ALIGN_LOG2 8
|
||
#endif
|
||
|
||
#define PUPA_MM_ALIGN (1 << PUPA_MM_ALIGN_LOG2)
|
||
|
||
typedef struct pupa_mm_region
|
||
{
|
||
struct pupa_mm_header *first;
|
||
struct pupa_mm_region *next;
|
||
pupa_addr_t addr;
|
||
pupa_size_t size;
|
||
}
|
||
*pupa_mm_region_t;
|
||
|
||
|
||
|
||
static pupa_mm_region_t base;
|
||
|
||
/* Get a header from the pointer PTR, and set *P and *R to a pointer
|
||
to the header and a pointer to its region, respectively. PTR must
|
||
be allocated. */
|
||
static void
|
||
get_header_from_pointer (void *ptr, pupa_mm_header_t *p, pupa_mm_region_t *r)
|
||
{
|
||
if ((unsigned) ptr & (PUPA_MM_ALIGN - 1))
|
||
pupa_fatal ("unaligned pointer %p", ptr);
|
||
|
||
for (*r = base; *r; *r = (*r)->next)
|
||
if ((unsigned) ptr > (*r)->addr
|
||
&& (unsigned) ptr <= (*r)->addr + (*r)->size)
|
||
break;
|
||
|
||
if (! *r)
|
||
pupa_fatal ("out of range pointer %p", ptr);
|
||
|
||
*p = (pupa_mm_header_t) ptr - 1;
|
||
if ((*p)->magic != PUPA_MM_ALLOC_MAGIC)
|
||
pupa_fatal ("alloc magic is broken at %p", *p);
|
||
}
|
||
|
||
/* Initialize a region starting from ADDR and whose size is SIZE,
|
||
to use it as free space. */
|
||
void
|
||
pupa_mm_init_region (void *addr, pupa_size_t size)
|
||
{
|
||
pupa_mm_header_t h;
|
||
pupa_mm_region_t r, *p, q;
|
||
|
||
#if 0
|
||
pupa_printf ("%s:%d: addr=%p, size=%u\n", __FILE__, __LINE__, addr, size);
|
||
#endif
|
||
|
||
/* If this region is too small, ignore it. */
|
||
if (size < PUPA_MM_ALIGN * 2)
|
||
return;
|
||
|
||
/* Allocate a region from the head. */
|
||
r = (pupa_mm_region_t) (((pupa_addr_t) addr + PUPA_MM_ALIGN - 1)
|
||
& (~(PUPA_MM_ALIGN - 1)));
|
||
size -= (char *) r - (char *) addr + sizeof (*r);
|
||
|
||
h = (pupa_mm_header_t) ((char *) r + PUPA_MM_ALIGN);
|
||
h->next = h;
|
||
h->magic = PUPA_MM_FREE_MAGIC;
|
||
h->size = (size >> PUPA_MM_ALIGN_LOG2);
|
||
|
||
r->first = h;
|
||
r->addr = (pupa_addr_t) h;
|
||
r->size = (h->size << PUPA_MM_ALIGN_LOG2);
|
||
|
||
/* Find where to insert this region. Put a smaller one before bigger ones,
|
||
to prevent fragmentations. */
|
||
for (p = &base, q = *p; q; p = &(q->next), q = *p)
|
||
if (q->size > r->size)
|
||
break;
|
||
|
||
*p = r;
|
||
r->next = q;
|
||
}
|
||
|
||
/* 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
|
||
non-NULL if successful, otherwise return NULL. */
|
||
static void *
|
||
pupa_real_malloc (pupa_mm_header_t *first, pupa_size_t n, pupa_size_t align)
|
||
{
|
||
pupa_mm_header_t p, q;
|
||
|
||
if ((*first)->magic == PUPA_MM_ALLOC_MAGIC)
|
||
return 0;
|
||
|
||
for (q = *first, p = q->next; ; q = p, p = p->next)
|
||
{
|
||
pupa_off_t extra;
|
||
|
||
extra = ((pupa_addr_t) (p + 1) >> PUPA_MM_ALIGN_LOG2) % align;
|
||
if (extra)
|
||
extra = align - extra;
|
||
|
||
if (! p)
|
||
pupa_fatal ("null in the ring");
|
||
|
||
if (p->magic != PUPA_MM_FREE_MAGIC)
|
||
pupa_fatal ("free magic is broken at %p", p);
|
||
|
||
if (p->size >= n + extra)
|
||
{
|
||
if (extra == 0 && p->size == n)
|
||
{
|
||
q->next = p->next;
|
||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||
}
|
||
else if (extra == 0 || p->size == n + extra)
|
||
{
|
||
p->size -= n;
|
||
p += p->size;
|
||
p->size = n;
|
||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||
}
|
||
else
|
||
{
|
||
pupa_mm_header_t r;
|
||
|
||
r = p + extra + n;
|
||
r->magic = PUPA_MM_FREE_MAGIC;
|
||
r->size = p->size - extra - n;
|
||
r->next = p->next;
|
||
|
||
p->size = extra;
|
||
p->next = r;
|
||
p += extra;
|
||
p->size = n;
|
||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||
}
|
||
|
||
*first = q;
|
||
return p + 1;
|
||
}
|
||
|
||
if (p == *first)
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Allocate SIZE bytes with the alignment ALIGN and return the pointer. */
|
||
void *
|
||
pupa_memalign (pupa_size_t align, pupa_size_t size)
|
||
{
|
||
pupa_mm_region_t r;
|
||
pupa_size_t n = ((size + PUPA_MM_ALIGN - 1) >> PUPA_MM_ALIGN_LOG2) + 1;
|
||
int count = 0;
|
||
|
||
align = (align >> PUPA_MM_ALIGN_LOG2);
|
||
if (align == 0)
|
||
align = 1;
|
||
|
||
again:
|
||
|
||
for (r = base; r; r = r->next)
|
||
{
|
||
void *p;
|
||
|
||
p = pupa_real_malloc (&(r->first), n, align);
|
||
if (p)
|
||
return p;
|
||
}
|
||
|
||
/* If failed, increase free memory somehow. */
|
||
switch (count)
|
||
{
|
||
case 0:
|
||
/* Invalidate disk caches. */
|
||
pupa_disk_cache_invalidate_all ();
|
||
count++;
|
||
goto again;
|
||
|
||
case 1:
|
||
/* Unload unneeded modules. */
|
||
pupa_dl_unload_unneeded ();
|
||
count++;
|
||
goto again;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
pupa_error (PUPA_ERR_OUT_OF_MEMORY, "out of memory");
|
||
return 0;
|
||
}
|
||
|
||
/* Allocate SIZE bytes and return the pointer. */
|
||
void *
|
||
pupa_malloc (pupa_size_t size)
|
||
{
|
||
return pupa_memalign (0, size);
|
||
}
|
||
|
||
/* Deallocate the pointer PTR. */
|
||
void
|
||
pupa_free (void *ptr)
|
||
{
|
||
pupa_mm_header_t p;
|
||
pupa_mm_region_t r;
|
||
|
||
if (! ptr)
|
||
return;
|
||
|
||
get_header_from_pointer (ptr, &p, &r);
|
||
|
||
if (p == r->first)
|
||
{
|
||
p->magic = PUPA_MM_FREE_MAGIC;
|
||
p->next = p;
|
||
}
|
||
else
|
||
{
|
||
pupa_mm_header_t q;
|
||
|
||
for (q = r->first; q >= p || q->next <= p; q = q->next)
|
||
{
|
||
if (q->magic != PUPA_MM_FREE_MAGIC)
|
||
pupa_fatal ("free magic is broken at %p", q);
|
||
|
||
if (q >= q->next && (q < p || q->next > p))
|
||
break;
|
||
}
|
||
|
||
p->magic = PUPA_MM_FREE_MAGIC;
|
||
p->next = q->next;
|
||
q->next = p;
|
||
|
||
if (p + p->size == p->next)
|
||
{
|
||
p->next->magic = 0;
|
||
p->size += p->next->size;
|
||
p->next = p->next->next;
|
||
}
|
||
|
||
if (q + q->size == p)
|
||
{
|
||
p->magic = 0;
|
||
q->size += p->size;
|
||
q->next = p->next;
|
||
}
|
||
|
||
r->first = q;
|
||
}
|
||
}
|
||
|
||
/* Reallocate SIZE bytes and return the pointer. The contents will be
|
||
the same as that of PTR. */
|
||
void *
|
||
pupa_realloc (void *ptr, pupa_size_t size)
|
||
{
|
||
pupa_mm_header_t p;
|
||
pupa_mm_region_t r;
|
||
void *q;
|
||
pupa_size_t n;
|
||
|
||
if (! ptr)
|
||
return pupa_malloc (size);
|
||
|
||
if (! size)
|
||
{
|
||
pupa_free (ptr);
|
||
return 0;
|
||
}
|
||
|
||
/* FIXME: Not optimal. */
|
||
n = ((size + PUPA_MM_ALIGN - 1) >> PUPA_MM_ALIGN_LOG2) + 1;
|
||
get_header_from_pointer (ptr, &p, &r);
|
||
|
||
if (p->size >= n)
|
||
return p;
|
||
|
||
q = pupa_malloc (size);
|
||
if (! q)
|
||
return q;
|
||
|
||
pupa_memcpy (q, ptr, size);
|
||
pupa_free (ptr);
|
||
return q;
|
||
}
|
||
|
||
#if MM_DEBUG
|
||
void
|
||
pupa_mm_dump (unsigned lineno)
|
||
{
|
||
pupa_mm_region_t r;
|
||
|
||
pupa_printf ("called at line %u\n", lineno);
|
||
for (r = base; r; r = r->next)
|
||
{
|
||
pupa_mm_header_t p;
|
||
|
||
for (p = (pupa_mm_header_t) ((r->addr + PUPA_MM_ALIGN - 1)
|
||
& (~(PUPA_MM_ALIGN - 1)));
|
||
(pupa_addr_t) p < r->addr + r->size;
|
||
p++)
|
||
{
|
||
switch (p->magic)
|
||
{
|
||
case PUPA_MM_FREE_MAGIC:
|
||
pupa_printf ("F:%p:%u:%p\n",
|
||
p, p->size << PUPA_MM_ALIGN_LOG2, p->next);
|
||
break;
|
||
case PUPA_MM_ALLOC_MAGIC:
|
||
pupa_printf ("A:%p:%u\n", p, p->size << PUPA_MM_ALIGN_LOG2);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
pupa_printf ("\n");
|
||
}
|
||
#endif /* MM_DEBUG */
|