alignedmem.c 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #include <dragonstub/dragonstub.h>
  2. #include <dragonstub/linux/align.h>
  3. #include <dragonstub/linux/math.h>
  4. /**
  5. * efi_allocate_pages_aligned() - Allocate memory pages
  6. * @size: minimum number of bytes to allocate
  7. * @addr: On return the address of the first allocated page. The first
  8. * allocated page has alignment EFI_ALLOC_ALIGN which is an
  9. * architecture dependent multiple of the page size.
  10. * @max: the address that the last allocated memory page shall not
  11. * exceed
  12. * @align: minimum alignment of the base of the allocation
  13. *
  14. * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
  15. * to @align, which should be >= EFI_ALLOC_ALIGN. The last allocated page will
  16. * not exceed the address given by @max.
  17. *
  18. * Return: status code
  19. */
  20. efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
  21. unsigned long max, unsigned long align,
  22. int memory_type)
  23. {
  24. efi_physical_addr_t alloc_addr;
  25. efi_status_t status;
  26. int slack;
  27. max = min(max, EFI_ALLOC_LIMIT);
  28. if (align < EFI_ALLOC_ALIGN)
  29. align = EFI_ALLOC_ALIGN;
  30. alloc_addr = ALIGN_DOWN(max + 1, align) - 1;
  31. size = round_up(size, EFI_ALLOC_ALIGN);
  32. slack = align / EFI_PAGE_SIZE - 1;
  33. status = efi_bs_call(AllocatePages, EFI_ALLOCATE_MAX_ADDRESS,
  34. memory_type, size / EFI_PAGE_SIZE + slack,
  35. &alloc_addr);
  36. if (status != EFI_SUCCESS)
  37. return status;
  38. *addr = ALIGN_UP((unsigned long)alloc_addr, align);
  39. if (slack > 0) {
  40. int l = (alloc_addr & (align - 1)) / EFI_PAGE_SIZE;
  41. if (l) {
  42. efi_bs_call(FreePages, alloc_addr, slack - l + 1);
  43. slack = l - 1;
  44. }
  45. if (slack)
  46. efi_bs_call(FreePages, *addr + size, slack);
  47. }
  48. return EFI_SUCCESS;
  49. }