relocate.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * (C) Copyright 2008-2011
  3. * Graeme Russ, <graeme.russ@gmail.com>
  4. *
  5. * (C) Copyright 2002
  6. * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
  7. *
  8. * (C) Copyright 2002
  9. * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
  10. *
  11. * (C) Copyright 2002
  12. * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  13. * Marius Groeger <mgroeger@sysgo.de>
  14. *
  15. * SPDX-License-Identifier: GPL-2.0+
  16. */
  17. #include <common.h>
  18. #include <inttypes.h>
  19. #include <asm/u-boot-x86.h>
  20. #include <asm/relocate.h>
  21. #include <asm/sections.h>
  22. #include <elf.h>
  23. DECLARE_GLOBAL_DATA_PTR;
  24. int copy_uboot_to_ram(void)
  25. {
  26. size_t len = (uintptr_t)&__data_end - (uintptr_t)&__text_start;
  27. if (gd->flags & GD_FLG_SKIP_RELOC)
  28. return 0;
  29. memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
  30. return 0;
  31. }
  32. int clear_bss(void)
  33. {
  34. ulong dst_addr = (ulong)&__bss_start + gd->reloc_off;
  35. size_t len = (uintptr_t)&__bss_end - (uintptr_t)&__bss_start;
  36. if (gd->flags & GD_FLG_SKIP_RELOC)
  37. return 0;
  38. memset((void *)dst_addr, 0x00, len);
  39. return 0;
  40. }
  41. #if CONFIG_IS_ENABLED(X86_64)
  42. static void do_elf_reloc_fixups64(unsigned int text_base, uintptr_t size,
  43. Elf64_Rela *re_src, Elf64_Rela *re_end)
  44. {
  45. Elf64_Addr *offset_ptr_rom, *last_offset = NULL;
  46. Elf64_Addr *offset_ptr_ram;
  47. do {
  48. /* Get the location from the relocation entry */
  49. offset_ptr_rom = (Elf64_Addr *)(uintptr_t)re_src->r_offset;
  50. /* Check that the location of the relocation is in .text */
  51. if (offset_ptr_rom >= (Elf64_Addr *)(uintptr_t)text_base &&
  52. offset_ptr_rom > last_offset) {
  53. /* Switch to the in-RAM version */
  54. offset_ptr_ram = (Elf64_Addr *)((ulong)offset_ptr_rom +
  55. gd->reloc_off);
  56. /* Check that the target points into .text */
  57. if (*offset_ptr_ram >= text_base &&
  58. *offset_ptr_ram <= text_base + size) {
  59. *offset_ptr_ram = gd->reloc_off +
  60. re_src->r_addend;
  61. } else {
  62. debug(" %p: %lx: rom reloc %lx, ram %p, value %lx, limit %"
  63. PRIXPTR "\n",
  64. re_src, (ulong)re_src->r_info,
  65. (ulong)re_src->r_offset, offset_ptr_ram,
  66. (ulong)*offset_ptr_ram, text_base + size);
  67. }
  68. } else {
  69. debug(" %p: %lx: rom reloc %lx, last %p\n", re_src,
  70. (ulong)re_src->r_info, (ulong)re_src->r_offset,
  71. last_offset);
  72. }
  73. last_offset = offset_ptr_rom;
  74. } while (++re_src < re_end);
  75. }
  76. #else
  77. static void do_elf_reloc_fixups32(unsigned int text_base, uintptr_t size,
  78. Elf32_Rel *re_src, Elf32_Rel *re_end)
  79. {
  80. Elf32_Addr *offset_ptr_rom, *last_offset = NULL;
  81. Elf32_Addr *offset_ptr_ram;
  82. do {
  83. /* Get the location from the relocation entry */
  84. offset_ptr_rom = (Elf32_Addr *)(uintptr_t)re_src->r_offset;
  85. /* Check that the location of the relocation is in .text */
  86. if (offset_ptr_rom >= (Elf32_Addr *)(uintptr_t)text_base &&
  87. offset_ptr_rom > last_offset) {
  88. /* Switch to the in-RAM version */
  89. offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom +
  90. gd->reloc_off);
  91. /* Check that the target points into .text */
  92. if (*offset_ptr_ram >= text_base &&
  93. *offset_ptr_ram <= text_base + size) {
  94. *offset_ptr_ram += gd->reloc_off;
  95. } else {
  96. debug(" %p: rom reloc %x, ram %p, value %x,"
  97. " limit %" PRIXPTR "\n", re_src,
  98. re_src->r_offset, offset_ptr_ram,
  99. *offset_ptr_ram,
  100. text_base + size);
  101. }
  102. } else {
  103. debug(" %p: rom reloc %x, last %p\n", re_src,
  104. re_src->r_offset, last_offset);
  105. }
  106. last_offset = offset_ptr_rom;
  107. } while (++re_src < re_end);
  108. }
  109. #endif
  110. /*
  111. * This function has more error checking than you might expect. Please see
  112. * this commit message for more information:
  113. * 62f7970a x86: Add error checking to x86 relocation code
  114. */
  115. int do_elf_reloc_fixups(void)
  116. {
  117. void *re_src = (void *)(&__rel_dyn_start);
  118. void *re_end = (void *)(&__rel_dyn_end);
  119. uint text_base;
  120. /* The size of the region of u-boot that runs out of RAM. */
  121. uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start;
  122. if (gd->flags & GD_FLG_SKIP_RELOC)
  123. return 0;
  124. if (re_src == re_end)
  125. panic("No relocation data");
  126. #ifdef CONFIG_SYS_TEXT_BASE
  127. text_base = CONFIG_SYS_TEXT_BASE;
  128. #else
  129. panic("No CONFIG_SYS_TEXT_BASE");
  130. #endif
  131. #if CONFIG_IS_ENABLED(X86_64)
  132. do_elf_reloc_fixups64(text_base, size, re_src, re_end);
  133. #else
  134. do_elf_reloc_fixups32(text_base, size, re_src, re_end);
  135. #endif
  136. return 0;
  137. }