You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

relocate.c 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #ifndef NORELOCATE
  2. #include "etherboot.h"
  3. #include "memsizes.h"
  4. /* by Eric Biederman */
  5. /* On some platforms etherboot is compiled as a shared library, and we use
  6. * the ELF pic support to make it relocateable. This works very nicely
  7. * for code, but since no one has implemented PIC data yet pointer
  8. * values in variables are a a problem. Global variables are a
  9. * pain but the return addresses on the stack are the worst. On these
  10. * platforms relocate_to will restart etherboot, to ensure the stack
  11. * is reinitialize and hopefully get the global variables
  12. * appropriately reinitialized as well.
  13. *
  14. */
  15. void relocate(void)
  16. {
  17. unsigned long addr, eaddr, size;
  18. unsigned i;
  19. /* Walk through the memory map and find the highest address
  20. * below 4GB that etherboot will fit into. Ensure etherboot
  21. * lies entirely within a range with A20=0. This means that
  22. * even if something screws up the state of the A20 line, the
  23. * etherboot code is still visible and we have a chance to
  24. * diagnose the problem.
  25. */
  26. /* First find the size of etherboot */
  27. addr = virt_to_phys(_text);
  28. eaddr = virt_to_phys(_end);
  29. size = (eaddr - addr + 0xf) & ~0xf;
  30. /* If the current etherboot is beyond MAX_ADDR pretend it is
  31. * at the lowest possible address.
  32. */
  33. if (eaddr > MAX_ADDR) {
  34. eaddr = 0;
  35. }
  36. for(i = 0; i < meminfo.map_count; i++) {
  37. unsigned long r_start, r_end;
  38. if (meminfo.map[i].type != E820_RAM) {
  39. continue;
  40. }
  41. if (meminfo.map[i].addr > MAX_ADDR) {
  42. continue;
  43. }
  44. if (meminfo.map[i].size > MAX_ADDR) {
  45. continue;
  46. }
  47. r_start = meminfo.map[i].addr;
  48. r_end = r_start + meminfo.map[i].size;
  49. /* Make the addresses 16 byte (128 bit) aligned */
  50. r_start = (r_start + 15) & ~15;
  51. r_end = r_end & ~15;
  52. if (r_end < r_start) {
  53. r_end = MAX_ADDR;
  54. }
  55. if (r_end < size) {
  56. /* Avoid overflow weirdness when r_end - size < 0 */
  57. continue;
  58. }
  59. /* Shrink the range down to use only even megabytes
  60. * (i.e. A20=0).
  61. */
  62. if ( r_end & 0x100000 ) {
  63. /* If r_end is in an odd megabyte, round down
  64. * r_end to the top of the next even megabyte.
  65. */
  66. r_end = r_end & ~0xfffff;
  67. } else if ( ( r_end - size ) & 0x100000 ) {
  68. /* If r_end is in an even megabyte, but the
  69. * start of Etherboot would be in an odd
  70. * megabyte, round down to the top of the next
  71. * even megabyte.
  72. */
  73. r_end = ( r_end - 0x100000 ) & ~0xfffff;
  74. }
  75. /* If we have rounded down r_end below r_ start, skip
  76. * this block.
  77. */
  78. if ( r_end < r_start ) {
  79. continue;
  80. }
  81. if (eaddr < r_end - size) {
  82. addr = r_end - size;
  83. eaddr = r_end;
  84. }
  85. }
  86. if (addr != virt_to_phys(_text)) {
  87. unsigned long old_addr = virt_to_phys(_text);
  88. printf("Relocating _text from: [%lx,%lx) to [%lx,%lx)\n",
  89. old_addr, virt_to_phys(_end),
  90. addr, eaddr);
  91. /* arch_relocate_to ( addr ) */
  92. cleanup();
  93. relocate_to(addr);
  94. /* arch_relocated_from ( addr ) */
  95. }
  96. }
  97. #endif /* NORELOCATE */