efi_dt_fixup.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * EFI_DT_FIXUP_PROTOCOL
  4. *
  5. * Copyright (c) 2020 Heinrich Schuchardt
  6. */
  7. #include <common.h>
  8. #include <efi_dt_fixup.h>
  9. #include <efi_loader.h>
  10. #include <mapmem.h>
  11. static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this,
  12. void *dtb,
  13. efi_uintn_t *buffer_size,
  14. u32 flags);
  15. struct efi_dt_fixup_protocol efi_dt_fixup_prot = {
  16. .revision = EFI_DT_FIXUP_PROTOCOL_REVISION,
  17. .fixup = efi_dt_fixup
  18. };
  19. const efi_guid_t efi_guid_dt_fixup_protocol = EFI_DT_FIXUP_PROTOCOL_GUID;
  20. /**
  21. * efi_reserve_memory() - add reserved memory to memory map
  22. *
  23. * @addr: start address of the reserved memory range
  24. * @size: size of the reserved memory range
  25. * @nomap: indicates that the memory range shall not be accessed by the
  26. * UEFI payload
  27. */
  28. static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
  29. {
  30. int type;
  31. efi_uintn_t ret;
  32. /* Convert from sandbox address space. */
  33. addr = (uintptr_t)map_sysmem(addr, 0);
  34. if (nomap)
  35. type = EFI_RESERVED_MEMORY_TYPE;
  36. else
  37. type = EFI_BOOT_SERVICES_DATA;
  38. ret = efi_add_memory_map(addr, size, type);
  39. if (ret != EFI_SUCCESS)
  40. log_err("Reserved memory mapping failed addr %llx size %llx\n",
  41. addr, size);
  42. }
  43. /**
  44. * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
  45. *
  46. * The mem_rsv entries of the FDT are added to the memory map. Any failures are
  47. * ignored because this is not critical and we would rather continue to try to
  48. * boot.
  49. *
  50. * @fdt: Pointer to device tree
  51. */
  52. void efi_carve_out_dt_rsv(void *fdt)
  53. {
  54. int nr_rsv, i;
  55. u64 addr, size;
  56. int nodeoffset, subnode;
  57. nr_rsv = fdt_num_mem_rsv(fdt);
  58. /* Look for an existing entry and add it to the efi mem map. */
  59. for (i = 0; i < nr_rsv; i++) {
  60. if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
  61. continue;
  62. efi_reserve_memory(addr, size, false);
  63. }
  64. /* process reserved-memory */
  65. nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
  66. if (nodeoffset >= 0) {
  67. subnode = fdt_first_subnode(fdt, nodeoffset);
  68. while (subnode >= 0) {
  69. fdt_addr_t fdt_addr;
  70. fdt_size_t fdt_size;
  71. /* check if this subnode has a reg property */
  72. fdt_addr = fdtdec_get_addr_size_auto_parent(
  73. fdt, nodeoffset, subnode,
  74. "reg", 0, &fdt_size, false);
  75. /*
  76. * The /reserved-memory node may have children with
  77. * a size instead of a reg property.
  78. */
  79. if (fdt_addr != FDT_ADDR_T_NONE &&
  80. fdtdec_get_is_enabled(fdt, subnode)) {
  81. bool nomap;
  82. nomap = !!fdt_getprop(fdt, subnode, "no-map",
  83. NULL);
  84. efi_reserve_memory(fdt_addr, fdt_size, nomap);
  85. }
  86. subnode = fdt_next_subnode(fdt, subnode);
  87. }
  88. }
  89. }
  90. static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this,
  91. void *dtb,
  92. efi_uintn_t *buffer_size,
  93. u32 flags)
  94. {
  95. efi_status_t ret;
  96. size_t required_size;
  97. bootm_headers_t img = { 0 };
  98. EFI_ENTRY("%p, %p, %p, %d", this, dtb, buffer_size, flags);
  99. if (this != &efi_dt_fixup_prot || !dtb || !buffer_size ||
  100. !flags || (flags & ~EFI_DT_ALL)) {
  101. ret = EFI_INVALID_PARAMETER;
  102. goto out;
  103. }
  104. if (fdt_check_header(dtb)) {
  105. ret = EFI_INVALID_PARAMETER;
  106. goto out;
  107. }
  108. if (flags & EFI_DT_APPLY_FIXUPS) {
  109. required_size = fdt_off_dt_strings(dtb) +
  110. fdt_size_dt_strings(dtb) +
  111. 0x3000;
  112. } else {
  113. required_size = fdt_totalsize(dtb);
  114. }
  115. if (required_size > *buffer_size) {
  116. *buffer_size = required_size;
  117. ret = EFI_BUFFER_TOO_SMALL;
  118. goto out;
  119. }
  120. fdt_set_totalsize(dtb, *buffer_size);
  121. if (flags & EFI_DT_APPLY_FIXUPS) {
  122. if (image_setup_libfdt(&img, dtb, 0, NULL)) {
  123. log_err("failed to process device tree\n");
  124. ret = EFI_INVALID_PARAMETER;
  125. goto out;
  126. }
  127. }
  128. if (flags & EFI_DT_RESERVE_MEMORY)
  129. efi_carve_out_dt_rsv(dtb);
  130. if (EFI_DT_INSTALL_TABLE) {
  131. ret = efi_install_configuration_table(&efi_guid_fdt, dtb);
  132. if (ret != EFI_SUCCESS) {
  133. log_err("ERROR: failed to install device tree\n");
  134. goto out;
  135. }
  136. }
  137. ret = EFI_SUCCESS;
  138. out:
  139. return EFI_EXIT(ret);
  140. }