fdt.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2013-2015 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/fdt.h>
  19. #include <grub/mm.h>
  20. #include <grub/err.h>
  21. #include <grub/dl.h>
  22. #include <grub/command.h>
  23. #include <grub/file.h>
  24. #include <grub/efi/efi.h>
  25. #include <grub/efi/fdtload.h>
  26. #include <grub/efi/memory.h>
  27. static void *loaded_fdt;
  28. static void *fdt;
  29. #define FDT_ADDR_CELLS_STRING "#address-cells"
  30. #define FDT_SIZE_CELLS_STRING "#size-cells"
  31. #define FDT_ADDR_SIZE_EXTRA ((2 * grub_fdt_prop_entry_size (sizeof(grub_uint32_t))) + \
  32. sizeof (FDT_ADDR_CELLS_STRING) + \
  33. sizeof (FDT_SIZE_CELLS_STRING))
  34. void *
  35. grub_fdt_load (grub_size_t additional_size)
  36. {
  37. void *raw_fdt;
  38. unsigned int size;
  39. if (fdt)
  40. {
  41. size = GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt));
  42. grub_efi_free_pages ((grub_addr_t) fdt, size);
  43. }
  44. if (loaded_fdt)
  45. raw_fdt = loaded_fdt;
  46. else
  47. raw_fdt = grub_efi_get_firmware_fdt();
  48. if (raw_fdt)
  49. size = grub_fdt_get_totalsize (raw_fdt);
  50. else
  51. size = GRUB_FDT_EMPTY_TREE_SZ + FDT_ADDR_SIZE_EXTRA;
  52. size += additional_size;
  53. grub_dprintf ("linux", "allocating %d bytes for fdt\n", size);
  54. fdt = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (size));
  55. if (!fdt)
  56. return NULL;
  57. if (raw_fdt)
  58. {
  59. grub_memmove (fdt, raw_fdt, size - additional_size);
  60. grub_fdt_set_totalsize (fdt, size);
  61. }
  62. else
  63. {
  64. grub_fdt_create_empty_tree (fdt, size);
  65. grub_fdt_set_prop32 (fdt, 0, FDT_ADDR_CELLS_STRING, 2);
  66. grub_fdt_set_prop32 (fdt, 0, FDT_SIZE_CELLS_STRING, 2);
  67. }
  68. return fdt;
  69. }
  70. grub_err_t
  71. grub_fdt_install (void)
  72. {
  73. grub_efi_boot_services_t *b;
  74. grub_efi_guid_t fdt_guid = GRUB_EFI_DEVICE_TREE_GUID;
  75. grub_efi_status_t status;
  76. b = grub_efi_system_table->boot_services;
  77. status = b->install_configuration_table (&fdt_guid, fdt);
  78. if (status != GRUB_EFI_SUCCESS)
  79. return grub_error (GRUB_ERR_IO, "failed to install FDT");
  80. grub_dprintf ("fdt", "Installed/updated FDT configuration table @ %p\n",
  81. fdt);
  82. return GRUB_ERR_NONE;
  83. }
  84. void
  85. grub_fdt_unload (void) {
  86. if (!fdt) {
  87. return;
  88. }
  89. grub_efi_free_pages ((grub_addr_t) fdt,
  90. GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt)));
  91. fdt = NULL;
  92. }
  93. static grub_err_t
  94. grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
  95. int argc, char *argv[])
  96. {
  97. grub_file_t dtb;
  98. void *blob = NULL;
  99. int size;
  100. if (loaded_fdt)
  101. grub_free (loaded_fdt);
  102. loaded_fdt = NULL;
  103. /* No arguments means "use firmware FDT". */
  104. if (argc == 0)
  105. {
  106. return GRUB_ERR_NONE;
  107. }
  108. dtb = grub_file_open (argv[0], GRUB_FILE_TYPE_DEVICE_TREE_IMAGE);
  109. if (!dtb)
  110. goto out;
  111. size = grub_file_size (dtb);
  112. blob = grub_malloc (size);
  113. if (!blob)
  114. goto out;
  115. if (grub_file_read (dtb, blob, size) < size)
  116. {
  117. if (!grub_errno)
  118. grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]);
  119. goto out;
  120. }
  121. if (grub_fdt_check_header (blob, size) != 0)
  122. {
  123. grub_error (GRUB_ERR_BAD_OS, N_("invalid device tree"));
  124. goto out;
  125. }
  126. out:
  127. if (dtb)
  128. grub_file_close (dtb);
  129. if (blob)
  130. {
  131. if (grub_errno == GRUB_ERR_NONE)
  132. loaded_fdt = blob;
  133. else
  134. grub_free (blob);
  135. }
  136. return grub_errno;
  137. }
  138. static grub_command_t cmd_devicetree;
  139. GRUB_MOD_INIT (fdt)
  140. {
  141. cmd_devicetree =
  142. grub_register_command ("devicetree", grub_cmd_devicetree, 0,
  143. N_("Load DTB file."));
  144. }
  145. GRUB_MOD_FINI (fdt)
  146. {
  147. grub_unregister_command (cmd_devicetree);
  148. }