Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:wenbowang
grub
grub-0.97-better-get-memory-map-rhbz607213.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File grub-0.97-better-get-memory-map-rhbz607213.patch of Package grub
From 3605b86b534c4bdc5ab5011b7ac1568bf986fa91 Mon Sep 17 00:00:00 2001 From: Peter Jones <pjones@redhat.com> Date: Mon, 12 Jul 2010 16:45:47 -0400 Subject: [PATCH] Make the allocator for kernel memory slightly more sane... Based on a patch from Stuart Hayes. --- efi/efimm.c | 78 ++++++++++++++++++++---------------- efi/grub/efi/efi.h | 8 ++- efi/ia32/loader/linux.c | 96 ++++++-------------------------------------- efi/x86_64/loader/linux.c | 90 +++++------------------------------------- 4 files changed, 71 insertions(+), 201 deletions(-) diff --git a/efi/efimm.c b/efi/efimm.c index 3b790d5..e21babd 100644 --- a/efi/efimm.c +++ b/efi/efimm.c @@ -32,9 +32,11 @@ #define BYTES_TO_PAGES(bytes) ((bytes) >> 12) #define PAGES_TO_BYTES(pages) ((pages) << 12) -/* The size of a memory map obtained from the firmware. This must be - a multiplier of 4KB. */ -#define MEMORY_MAP_SIZE 0x2000 +/* Global variables used to store memory map, its size, and the number of + * pages allocated for the buffer. */ +void *mmap_buf; +grub_efi_uintn_t mmap_size; +grub_efi_uintn_t mmap_pages; /* Maintain the list of allocated pages. */ struct allocated_page @@ -205,11 +207,14 @@ grub_efi_free_pages (grub_efi_physical_address_t address, } /* Get the memory map as defined in the EFI spec. Return 1 if successful, - return 0 if partial, or return -1 if an error occurs. */ + return 0 if partial, or return -1 if an error occurs. + + This function will allocate memory for (global) mmap_buf if there isn't + already a buffer allocated, and will free & reallocate if it needs to + be larger. */ + int -grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, - grub_efi_memory_descriptor_t *memory_map, - grub_efi_uintn_t *map_key, +grub_efi_get_memory_map (grub_efi_uintn_t *map_key, grub_efi_uintn_t *descriptor_size, grub_efi_uint32_t *descriptor_version) { @@ -217,6 +222,7 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, grub_efi_boot_services_t *b; grub_efi_uintn_t key; grub_efi_uint32_t version; + grub_efi_uintn_t tmp_mmap_size; /* Allow some parameters to be missing. */ if (! map_key) @@ -224,16 +230,35 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, if (! descriptor_version) descriptor_version = &version; - b = grub_efi_system_table->boot_services; - status = Call_Service_5 (b->get_memory_map, - memory_map_size, memory_map, map_key, + while (1) + { + b = grub_efi_system_table->boot_services; + tmp_mmap_size = PAGES_TO_BYTES(mmap_pages); + status = Call_Service_5 (b->get_memory_map, + &tmp_mmap_size, mmap_buf, map_key, descriptor_size, descriptor_version); - if (status == GRUB_EFI_SUCCESS) - return 1; - else if (status == GRUB_EFI_BUFFER_TOO_SMALL) - return 0; - else - return -1; + if (status == GRUB_EFI_SUCCESS) + { + mmap_size = tmp_mmap_size; + return 1; + } + else if (status != GRUB_EFI_BUFFER_TOO_SMALL) + return -1; + + /* we need a larger buffer */ + if (mmap_buf) + grub_efi_free_pages ((grub_addr_t) mmap_buf, mmap_pages); + + /* get 1 more page than we need, just in case */ + mmap_pages = BYTES_TO_PAGES(tmp_mmap_size + 4095) + 1; + mmap_buf = grub_efi_allocate_pages (0, mmap_pages); + if (! mmap_buf) + { + mmap_pages = 0; + grub_printf ("cannot allocate memory for memory map"); + return -1; + } + } } #define MMAR_DESC_LENGTH 20 @@ -345,33 +370,16 @@ static void update_e820_map (struct e820_entry *e820_map, int *e820_nr_map) { - grub_efi_memory_descriptor_t *memory_map; - grub_efi_uintn_t map_size; grub_efi_uintn_t desc_size; - /* Prepare a memory region to store memory map. */ - memory_map = grub_efi_allocate_pages (0, BYTES_TO_PAGES (MEMORY_MAP_SIZE)); - if (! memory_map) - { - grub_printf ("cannot allocate memory"); - return; - } - - /* Obtain descriptors for available memory. */ - map_size = MEMORY_MAP_SIZE; - - if (grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0) < 0) + if (grub_efi_get_memory_map (0, &desc_size, 0) < 0) { grub_printf ("cannot get memory map"); return; } e820_map_from_efi_map (e820_map, e820_nr_map, - memory_map, desc_size, map_size); - - /* Release the memory map. */ - grub_efi_free_pages ((grub_addr_t) memory_map, - BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + mmap_buf, desc_size, mmap_size); } /* Simulated memory sizes. */ diff --git a/efi/grub/efi/efi.h b/efi/grub/efi/efi.h index 858e37d..936759b 100644 --- a/efi/grub/efi/efi.h +++ b/efi/grub/efi/efi.h @@ -52,9 +52,7 @@ void grub_efi_free_pages (grub_efi_physical_address_t address, grub_efi_uintn_t pages); int -grub_efi_get_memory_map (grub_efi_uintn_t * memory_map_size, - grub_efi_memory_descriptor_t * memory_map, - grub_efi_uintn_t * map_key, +grub_efi_get_memory_map (grub_efi_uintn_t * map_key, grub_efi_uintn_t * descriptor_size, grub_efi_uint32_t * descriptor_version); grub_efi_loaded_image_t *grub_efi_get_loaded_image (grub_efi_handle_t @@ -71,6 +69,10 @@ void grub_efi_fini (void); void grub_efi_set_prefix (void); /* Variables. */ +extern void *mmap_buf; +extern grub_efi_uintn_t mmap_size; +extern grub_efi_uintn_t mmap_pages; + extern grub_efi_system_table_t *grub_efi_system_table; extern grub_efi_handle_t grub_efi_image_handle; diff --git a/efi/ia32/loader/linux.c b/efi/ia32/loader/linux.c index 41f1ce6..eb6b5de 100644 --- a/efi/ia32/loader/linux.c +++ b/efi/ia32/loader/linux.c @@ -42,11 +42,9 @@ static int loaded; static void *real_mode_mem; static void *prot_mode_mem; static void *initrd_mem; -static void *mmap_buf; static grub_efi_uintn_t real_mode_pages; static grub_efi_uintn_t prot_mode_pages; static grub_efi_uintn_t initrd_pages; -static grub_efi_uintn_t mmap_pages; static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GRAPHICS_OUTPUT_GUID; static inline grub_size_t @@ -55,45 +53,6 @@ page_align (grub_size_t size) return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); } -/* Find the optimal number of pages for the memory map. Is it better to - move this code to efimm.c? */ -static grub_efi_uintn_t -find_mmap_size (void) -{ - static grub_efi_uintn_t mmap_size = 0; - - if (mmap_size != 0) - return mmap_size; - - mmap_size = (1 << 12); - while (1) - { - int ret; - grub_efi_memory_descriptor_t *mmap; - grub_efi_uintn_t desc_size; - - mmap = grub_malloc (mmap_size); - if (! mmap) - return 0; - - ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); - grub_free (mmap); - - if (ret < 0) - grub_fatal ("cannot get memory map"); - else if (ret > 0) - break; - - mmap_size += (1 << 12); - } - - /* Increase the size a bit for safety, because GRUB allocates more on - later, and EFI itself may allocate more. */ - mmap_size += (1 << 11); - - return page_align (mmap_size); -} - static void free_pages (void) { @@ -128,15 +87,13 @@ static int allocate_pages (grub_size_t real_size, grub_size_t prot_size) { grub_efi_uintn_t desc_size; - grub_efi_memory_descriptor_t *mmap, *mmap_end; - grub_efi_uintn_t mmap_size, tmp_mmap_size; + grub_efi_memory_descriptor_t *mmap_end; grub_efi_memory_descriptor_t *desc; grub_efi_physical_address_t addr; /* Make sure that each size is aligned to a page boundary. */ real_size = page_align (real_size + SECTOR_SIZE); prot_size = page_align (prot_size); - mmap_size = find_mmap_size (); grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", (unsigned int) real_size, (unsigned int) prot_size, @@ -146,30 +103,19 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) the memory map buffer for simplicity. */ real_mode_pages = (real_size >> 12); prot_mode_pages = (prot_size >> 12); - mmap_pages = (mmap_size >> 12); /* Initialize the memory pointers with NULL for convenience. */ real_mode_mem = 0; prot_mode_mem = 0; - mmap_buf = 0; - - /* Read the memory map temporarily, to find free space. */ - mmap = grub_malloc (mmap_size); - if (! mmap) - { - errnum = ERR_UNRECOGNIZED; - return 0; - } - tmp_mmap_size = mmap_size; - if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0) + if (grub_efi_get_memory_map (0, &desc_size, 0) <= 0) grub_fatal ("cannot get memory map"); addr = 0; - mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size); + mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); /* First, find free pages for the real mode code and the memory map buffer. */ - for (desc = mmap; + for (desc = mmap_buf; desc < mmap_end; desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { @@ -183,7 +129,7 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n", (unsigned) desc->physical_start, (unsigned) physical_end); - addr = physical_end - real_size - mmap_size; + addr = physical_end - real_size; if (addr < 0x10000) continue; @@ -205,29 +151,15 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) goto fail; } - mmap_buf = grub_efi_allocate_pages (0, mmap_pages); - if (! mmap_buf) - { - grub_printf("cannot allocate efi mmap pages"); - errnum = ERR_WONT_FIT; - goto fail; - } - /* Next, find free pages for the protected mode code. */ /* XXX what happens if anything is using this address? */ prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages); if (! prot_mode_mem) - { - errnum = ERR_WONT_FIT; - grub_printf ("cannot allocate protected mode pages"); - goto fail; - } + grub_fatal("Cannot allocate pages for VMLINUZ"); - grub_free (mmap); return 1; fail: - grub_free (mmap); free_pages (); return 0; } @@ -274,7 +206,6 @@ big_linux_boot (void) { struct linux_kernel_params *params; struct grub_linux_kernel_header *lh; - grub_efi_uintn_t mmap_size; grub_efi_uintn_t map_key; grub_efi_uintn_t desc_size; grub_efi_uint32_t desc_version; @@ -285,9 +216,7 @@ big_linux_boot (void) graphics_set_kernel_params (params); - mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) <= 0) + if (grub_efi_get_memory_map (&map_key, &desc_size, &desc_version) <= 0) grub_fatal ("cannot get memory map"); /* Pass e820 memmap. */ @@ -599,10 +528,12 @@ grub_load_initrd (char *initrd) grub_ssize_t size; grub_addr_t addr_min, addr_max; grub_addr_t addr; - grub_efi_uintn_t mmap_size; + grub_efi_uintn_t map_key; + grub_efi_memory_descriptor_t *mmap_end; grub_efi_memory_descriptor_t *desc; grub_efi_memory_descriptor_t tdesc; grub_efi_uintn_t desc_size; + grub_efi_uint32_t desc_version; struct linux_kernel_params *params; if (initrd == NULL) @@ -644,14 +575,13 @@ grub_load_initrd (char *initrd) grub_dprintf(__func__, "prot_mode_mem=%p prot_mode_pages=%lu\n", prot_mode_mem, prot_mode_pages); /* Find the highest address to put the initrd. */ - mmap_size = find_mmap_size (); - grub_dprintf(__func__, "addr_min: 0x%lx addr_max: 0x%lx mmap_size: %lu\n", addr_min, addr_max, mmap_size); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0) + if (grub_efi_get_memory_map (&map_key, &desc_size, &desc_version) <= 0) grub_fatal ("cannot get memory map"); + mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); addr = 0; for (desc = mmap_buf; - desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); + desc < mmap_end; desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) diff --git a/efi/x86_64/loader/linux.c b/efi/x86_64/loader/linux.c index a5cfbf8..18746ea 100644 --- a/efi/x86_64/loader/linux.c +++ b/efi/x86_64/loader/linux.c @@ -43,11 +43,9 @@ static void *real_mode_mem; static void *prot_mode_mem; static grub_size_t prot_kernel_size; static void *initrd_mem; -static void *mmap_buf; static grub_efi_uintn_t real_mode_pages; static grub_efi_uintn_t prot_mode_pages; static grub_efi_uintn_t initrd_pages; -static grub_efi_uintn_t mmap_pages; static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GRAPHICS_OUTPUT_GUID; static inline grub_size_t @@ -56,45 +54,6 @@ page_align (grub_size_t size) return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); } -/* Find the optimal number of pages for the memory map. Is it better to - move this code to efimm.c? */ -static grub_efi_uintn_t -find_mmap_size (void) -{ - static grub_efi_uintn_t mmap_size = 0; - - if (mmap_size != 0) - return mmap_size; - - mmap_size = (1 << 12); - while (1) - { - int ret; - grub_efi_memory_descriptor_t *mmap; - grub_efi_uintn_t desc_size; - - mmap = grub_malloc (mmap_size); - if (! mmap) - return 0; - - ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); - grub_free (mmap); - - if (ret < 0) - grub_fatal ("cannot get memory map"); - else if (ret > 0) - break; - - mmap_size += (1 << 12); - } - - /* Increase the size a bit for safety, because GRUB allocates more on - later, and EFI itself may allocate more. */ - mmap_size += (1 << 11); - - return page_align (mmap_size); -} - static void free_pages (void) { @@ -123,15 +82,13 @@ static int allocate_pages (grub_size_t real_size, grub_size_t prot_size) { grub_efi_uintn_t desc_size; - grub_efi_memory_descriptor_t *mmap, *mmap_end; - grub_efi_uintn_t mmap_size, tmp_mmap_size; + grub_efi_memory_descriptor_t *mmap_end; grub_efi_memory_descriptor_t *desc; grub_efi_physical_address_t addr; /* Make sure that each size is aligned to a page boundary. */ real_size = page_align (real_size + SECTOR_SIZE); prot_size = page_align (prot_size); - mmap_size = find_mmap_size (); grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", (unsigned int) real_size, (unsigned int) prot_size, @@ -141,30 +98,19 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) the memory map buffer for simplicity. */ real_mode_pages = (real_size >> 12); prot_mode_pages = (prot_size >> 12); - mmap_pages = (mmap_size >> 12); /* Initialize the memory pointers with NULL for convenience. */ real_mode_mem = 0; prot_mode_mem = 0; - mmap_buf = 0; - - /* Read the memory map temporarily, to find free space. */ - mmap = grub_malloc (mmap_size); - if (! mmap) - { - errnum = ERR_UNRECOGNIZED; - return 0; - } - tmp_mmap_size = mmap_size; - if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0) + if (grub_efi_get_memory_map (0, &desc_size, 0) <= 0) grub_fatal ("cannot get memory map"); addr = 0; - mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size); + mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); /* First, find free pages for the real mode code and the memory map buffer. */ - for (desc = mmap; + for (desc = mmap_buf; desc < mmap_end; desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { @@ -172,23 +118,22 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) && desc->num_pages >= real_mode_pages) { grub_efi_physical_address_t physical_end; - int allocsize = real_size + mmap_size; physical_end = desc->physical_start + (desc->num_pages << 12); grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n", (unsigned) desc->physical_start, (unsigned) physical_end); - addr = physical_end - allocsize; + addr = physical_end - real_size; if (addr < 0x10000) continue; /* the kernel wants this address to be under 1 gig.*/ - if (desc->physical_start > 0x40000000 - allocsize) + if (desc->physical_start > 0x40000000 - real_size) continue; - if (addr > 0x40000000 - allocsize) - addr = 0x40000000 - allocsize; + if (addr > 0x40000000 - real_size) + addr = 0x40000000 - real_size; grub_dprintf ("linux", "trying to allocate %u pages at %x\n", (unsigned) real_mode_pages, (unsigned) addr); @@ -215,19 +160,9 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) if (!prot_mode_mem) grub_fatal("Cannot allocate pages for VMLINUZ"); - mmap_buf = grub_efi_allocate_pages (0, mmap_pages); - if (! mmap_buf) - { - grub_printf("cannot allocate efi mmap pages"); - errnum = ERR_WONT_FIT; - goto fail; - } - - grub_free (mmap); return 1; fail: - grub_free (mmap); free_pages (); return 0; } @@ -245,7 +180,6 @@ big_linux_boot (void) { struct linux_kernel_params *params; struct grub_linux_kernel_header *lh; - grub_efi_uintn_t mmap_size; grub_efi_uintn_t map_key; grub_efi_uintn_t desc_size; grub_efi_uint32_t desc_version; @@ -255,9 +189,7 @@ big_linux_boot (void) graphics_set_kernel_params (params); - mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) <= 0) + if (grub_efi_get_memory_map (&map_key, &desc_size, &desc_version) <= 0) grub_fatal ("cannot get memory map"); /* Pass e820 memmap. */ @@ -544,7 +476,6 @@ grub_load_initrd (char *initrd) grub_ssize_t size; grub_addr_t addr_min, addr_max; grub_addr_t addr; - grub_efi_uintn_t mmap_size; grub_efi_memory_descriptor_t *desc; grub_efi_memory_descriptor_t tdesc; grub_efi_uintn_t desc_size; @@ -582,9 +513,8 @@ grub_load_initrd (char *initrd) addr_min = 0; /* Find the highest address to put the initrd. */ - mmap_size = find_mmap_size (); grub_dprintf(__func__, "addr_min: 0x%lx addr_max: 0x%lx mmap_size: %lu\n", addr_min, addr_max, mmap_size); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0) + if (grub_efi_get_memory_map (0, &desc_size, 0) <= 0) grub_fatal ("cannot get memory map"); addr = 0; -- 1.7.1.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor