Pass-through unknown E820 types. It required reorganisation of mmap

module.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2013-10-14 16:33:44 +02:00
parent f8f3f15559
commit 6de9ee86bf
8 changed files with 111 additions and 139 deletions

View file

@ -1,3 +1,8 @@
2013-10-14 Vladimir Serbinenko <phcoder@gmail.com>
Pass-through unknown E820 types. It required reorganisation of mmap
module.
2013-10-14 Andrey Borzenkov <arvidjaar@gmail.com> 2013-10-14 Andrey Borzenkov <arvidjaar@gmail.com>
* Makefile.util.def: Add osdep/init.c to grub-mount files. * Makefile.util.def: Add osdep/init.c to grub-mount files.

View file

@ -38,8 +38,7 @@ static const char *names[] =
[GRUB_MEMORY_NVS] = N_("ACPI non-volatile storage RAM"), [GRUB_MEMORY_NVS] = N_("ACPI non-volatile storage RAM"),
[GRUB_MEMORY_BADRAM] = N_("faulty RAM (BadRAM)"), [GRUB_MEMORY_BADRAM] = N_("faulty RAM (BadRAM)"),
[GRUB_MEMORY_COREBOOT_TABLES] = N_("RAM holding coreboot tables"), [GRUB_MEMORY_COREBOOT_TABLES] = N_("RAM holding coreboot tables"),
[GRUB_MEMORY_CODE] = N_("RAM holding firmware code"), [GRUB_MEMORY_CODE] = N_("RAM holding firmware code")
[GRUB_MEMORY_HOLE] = N_("Address range not associated with RAM")
}; };
/* Helper for grub_cmd_lsmmap. */ /* Helper for grub_cmd_lsmmap. */
@ -47,7 +46,7 @@ static int
lsmmap_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type, lsmmap_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
void *data __attribute__ ((unused))) void *data __attribute__ ((unused)))
{ {
if (type < ARRAY_SIZE (names) && names[type]) if (type < (int) ARRAY_SIZE (names) && type >= 0 && names[type])
grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, %s\n"), grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, %s\n"),
(long long) addr, (long long) size, _(names[type])); (long long) addr, (long long) size, _(names[type]));
else else

View file

