From 6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 14 Oct 2013 16:33:44 +0200 Subject: [PATCH] Pass-through unknown E820 types. It required reorganisation of mmap module. --- ChangeLog | 5 + grub-core/commands/lsmmap.c | 5 +- grub-core/loader/i386/bsd.c | 29 +----- grub-core/loader/i386/linux.c | 25 +---- grub-core/loader/i386/multiboot_mbi.c | 23 +---- grub-core/loader/multiboot_mbi2.c | 23 +---- grub-core/mmap/mmap.c | 134 +++++++++++++++++--------- include/grub/memory.h | 6 +- 8 files changed, 111 insertions(+), 139 deletions(-) diff --git a/ChangeLog b/ChangeLog index 222522e4d..06e07b7ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-10-14 Vladimir Serbinenko + + Pass-through unknown E820 types. It required reorganisation of mmap + module. + 2013-10-14 Andrey Borzenkov * Makefile.util.def: Add osdep/init.c to grub-mount files. diff --git a/grub-core/commands/lsmmap.c b/grub-core/commands/lsmmap.c index 0d298559c..4b504fd28 100644 --- a/grub-core/commands/lsmmap.c +++ b/grub-core/commands/lsmmap.c @@ -38,8 +38,7 @@ static const char *names[] = [GRUB_MEMORY_NVS] = N_("ACPI non-volatile storage RAM"), [GRUB_MEMORY_BADRAM] = N_("faulty RAM (BadRAM)"), [GRUB_MEMORY_COREBOOT_TABLES] = N_("RAM holding coreboot tables"), - [GRUB_MEMORY_CODE] = N_("RAM holding firmware code"), - [GRUB_MEMORY_HOLE] = N_("Address range not associated with RAM") + [GRUB_MEMORY_CODE] = N_("RAM holding firmware code") }; /* 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, 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"), (long long) addr, (long long) size, _(names[type])); else diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 90877a365..5143813fe 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -287,34 +287,15 @@ generate_e820_mmap_iter (grub_uint64_t addr, grub_uint64_t size, ctx->cur.addr = addr; ctx->cur.size = size; - switch (type) - { - case GRUB_MEMORY_AVAILABLE: - ctx->cur.type = GRUB_E820_RAM; - break; - case GRUB_MEMORY_ACPI: - ctx->cur.type = GRUB_E820_ACPI; - break; - - case GRUB_MEMORY_NVS: - ctx->cur.type = GRUB_E820_NVS; - break; - case GRUB_MEMORY_COREBOOT_TABLES: + if (type == GRUB_MEMORY_COREBOOT_TABLES + && addr == 0) /* Nowadays the tables at 0 don't contain anything important but *BSD needs the memory at 0 for own needs. */ - if (addr == 0) - ctx->cur.type = GRUB_E820_RAM; - else - ctx->cur.type = GRUB_E820_COREBOOT_TABLES; - break; - default: - case GRUB_MEMORY_CODE: - case GRUB_MEMORY_RESERVED: - ctx->cur.type = GRUB_E820_RESERVED; - break; - } + type = GRUB_E820_RAM; + + ctx->cur.type = type; /* Merge regions if possible. */ if (ctx->count && ctx->cur.type == ctx->prev.type diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 4ff610609..4e6a38898 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -421,36 +421,15 @@ grub_linux_boot_mmap_find (grub_uint64_t addr, grub_uint64_t size, return 1; } +/* GRUB types conveniently match E820 types. */ static int grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type, void *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, - addr, size, e820_type)) + addr, size, type)) return 1; return 0; diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index 18fd367ee..37cf36d7a 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -233,28 +233,7 @@ grub_fill_multiboot_mmap_iter (grub_uint64_t addr, grub_uint64_t size, (*mmap_entry)->addr = addr; (*mmap_entry)->len = size; - switch (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)->type = type; (*mmap_entry)->size = sizeof (struct multiboot_mmap_entry) - sizeof ((*mmap_entry)->size); (*mmap_entry)++; diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index ccd32a746..561c79157 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -331,28 +331,7 @@ grub_fill_multiboot_mmap_iter (grub_uint64_t addr, grub_uint64_t size, (*mmap_entry)->addr = addr; (*mmap_entry)->len = size; - switch (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)->type = type; (*mmap_entry)++; return 0; diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c index d8bd8d2e6..6a31cbae3 100644 --- a/grub-core/mmap/mmap.c +++ b/grub-core/mmap/mmap.c @@ -35,23 +35,7 @@ static int curhandle = 1; #endif -/* If same page is used by multiple types it's resolved - 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, -}; +static int current_priority = 1; /* Scanline events. */ struct grub_mmap_scan @@ -61,7 +45,9 @@ struct grub_mmap_scan /* 0 = region starts, 1 = region ends. */ int type; /* 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. */ @@ -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; - ctx->scanline_events[ctx->i].pos = addr; - ctx->scanline_events[ctx->i].type = 0; - if (type < ARRAY_SIZE (priority) && priority[type]) - ctx->scanline_events[ctx->i].memtype = type; - else + if (type == GRUB_MEMORY_HOLE) { grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n", 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->scanline_events[ctx->i].pos = addr + size; ctx->scanline_events[ctx->i].type = 1; - ctx->scanline_events[ctx->i].memtype = - ctx->scanline_events[ctx->i - 1].memtype; + ctx->scanline_events[ctx->i].memtype = type; + ctx->scanline_events[ctx->i].priority = 0; ctx->i++; return 0; } +struct mm_list +{ + struct mm_list *next; + grub_memory_type_t val; + int present; +}; + grub_err_t 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; /* Current scanline event. */ int curtype; - /* How many regions of given type overlap at current location? */ - int present[ARRAY_SIZE (priority)]; + /* How many regions of given type/priority overlap at current location? */ + /* Normally there shouldn't be more than one region per priority but be robust. */ + struct mm_list *present; /* Number of mmap chunks. */ 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); /* Initialize variables. */ - grub_memset (present, 0, sizeof (present)); ctx.scanline_events = (struct grub_mmap_scan *) grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num); - if (! ctx.scanline_events) - return grub_errno; + present = grub_zalloc (sizeof (present[0]) * current_priority); + + if (! ctx.scanline_events || !present) + { + grub_free (ctx.scanline_events); + grub_free (present); + return grub_errno; + } ctx.i = 0; #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].type = 0; - if (cur->type < ARRAY_SIZE (priority) && priority[cur->type]) - ctx.scanline_events[ctx.i].memtype = cur->type; - else - ctx.scanline_events[ctx.i].memtype = GRUB_MEMORY_RESERVED; + ctx.scanline_events[ctx.i].memtype = cur->type; + ctx.scanline_events[ctx.i].priority = cur->priority; ctx.i++; ctx.scanline_events[ctx.i].pos = cur->end; ctx.scanline_events[ctx.i].type = 1; - ctx.scanline_events[ctx.i].memtype = - ctx.scanline_events[ctx.i - 1].memtype; + ctx.scanline_events[ctx.i].memtype = cur->type; + ctx.scanline_events[ctx.i].priority = cur->priority; ctx.i++; } #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; for (i = 0; i < 2 * mmap_num; i++) { - unsigned k; /* Process event. */ 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 + { + 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 - present[ctx.scanline_events[i].memtype]++; + { + 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. */ curtype = -1; - for (k = 0; k < ARRAY_SIZE (priority); k++) - if (present[k] && (curtype == -1 || priority[k] > priority[curtype])) - curtype = k; + { + int 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. */ 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->type = type; cur->handle = curhandle++; + cur->priority = current_priority++; grub_mmap_overlays = cur; if (grub_machine_mmap_register (start, size, type, curhandle)) diff --git a/include/grub/memory.h b/include/grub/memory.h index 0df807424..083cfb680 100644 --- a/include/grub/memory.h +++ b/include/grub/memory.h @@ -33,8 +33,9 @@ typedef enum grub_memory_type GRUB_MEMORY_COREBOOT_TABLES = 16, GRUB_MEMORY_CODE = 20, /* This one is special: it's used internally but is never reported - by firmware. */ - GRUB_MEMORY_HOLE = 21 + by firmware. Don't use -1 as it's used internally for other purposes. */ + GRUB_MEMORY_HOLE = -2, + GRUB_MEMORY_MAX = 0x10000 } grub_memory_type_t; typedef int (*grub_memory_hook_t) (grub_uint64_t, @@ -75,6 +76,7 @@ struct grub_mmap_region grub_uint64_t end; grub_memory_type_t type; int handle; + int priority; }; extern struct grub_mmap_region *grub_mmap_overlays;