Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

relocate.c 2.8KB

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