@ -287,34 +287,15 @@ generate_e820_mmap_iter (grub_uint64_t addr, grub_uint64_t size,
ctx->cur.addr = addr; ctx->cur.addr = addr;
ctx->cur.size = size; ctx->cur.size = size;
switch (type)
{
case GRUB_MEMORY_AVAILABLE:
ctx->cur.type = GRUB_E820_RAM;
break;
case GRUB_MEMORY_ACPI: if (type == GRUB_MEMORY_COREBOOT_TABLES
ctx->cur.type = GRUB_E820_ACPI; && addr == 0)
break;
case GRUB_MEMORY_NVS:
ctx->cur.type = GRUB_E820_NVS;
break;
case GRUB_MEMORY_COREBOOT_TABLES:
/* Nowadays the tables at 0 don't contain anything important but /* Nowadays the tables at 0 don't contain anything important but
*BSD needs the memory at 0 for own needs. *BSD needs the memory at 0 for own needs.
*/ */
if (addr == 0) type = GRUB_E820_RAM;
ctx->cur.type = GRUB_E820_RAM;
else ctx->cur.type = type;
ctx->cur.type = GRUB_E820_COREBOOT_TABLES;
break;
default:
case GRUB_MEMORY_CODE:
case GRUB_MEMORY_RESERVED:
ctx->cur.type = GRUB_E820_RESERVED;
break;
}
/* Merge regions if possible. */ /* Merge regions if possible. */
if (ctx->count && ctx->cur.type == ctx->prev.type if (ctx->count && ctx->cur.type == ctx->prev.type

View file

@ -421,36 +421,15 @@ grub_linux_boot_mmap_find (grub_uint64_t addr, grub_uint64_t size,
return 1; return 1;
} }
/* GRUB types conveniently match E820 types. */
static int static int
grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size, grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size,
grub_memory_type_t type, void *data) grub_memory_type_t type, void *data)
{ {
struct grub_linux_boot_ctx *ctx = data; struct grub_linux_boot_ctx *ctx = data;
grub_uint32_t e820_type;
switch (type)
{
case GRUB_MEMORY_AVAILABLE:
e820_type = GRUB_E820_RAM;
break;
case GRUB_MEMORY_ACPI:
e820_type = GRUB_E820_ACPI;
break;
case GRUB_MEMORY_NVS:
e820_type = GRUB_E820_NVS;
break;
case GRUB_MEMORY_BADRAM:
e820_type = GRUB_E820_BADRAM;
break;
default:
e820_type = GRUB_E820_RESERVED;
}
if (grub_e820_add_region (ctx->params->e820_map, &ctx->e820_num, if (grub_e820_add_region (ctx->params->e820_map, &ctx->e820_num,
addr, size, e820_type)) addr, size, type))
return 1; return 1;
return 0; return 0;

View file

@ -233,28 +233,7 @@ grub_fill_multiboot_mmap_iter (grub_uint64_t addr, grub_uint64_t size,
(*mmap_entry)->addr = addr; (*mmap_entry)->addr = addr;
(*mmap_entry)->len = size; (*mmap_entry)->len = size;
switch (type) (*mmap_entry)->type = type;
{
case GRUB_MEMORY_AVAILABLE:
(*mmap_entry)->type = MULTIBOOT_MEMORY_AVAILABLE;
break;
case GRUB_MEMORY_ACPI:
(*mmap_entry)->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE;
break;
case GRUB_MEMORY_NVS:
(*mmap_entry)->type = MULTIBOOT_MEMORY_NVS;
break;
case GRUB_MEMORY_BADRAM:
(*mmap_entry)->type = MULTIBOOT_MEMORY_BADRAM;
break;
default:
(*mmap_entry)->type = MULTIBOOT_MEMORY_RESERVED;
break;
}
(*mmap_entry)->size = sizeof (struct multiboot_mmap_entry) - sizeof ((*mmap_entry)->size); (*mmap_entry)->size = sizeof (struct multiboot_mmap_entry) - sizeof ((*mmap_entry)->size);
(*mmap_entry)++; (*mmap_entry)++;

View file

@ -331,28 +331,7 @@ grub_fill_multiboot_mmap_iter (grub_uint64_t addr, grub_uint64_t size,
(*mmap_entry)->addr = addr; (*mmap_entry)->addr = addr;
(*mmap_entry)->len = size; (*mmap_entry)->len = size;
switch (type) (*mmap_entry)->type = type;
{
case GRUB_MEMORY_AVAILABLE:
(*mmap_entry)->type = MULTIBOOT_MEMORY_AVAILABLE;
break;
case GRUB_MEMORY_ACPI:
(*mmap_entry)->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE;
break;
case GRUB_MEMORY_NVS:
(*mmap_entry)->type = MULTIBOOT_MEMORY_NVS;
break;
case GRUB_MEMORY_BADRAM:
(*mmap_entry)->type = MULTIBOOT_MEMORY_BADRAM;
break;
default:
(*mmap_entry)->type = MULTIBOOT_MEMORY_RESERVED;
break;
}
(*mmap_entry)++; (*mmap_entry)++;
return 0; return 0;

View file

@ -35,23 +35,7 @@ static int curhandle = 1;
#endif #endif
/* If same page is used by multiple types it's resolved static int current_priority = 1;
according to priority:
1 - free memory
2 - memory usable by firmware-aware code
3 - unusable memory
4 - a range deliberately empty
*/
static const int priority[] =
{
[GRUB_MEMORY_AVAILABLE] = 1,
[GRUB_MEMORY_RESERVED] = 3,
[GRUB_MEMORY_ACPI] = 2,
[GRUB_MEMORY_COREBOOT_TABLES] = 2,
[GRUB_MEMORY_CODE] = 3,
[GRUB_MEMORY_NVS] = 3,
[GRUB_MEMORY_HOLE] = 4,
};
/* Scanline events. */ /* Scanline events. */
struct grub_mmap_scan struct grub_mmap_scan
@ -61,7 +45,9 @@ struct grub_mmap_scan
/* 0 = region starts, 1 = region ends. */ /* 0 = region starts, 1 = region ends. */
int type; int type;
/* Which type of memory region? */ /* Which type of memory region? */
int memtype; grub_memory_type_t memtype;
/* Priority. 0 means coming from firmware. */
int priority;
}; };
/* Context for grub_mmap_iterate. */ /* Context for grub_mmap_iterate. */
@ -90,27 +76,36 @@ fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
{ {
struct grub_mmap_iterate_ctx *ctx = data; struct grub_mmap_iterate_ctx *ctx = data;
ctx->scanline_events[ctx->i].pos = addr; if (type == GRUB_MEMORY_HOLE)
ctx->scanline_events[ctx->i].type = 0;
if (type < ARRAY_SIZE (priority) && priority[type])
ctx->scanline_events[ctx->i].memtype = type;
else
{ {
grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n", grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n",
type); type);
ctx->scanline_events[ctx->i].memtype = GRUB_MEMORY_RESERVED; type = GRUB_MEMORY_RESERVED;
} }
ctx->scanline_events[ctx->i].pos = addr;
ctx->scanline_events[ctx->i].type = 0;
ctx->scanline_events[ctx->i].memtype = type;
ctx->scanline_events[ctx->i].priority = 0;
ctx->i++; ctx->i++;
ctx->scanline_events[ctx->i].pos = addr + size; ctx->scanline_events[ctx->i].pos = addr + size;
ctx->scanline_events[ctx->i].type = 1; ctx->scanline_events[ctx->i].type = 1;
ctx->scanline_events[ctx->i].memtype = ctx->scanline_events[ctx->i].memtype = type;
ctx->scanline_events[ctx->i - 1].memtype; ctx->scanline_events[ctx->i].priority = 0;
ctx->i++; ctx->i++;
return 0; return 0;
} }
struct mm_list
{
struct mm_list *next;
grub_memory_type_t val;
int present;
};
grub_err_t grub_err_t
grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data) grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
{ {
@ -127,8 +122,9 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
int lasttype; int lasttype;
/* Current scanline event. */ /* Current scanline event. */
int curtype; int curtype;
/* How many regions of given type overlap at current location? */ /* How many regions of given type/priority overlap at current location? */
int present[ARRAY_SIZE (priority)]; /* Normally there shouldn't be more than one region per priority but be robust. */
struct mm_list *present;
/* Number of mmap chunks. */ /* Number of mmap chunks. */
int mmap_num; int mmap_num;
@ -146,12 +142,17 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
grub_machine_mmap_iterate (count_hook, &mmap_num); grub_machine_mmap_iterate (count_hook, &mmap_num);
/* Initialize variables. */ /* Initialize variables. */
grub_memset (present, 0, sizeof (present));
ctx.scanline_events = (struct grub_mmap_scan *) ctx.scanline_events = (struct grub_mmap_scan *)
grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num); grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);
if (! ctx.scanline_events) present = grub_zalloc (sizeof (present[0]) * current_priority);
if (! ctx.scanline_events || !present)
{
grub_free (ctx.scanline_events);
grub_free (present);
return grub_errno; return grub_errno;
}
ctx.i = 0; ctx.i = 0;
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
@ -160,16 +161,14 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
{ {
ctx.scanline_events[ctx.i].pos = cur->start; ctx.scanline_events[ctx.i].pos = cur->start;
ctx.scanline_events[ctx.i].type = 0; ctx.scanline_events[ctx.i].type = 0;
if (cur->type < ARRAY_SIZE (priority) && priority[cur->type])
ctx.scanline_events[ctx.i].memtype = cur->type; ctx.scanline_events[ctx.i].memtype = cur->type;
else ctx.scanline_events[ctx.i].priority = cur->priority;
ctx.scanline_events[ctx.i].memtype = GRUB_MEMORY_RESERVED;
ctx.i++; ctx.i++;
ctx.scanline_events[ctx.i].pos = cur->end; ctx.scanline_events[ctx.i].pos = cur->end;
ctx.scanline_events[ctx.i].type = 1; ctx.scanline_events[ctx.i].type = 1;
ctx.scanline_events[ctx.i].memtype = ctx.scanline_events[ctx.i].memtype = cur->type;
ctx.scanline_events[ctx.i - 1].memtype; ctx.scanline_events[ctx.i].priority = cur->priority;
ctx.i++; ctx.i++;
} }
#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */ #endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
@ -200,18 +199,66 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
lasttype = ctx.scanline_events[0].memtype; lasttype = ctx.scanline_events[0].memtype;
for (i = 0; i < 2 * mmap_num; i++) for (i = 0; i < 2 * mmap_num; i++)
{ {
unsigned k;
/* Process event. */ /* Process event. */
if (ctx.scanline_events[i].type) if (ctx.scanline_events[i].type)
present[ctx.scanline_events[i].memtype]--; {
if (present[ctx.scanline_events[i].priority].present)
{
if (present[ctx.scanline_events[i].priority].val == ctx.scanline_events[i].memtype)
{
if (present[ctx.scanline_events[i].priority].next)
{
struct mm_list *p = present[ctx.scanline_events[i].priority].next;
present[ctx.scanline_events[i].priority] = *p;
grub_free (p);
}
else else
present[ctx.scanline_events[i].memtype]++; {
present[ctx.scanline_events[i].priority].present = 0;
}
}
else
{
struct mm_list **q = &(present[ctx.scanline_events[i].priority].next), *p;
for (; *q; q = &((*q)->next))
if ((*q)->val == ctx.scanline_events[i].memtype)
{
p = *q;
*q = p->next;
grub_free (p);
break;
}
}
}
}
else
{
if (!present[ctx.scanline_events[i].priority].present)
{
present[ctx.scanline_events[i].priority].present = 1;
present[ctx.scanline_events[i].priority].val = ctx.scanline_events[i].memtype;
}
else
{
struct mm_list *n = grub_malloc (sizeof (*n));
n->val = ctx.scanline_events[i].memtype;
n->present = 1;
n->next = present[ctx.scanline_events[i].priority].next;
present[ctx.scanline_events[i].priority].next = n;
}
}
/* Determine current region type. */ /* Determine current region type. */
curtype = -1; curtype = -1;
for (k = 0; k < ARRAY_SIZE (priority); k++) {
if (present[k] && (curtype == -1 || priority[k] > priority[curtype])) int k;
curtype = k; for (k = current_priority - 1; k >= 0; k--)
if (present[k].present)
{
curtype = present[k].val;
break;
}
}
/* Announce region to the hook if necessary. */ /* Announce region to the hook if necessary. */
if ((curtype == -1 || curtype != lasttype) if ((curtype == -1 || curtype != lasttype)
@ -255,6 +302,7 @@ grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
cur->end = start + size; cur->end = start + size;
cur->type = type; cur->type = type;
cur->handle = curhandle++; cur->handle = curhandle++;
cur->priority = current_priority++;
grub_mmap_overlays = cur; grub_mmap_overlays = cur;
if (grub_machine_mmap_register (start, size, type, curhandle)) if (grub_machine_mmap_register (start, size, type, curhandle))

View file

@ -33,8 +33,9 @@ typedef enum grub_memory_type
GRUB_MEMORY_COREBOOT_TABLES = 16, GRUB_MEMORY_COREBOOT_TABLES = 16,
GRUB_MEMORY_CODE = 20, GRUB_MEMORY_CODE = 20,
/* This one is special: it's used internally but is never reported /* This one is special: it's used internally but is never reported
by firmware. */ by firmware. Don't use -1 as it's used internally for other purposes. */
GRUB_MEMORY_HOLE = 21 GRUB_MEMORY_HOLE = -2,
GRUB_MEMORY_MAX = 0x10000
} grub_memory_type_t; } grub_memory_type_t;
typedef int (*grub_memory_hook_t) (grub_uint64_t, typedef int (*grub_memory_hook_t) (grub_uint64_t,
@ -75,6 +76,7 @@ struct grub_mmap_region
grub_uint64_t end; grub_uint64_t end;
grub_memory_type_t type; grub_memory_type_t type;
int handle; int handle;
int priority;
}; };
extern struct grub_mmap_region *grub_mmap_overlays; extern struct grub_mmap_region *grub_mmap_overlays;