| /* Memory management for efiemu */ |
| /* |
| * GRUB -- GRand Unified Bootloader |
| * Copyright (C) 2009 Free Software Foundation, Inc. |
| * |
| * GRUB 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 3 of the License, or |
| * (at your option) any later version. |
| * |
| * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| /* |
| To keep efiemu runtime contiguous this mm is special. |
| It uses deferred allocation. |
| In the first stage you may request memory with grub_efiemu_request_memalign |
| It will give you a handle with which in the second phase you can access your |
| memory with grub_efiemu_mm_obtain_request (handle). It's guaranteed that |
| subsequent calls with the same handle return the same result. You can't request any additional memory once you're in the second phase |
| */ |
| |
| #include <grub/err.h> |
| #include <grub/normal.h> |
| #include <grub/mm.h> |
| #include <grub/misc.h> |
| #include <grub/efiemu/efiemu.h> |
| #include <grub/memory.h> |
| |
| struct grub_efiemu_memrequest |
| { |
| struct grub_efiemu_memrequest *next; |
| grub_efi_memory_type_t type; |
| grub_size_t size; |
| grub_size_t align_overhead; |
| int handle; |
| void *val; |
| }; |
| /* Linked list of requested memory. */ |
| static struct grub_efiemu_memrequest *memrequests = 0; |
| /* Memory map. */ |
| static grub_efi_memory_descriptor_t *efiemu_mmap = 0; |
| /* Pointer to allocated memory */ |
| static void *resident_memory = 0; |
| /* Size of requested memory per type */ |
| static grub_size_t requested_memory[GRUB_EFI_MAX_MEMORY_TYPE]; |
| /* How many slots is allocated for memory_map and how many are already used */ |
| static int mmap_reserved_size = 0, mmap_num = 0; |
| |
| /* Add a memory region to map*/ |
| static grub_err_t |
| grub_efiemu_add_to_mmap (grub_uint64_t start, grub_uint64_t size, |
| grub_efi_memory_type_t type) |
| { |
| grub_uint64_t page_start, npages; |
| |
| /* Extend map if necessary*/ |
| if (mmap_num >= mmap_reserved_size) |
| { |
| void *old; |
| mmap_reserved_size = 2 * (mmap_reserved_size + 1); |
| old = efiemu_mmap; |
| efiemu_mmap = (grub_efi_memory_descriptor_t *) |
| grub_realloc (efiemu_mmap, mmap_reserved_size |
| * sizeof (grub_efi_memory_descriptor_t)); |
| if (!efiemu_mmap) |
| { |
| grub_free (old); |
| return grub_errno; |
| } |
| } |
| |
| /* Fill slot*/ |
| page_start = start - (start % GRUB_EFIEMU_PAGESIZE); |
| npages = (size + (start % GRUB_EFIEMU_PAGESIZE) + GRUB_EFIEMU_PAGESIZE - 1) |
| / GRUB_EFIEMU_PAGESIZE; |
| efiemu_mmap[mmap_num].physical_start = page_start; |
| efiemu_mmap[mmap_num].virtual_start = page_start; |
| efiemu_mmap[mmap_num].num_pages = npages; |
| efiemu_mmap[mmap_num].type = type; |
| mmap_num++; |
| |
| return GRUB_ERR_NONE; |
| } |
| |
| /* Request a resident memory of type TYPE of size SIZE aligned at ALIGN |
| ALIGN must be a divisor of page size (if it's a divisor of 4096 |
| it should be ok on all platforms) |
| */ |
| int |
| grub_efiemu_request_memalign (grub_size_t align, grub_size_t size, |
| grub_efi_memory_type_t type) |
| { |
| grub_size_t align_overhead; |
| struct grub_efiemu_memrequest *ret, *cur, *prev; |
| /* Check that the request is correct */ |
| if (type <= GRUB_EFI_LOADER_CODE || type == GRUB_EFI_PERSISTENT_MEMORY || |
| type >= GRUB_EFI_MAX_MEMORY_TYPE) |
| return -2; |
| |
| /* Add new size to requested size */ |
| align_overhead = align - (requested_memory[type]%align); |
| if (align_overhead == align) |
| align_overhead = 0; |
| requested_memory[type] += align_overhead + size; |
| |
| /* Remember the request */ |
| ret = grub_zalloc (sizeof (*ret)); |
| if (!ret) |
| return -1; |
| ret->type = type; |
| ret->size = size; |
| ret->align_overhead = align_overhead; |
| prev = 0; |
| |
| /* Add request to the end of the chain. |
| It should be at the end because otherwise alignment isn't guaranteed */ |
| for (cur = memrequests; cur; prev = cur, cur = cur->next); |
| if (prev) |
| { |
| ret->handle = prev->handle + 1; |
| prev->next = ret; |
| } |
| else |
| { |
| ret->handle = 1; /* Avoid 0 handle*/ |
| memrequests = ret; |
| } |
| return ret->handle; |
| } |
| |
| /* Really allocate the memory */ |
| static grub_err_t |
| efiemu_alloc_requests (void) |
| { |
| grub_size_t align_overhead = 0; |
| grub_uint8_t *curptr, *typestart; |
| struct grub_efiemu_memrequest *cur; |
| grub_size_t total_alloc = 0; |
| unsigned i; |
| /* Order of memory regions */ |
| grub_efi_memory_type_t reqorder[] = |
| { |
| /* First come regions usable by OS*/ |
| GRUB_EFI_LOADER_CODE, |
| GRUB_EFI_LOADER_DATA, |
| GRUB_EFI_BOOT_SERVICES_CODE, |
| GRUB_EFI_BOOT_SERVICES_DATA, |
| GRUB_EFI_CONVENTIONAL_MEMORY, |
| GRUB_EFI_ACPI_RECLAIM_MEMORY, |
| |
| /* Then memory used by runtime */ |
| /* This way all our regions are in a single block */ |
| GRUB_EFI_RUNTIME_SERVICES_CODE, |
| GRUB_EFI_RUNTIME_SERVICES_DATA, |
| GRUB_EFI_ACPI_MEMORY_NVS, |
| |
| /* And then unavailable memory types. This is more for a completeness. |
| You should double think before allocating memory of any of these types |
| */ |
| GRUB_EFI_UNUSABLE_MEMORY, |
| GRUB_EFI_MEMORY_MAPPED_IO, |
| GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE, |
| GRUB_EFI_PAL_CODE |
| |
| /* |
| * These are not allocatable: |
| * GRUB_EFI_RESERVED_MEMORY_TYPE |
| * GRUB_EFI_PERSISTENT_MEMORY |
| * >= GRUB_EFI_MAX_MEMORY_TYPE |
| */ |
| }; |
| |
| /* Compute total memory needed */ |
| for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++) |
| { |
| align_overhead = GRUB_EFIEMU_PAGESIZE |
| - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE); |
| if (align_overhead == GRUB_EFIEMU_PAGESIZE) |
| align_overhead = 0; |
| total_alloc += requested_memory[reqorder[i]] + align_overhead; |
| } |
| |
| /* Allocate the whole memory in one block */ |
| resident_memory = grub_memalign (GRUB_EFIEMU_PAGESIZE, total_alloc); |
| if (!resident_memory) |
| return grub_errno; |
| |
| /* Split the memory into blocks by type */ |
| curptr = resident_memory; |
| for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++) |
| { |
| if (!requested_memory[reqorder[i]]) |
| continue; |
| typestart = curptr; |
| |
| /* Write pointers to requests */ |
| for (cur = memrequests; cur; cur = cur->next) |
| if (cur->type == reqorder[i]) |
| { |
| curptr = ((grub_uint8_t *)curptr) + cur->align_overhead; |
| cur->val = curptr; |
| curptr = ((grub_uint8_t *)curptr) + cur->size; |
| } |
| |
| /* Ensure that the regions are page-aligned */ |
| align_overhead = GRUB_EFIEMU_PAGESIZE |
| - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE); |
| if (align_overhead == GRUB_EFIEMU_PAGESIZE) |
| align_overhead = 0; |
| curptr = ((grub_uint8_t *) curptr) + align_overhead; |
| |
| /* Add the region to memory map */ |
| grub_efiemu_add_to_mmap ((grub_addr_t) typestart, |
| curptr - typestart, reqorder[i]); |
| } |
| |
| return GRUB_ERR_NONE; |
| } |
| |
| /* Get a pointer to requested memory from handle */ |
| void * |
| grub_efiemu_mm_obtain_request (int handle) |
| { |
| struct grub_efiemu_memrequest *cur; |
| for (cur = memrequests; cur; cur = cur->next) |
| if (cur->handle == handle) |
| return cur->val; |
| return 0; |
| } |
| |
| /* Get type of requested memory by handle */ |
| grub_efi_memory_type_t |
| grub_efiemu_mm_get_type (int handle) |
| { |
| struct grub_efiemu_memrequest *cur; |
| for (cur = memrequests; cur; cur = cur->next) |
| if (cur->handle == handle) |
| return cur->type; |
| return 0; |
| } |
| |
| /* Free a request */ |
| void |
| grub_efiemu_mm_return_request (int handle) |
| { |
| struct grub_efiemu_memrequest *cur, *prev; |
| |
| /* Remove head if necessary */ |
| while (memrequests && memrequests->handle == handle) |
| { |
| cur = memrequests->next; |
| grub_free (memrequests); |
| memrequests = cur; |
| } |
| if (!memrequests) |
| return; |
| |
| /* Remove request from a middle of chain*/ |
| for (prev = memrequests, cur = prev->next; cur;) |
| if (cur->handle == handle) |
| { |
| prev->next = cur->next; |
| grub_free (cur); |
| cur = prev->next; |
| } |
| else |
| { |
| prev = cur; |
| cur = prev->next; |
| } |
| } |
| |
| /* Helper for grub_efiemu_mmap_init. */ |
| static int |
| bounds_hook (grub_uint64_t addr __attribute__ ((unused)), |
| grub_uint64_t size __attribute__ ((unused)), |
| grub_memory_type_t type __attribute__ ((unused)), |
| void *data __attribute__ ((unused))) |
| { |
| mmap_reserved_size++; |
| return 0; |
| } |
| |
| /* Reserve space for memory map */ |
| static grub_err_t |
| grub_efiemu_mmap_init (void) |
| { |
| // the place for memory used by efiemu itself |
| mmap_reserved_size = GRUB_EFI_MAX_MEMORY_TYPE + 1; |
| |
| #ifndef GRUB_MACHINE_EMU |
| grub_machine_mmap_iterate (bounds_hook, NULL); |
| #endif |
| |
| return GRUB_ERR_NONE; |
| } |
| |
| /* This is a drop-in replacement of grub_efi_get_memory_map */ |
| /* 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. */ |
| int |
| grub_efiemu_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_uintn_t *descriptor_size, |
| grub_efi_uint32_t *descriptor_version) |
| { |
| if (!efiemu_mmap) |
| { |
| grub_error (GRUB_ERR_INVALID_COMMAND, |
| "you need to first launch efiemu_prepare"); |
| return -1; |
| } |
| |
| if (*memory_map_size < mmap_num * sizeof (grub_efi_memory_descriptor_t)) |
| { |
| *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t); |
| return 0; |
| } |
| |
| *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t); |
| grub_memcpy (memory_map, efiemu_mmap, *memory_map_size); |
| if (descriptor_size) |
| *descriptor_size = sizeof (grub_efi_memory_descriptor_t); |
| if (descriptor_version) |
| *descriptor_version = 1; |
| if (map_key) |
| *map_key = 0; |
| |
| return 1; |
| } |
| |
| grub_err_t |
| grub_efiemu_finish_boot_services (grub_efi_uintn_t *memory_map_size, |
| grub_efi_memory_descriptor_t *memory_map, |
| grub_efi_uintn_t *map_key, |
| grub_efi_uintn_t *descriptor_size, |
| grub_efi_uint32_t *descriptor_version) |
| { |
| int val = grub_efiemu_get_memory_map (memory_map_size, |
| memory_map, map_key, |
| descriptor_size, |
| descriptor_version); |
| if (val == 1) |
| return GRUB_ERR_NONE; |
| if (val == -1) |
| return grub_errno; |
| return grub_error (GRUB_ERR_IO, "memory map buffer is too small"); |
| } |
| |
| |
| /* Free everything */ |
| grub_err_t |
| grub_efiemu_mm_unload (void) |
| { |
| struct grub_efiemu_memrequest *cur, *d; |
| for (cur = memrequests; cur;) |
| { |
| d = cur->next; |
| grub_free (cur); |
| cur = d; |
| } |
| memrequests = 0; |
| grub_memset (&requested_memory, 0, sizeof (requested_memory)); |
| grub_free (resident_memory); |
| resident_memory = 0; |
| grub_free (efiemu_mmap); |
| efiemu_mmap = 0; |
| mmap_reserved_size = mmap_num = 0; |
| return GRUB_ERR_NONE; |
| } |
| |
| /* This function should be called before doing any requests */ |
| grub_err_t |
| grub_efiemu_mm_init (void) |
| { |
| grub_err_t err; |
| |
| err = grub_efiemu_mm_unload (); |
| if (err) |
| return err; |
| |
| grub_efiemu_mmap_init (); |
| |
| return GRUB_ERR_NONE; |
| } |
| |
| /* Helper for grub_efiemu_mmap_fill. */ |
| static int |
| fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type, |
| void *data __attribute__ ((unused))) |
| { |
| switch (type) |
| { |
| case GRUB_MEMORY_AVAILABLE: |
| return grub_efiemu_add_to_mmap (addr, size, |
| GRUB_EFI_CONVENTIONAL_MEMORY); |
| |
| case GRUB_MEMORY_ACPI: |
| return grub_efiemu_add_to_mmap (addr, size, |
| GRUB_EFI_ACPI_RECLAIM_MEMORY); |
| |
| case GRUB_MEMORY_NVS: |
| return grub_efiemu_add_to_mmap (addr, size, |
| GRUB_EFI_ACPI_MEMORY_NVS); |
| |
| case GRUB_MEMORY_PERSISTENT: |
| case GRUB_MEMORY_PERSISTENT_LEGACY: |
| return grub_efiemu_add_to_mmap (addr, size, |
| GRUB_EFI_PERSISTENT_MEMORY); |
| default: |
| grub_dprintf ("efiemu", |
| "Unknown memory type %d. Assuming unusable\n", type); |
| /* FALLTHROUGH */ |
| case GRUB_MEMORY_RESERVED: |
| return grub_efiemu_add_to_mmap (addr, size, |
| GRUB_EFI_UNUSABLE_MEMORY); |
| } |
| } |
| |
| /* Copy host memory map */ |
| static grub_err_t |
| grub_efiemu_mmap_fill (void) |
| { |
| #ifndef GRUB_MACHINE_EMU |
| grub_machine_mmap_iterate (fill_hook, NULL); |
| #endif |
| |
| return GRUB_ERR_NONE; |
| } |
| |
| grub_err_t |
| grub_efiemu_mmap_iterate (grub_memory_hook_t hook, void *hook_data) |
| { |
| unsigned i; |
| |
| for (i = 0; i < (unsigned) mmap_num; i++) |
| switch (efiemu_mmap[i].type) |
| { |
| case GRUB_EFI_RUNTIME_SERVICES_CODE: |
| hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, |
| GRUB_MEMORY_CODE, hook_data); |
| break; |
| |
| case GRUB_EFI_UNUSABLE_MEMORY: |
| hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, |
| GRUB_MEMORY_BADRAM, hook_data); |
| break; |
| |
| case GRUB_EFI_RESERVED_MEMORY_TYPE: |
| case GRUB_EFI_RUNTIME_SERVICES_DATA: |
| case GRUB_EFI_MEMORY_MAPPED_IO: |
| case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE: |
| case GRUB_EFI_PAL_CODE: |
| default: |
| hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, |
| GRUB_MEMORY_RESERVED, hook_data); |
| break; |
| |
| case GRUB_EFI_LOADER_CODE: |
| case GRUB_EFI_LOADER_DATA: |
| case GRUB_EFI_BOOT_SERVICES_CODE: |
| case GRUB_EFI_BOOT_SERVICES_DATA: |
| case GRUB_EFI_CONVENTIONAL_MEMORY: |
| hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, |
| GRUB_MEMORY_AVAILABLE, hook_data); |
| break; |
| |
| case GRUB_EFI_ACPI_RECLAIM_MEMORY: |
| hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, |
| GRUB_MEMORY_ACPI, hook_data); |
| break; |
| |
| case GRUB_EFI_ACPI_MEMORY_NVS: |
| hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, |
| GRUB_MEMORY_NVS, hook_data); |
| break; |
| |
| case GRUB_EFI_PERSISTENT_MEMORY: |
| hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, |
| GRUB_MEMORY_PERSISTENT, hook_data); |
| break; |
| |
| } |
| |
| return 0; |
| } |
| |
| |
| /* This function resolves overlapping regions and sorts the memory map |
| It uses scanline (sweeping) algorithm |
| */ |
| static grub_err_t |
| grub_efiemu_mmap_sort_and_uniq (void) |
| { |
| /* If same page is used by multiple types it's resolved |
| according to priority |
| 0 - free memory |
| 1 - memory immediately usable after ExitBootServices |
| 2 - memory usable after loading ACPI tables |
| 3 - efiemu memory |
| 4 - unusable memory |
| */ |
| int priority[GRUB_EFI_MAX_MEMORY_TYPE] = |
| { |
| [GRUB_EFI_RESERVED_MEMORY_TYPE] = 4, |
| [GRUB_EFI_LOADER_CODE] = 1, |
| [GRUB_EFI_LOADER_DATA] = 1, |
| [GRUB_EFI_BOOT_SERVICES_CODE] = 1, |
| [GRUB_EFI_BOOT_SERVICES_DATA] = 1, |
| [GRUB_EFI_RUNTIME_SERVICES_CODE] = 3, |
| [GRUB_EFI_RUNTIME_SERVICES_DATA] = 3, |
| [GRUB_EFI_CONVENTIONAL_MEMORY] = 0, |
| [GRUB_EFI_UNUSABLE_MEMORY] = 4, |
| [GRUB_EFI_ACPI_RECLAIM_MEMORY] = 2, |
| [GRUB_EFI_ACPI_MEMORY_NVS] = 3, |
| [GRUB_EFI_MEMORY_MAPPED_IO] = 4, |
| [GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE] = 4, |
| [GRUB_EFI_PAL_CODE] = 4, |
| [GRUB_EFI_PERSISTENT_MEMORY] = 4 |
| }; |
| |
| int i, j, k, done; |
| |
| /* Scanline events */ |
| struct grub_efiemu_mmap_scan |
| { |
| /* At which memory address*/ |
| grub_uint64_t pos; |
| /* 0 = region starts, 1 = region ends */ |
| int type; |
| /* Which type of memory region */ |
| grub_efi_memory_type_t memtype; |
| }; |
| struct grub_efiemu_mmap_scan *scanline_events; |
| struct grub_efiemu_mmap_scan t; |
| |
| /* Previous scanline event */ |
| grub_uint64_t lastaddr; |
| int lasttype; |
| /* Current scanline event */ |
| int curtype; |
| /* how many regions of given type overlap at current location */ |
| int present[GRUB_EFI_MAX_MEMORY_TYPE]; |
| /* Here is stored the resulting memory map*/ |
| grub_efi_memory_descriptor_t *result; |
| |
| /* Initialize variables*/ |
| grub_memset (present, 0, sizeof (int) * GRUB_EFI_MAX_MEMORY_TYPE); |
| scanline_events = (struct grub_efiemu_mmap_scan *) |
| grub_calloc (mmap_num, sizeof (struct grub_efiemu_mmap_scan) * 2); |
| |
| /* Number of chunks can't increase more than by factor of 2 */ |
| result = (grub_efi_memory_descriptor_t *) |
| grub_calloc (mmap_num, sizeof (grub_efi_memory_descriptor_t) * 2); |
| if (!result || !scanline_events) |
| { |
| grub_free (result); |
| grub_free (scanline_events); |
| return grub_errno; |
| } |
| |
| /* Register scanline events */ |
| for (i = 0; i < mmap_num; i++) |
| { |
| scanline_events[2 * i].pos = efiemu_mmap[i].physical_start; |
| scanline_events[2 * i].type = 0; |
| scanline_events[2 * i].memtype = efiemu_mmap[i].type; |
| scanline_events[2 * i + 1].pos = efiemu_mmap[i].physical_start |
| + efiemu_mmap[i].num_pages * GRUB_EFIEMU_PAGESIZE; |
| scanline_events[2 * i + 1].type = 1; |
| scanline_events[2 * i + 1].memtype = efiemu_mmap[i].type; |
| } |
| |
| /* Primitive bubble sort. It has complexity O(n^2) but since we're |
| unlikely to have more than 100 chunks it's probably one of the |
| fastest for one purpose */ |
| done = 1; |
| while (done) |
| { |
| done = 0; |
| for (i = 0; i < 2 * mmap_num - 1; i++) |
| if (scanline_events[i + 1].pos < scanline_events[i].pos) |
| { |
| t = scanline_events[i + 1]; |
| scanline_events[i + 1] = scanline_events[i]; |
| scanline_events[i] = t; |
| done = 1; |
| } |
| } |
| |
| /* Pointer in resulting memory map */ |
| j = 0; |
| lastaddr = scanline_events[0].pos; |
| lasttype = scanline_events[0].memtype; |
| for (i = 0; i < 2 * mmap_num; i++) |
| { |
| /* Process event */ |
| if (scanline_events[i].type) |
| present[scanline_events[i].memtype]--; |
| else |
| present[scanline_events[i].memtype]++; |
| |
| /* Determine current region type */ |
| curtype = -1; |
| for (k = 0; k < GRUB_EFI_MAX_MEMORY_TYPE; k++) |
| if (present[k] && (curtype == -1 || priority[k] > priority[curtype])) |
| curtype = k; |
| |
| /* Add memory region to resulting map if necessary */ |
| if ((curtype == -1 || curtype != lasttype) |
| && lastaddr != scanline_events[i].pos |
| && lasttype != -1) |
| { |
| result[j].virtual_start = result[j].physical_start = lastaddr; |
| result[j].num_pages = (scanline_events[i].pos - lastaddr) |
| / GRUB_EFIEMU_PAGESIZE; |
| result[j].type = lasttype; |
| |
| /* We set runtime attribute on pages we need to be mapped */ |
| result[j].attribute |
| = (lasttype == GRUB_EFI_RUNTIME_SERVICES_CODE |
| || lasttype == GRUB_EFI_RUNTIME_SERVICES_DATA) |
| ? GRUB_EFI_MEMORY_RUNTIME : 0; |
| grub_dprintf ("efiemu", |
| "mmap entry: type %d start 0x%llx 0x%llx pages\n", |
| result[j].type, |
| result[j].physical_start, result[j].num_pages); |
| j++; |
| } |
| |
| /* Update last values if necessary */ |
| if (curtype == -1 || curtype != lasttype) |
| { |
| lasttype = curtype; |
| lastaddr = scanline_events[i].pos; |
| } |
| } |
| |
| grub_free (scanline_events); |
| |
| /* Shrink resulting memory map to really used size and replace efiemu_mmap |
| by new value */ |
| grub_free (efiemu_mmap); |
| efiemu_mmap = grub_realloc (result, j * sizeof (*result)); |
| return GRUB_ERR_NONE; |
| } |
| |
| /* This function is called to switch from first to second phase */ |
| grub_err_t |
| grub_efiemu_mm_do_alloc (void) |
| { |
| grub_err_t err; |
| |
| /* Preallocate mmap */ |
| efiemu_mmap = (grub_efi_memory_descriptor_t *) |
| grub_calloc (mmap_reserved_size, sizeof (grub_efi_memory_descriptor_t)); |
| if (!efiemu_mmap) |
| { |
| grub_efiemu_unload (); |
| return grub_errno; |
| } |
| |
| err = efiemu_alloc_requests (); |
| if (err) |
| return err; |
| err = grub_efiemu_mmap_fill (); |
| if (err) |
| return err; |
| return grub_efiemu_mmap_sort_and_uniq (); |
| } |