123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- #include <dragonstub/dragonstub.h>
- #include <dragonstub/linux/math.h>
- #include <dragonstub/linux/align.h>
- #include <dragonstub/minmax.h>
- /**
- * efi_get_memory_map() - get memory map
- * @map: pointer to memory map pointer to which to assign the
- * newly allocated memory map
- * @install_cfg_tbl: whether or not to install the boot memory map as a
- * configuration table
- *
- * Retrieve the UEFI memory map. The allocated memory leaves room for
- * up to EFI_MMAP_NR_SLACK_SLOTS additional memory map entries.
- *
- * Return: status code
- */
- efi_status_t efi_get_memory_map(struct efi_boot_memmap **map,
- bool install_cfg_tbl)
- {
- int memtype = install_cfg_tbl ? EfiACPIReclaimMemory : EfiLoaderData;
- efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
- struct efi_boot_memmap *m, tmp;
- efi_status_t status;
- unsigned long size;
- tmp.map_size = 0;
- status = efi_bs_call(GetMemoryMap, &tmp.map_size, NULL, &tmp.map_key,
- &tmp.desc_size, &tmp.desc_ver);
- if (status != EFI_BUFFER_TOO_SMALL)
- return EFI_LOAD_ERROR;
- size = tmp.map_size + tmp.desc_size * EFI_MMAP_NR_SLACK_SLOTS;
- status = efi_bs_call(AllocatePool, memtype, sizeof(*m) + size,
- (void **)&m);
- if (status != EFI_SUCCESS)
- return status;
- if (install_cfg_tbl) {
- /*
- * Installing a configuration table might allocate memory, and
- * this may modify the memory map. This means we should install
- * the configuration table first, and re-install or delete it
- * as needed.
- */
- status = efi_bs_call(InstallConfigurationTable, &tbl_guid, m);
- if (status != EFI_SUCCESS)
- goto free_map;
- }
- m->buff_size = m->map_size = size;
- status = efi_bs_call(GetMemoryMap, &m->map_size, m->map, &m->map_key,
- &m->desc_size, &m->desc_ver);
- if (status != EFI_SUCCESS)
- goto uninstall_table;
- *map = m;
- return EFI_SUCCESS;
- uninstall_table:
- if (install_cfg_tbl)
- efi_bs_call(InstallConfigurationTable, &tbl_guid, NULL);
- free_map:
- efi_bs_call(FreePool, m);
- return status;
- }
- /**
- * efi_allocate_pages() - Allocate memory pages
- * @size: minimum number of bytes to allocate
- * @addr: On return the address of the first allocated page. The first
- * allocated page has alignment EFI_ALLOC_ALIGN which is an
- * architecture dependent multiple of the page size.
- * @max: the address that the last allocated memory page shall not
- * exceed
- *
- * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
- * to EFI_ALLOC_ALIGN. The last allocated page will not exceed the address
- * given by @max.
- *
- * Return: status code
- */
- efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
- unsigned long max)
- {
- efi_physical_addr_t alloc_addr;
- efi_status_t status;
- max = min(max, EFI_ALLOC_LIMIT);
- // if (EFI_ALLOC_ALIGN > EFI_PAGE_SIZE)
- // return efi_allocate_pages_aligned(
- // size, addr, max, EFI_ALLOC_ALIGN, EfiLoaderData);
- alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
- status = efi_bs_call(AllocatePages, EFI_ALLOCATE_MAX_ADDRESS,
- EfiLoaderData, DIV_ROUND_UP(size, EFI_PAGE_SIZE),
- &alloc_addr);
- if (status != EFI_SUCCESS)
- return status;
- *addr = alloc_addr;
- return EFI_SUCCESS;
- }
- /**
- * efi_allocate_pages_exact() - Allocate memory pages at a specific address
- * @size: minimum number of bytes to allocate
- * @addr: The address of the first allocated page.
- *
- * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
- * to EFI_ALLOC_ALIGN.
- *
- * Return: status code
- */
- efi_status_t efi_allocate_pages_exact(unsigned long size, unsigned long addr)
- {
- efi_status_t status;
- u64 addr_rounded = addr & ~(EFI_ALLOC_ALIGN - 1);
- size += addr - addr_rounded;
- u32 pagecount = DIV_ROUND_UP(size, EFI_PAGE_SIZE);
- efi_debug(
- "efi_allocate_pages_exact: size=%d, addr=%p, addr_rounded=%p, pagecount=%d\n",
- size, addr, addr_rounded, pagecount);
- status = efi_bs_call(AllocatePages, AllocateAddress, EfiLoaderData,
- pagecount, (EFI_PHYSICAL_ADDRESS *)&addr);
- // status = efi_bs_call(AllocatePages, AllocateAddress, EfiLoaderData,
- // DIV_ROUND_UP(size, EFI_PAGE_SIZE),
- // (EFI_PHYSICAL_ADDRESS *)&addr);
- if (status != EFI_SUCCESS)
- return status;
- return EFI_SUCCESS;
- }
- /**
- * efi_free() - free memory pages
- * @size: size of the memory area to free in bytes
- * @addr: start of the memory area to free (must be EFI_PAGE_SIZE
- * aligned)
- *
- * @size is rounded up to a multiple of EFI_ALLOC_ALIGN which is an
- * architecture specific multiple of EFI_PAGE_SIZE. So this function should
- * only be used to return pages allocated with efi_allocate_pages() or
- * efi_low_alloc_above().
- */
- void efi_free(unsigned long size, unsigned long addr)
- {
- unsigned long nr_pages;
- if (!size)
- return;
- nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
- efi_bs_call(FreePages, addr, nr_pages);
- }
|