pgtable_64.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include <asm/e820/types.h>
  2. #include <asm/processor.h>
  3. #include "pgtable.h"
  4. #include "../string.h"
  5. /*
  6. * __force_order is used by special_insns.h asm code to force instruction
  7. * serialization.
  8. *
  9. * It is not referenced from the code, but GCC < 5 with -fPIE would fail
  10. * due to an undefined symbol. Define it to make these ancient GCCs work.
  11. */
  12. unsigned long __force_order;
  13. #define BIOS_START_MIN 0x20000U /* 128K, less than this is insane */
  14. #define BIOS_START_MAX 0x9f000U /* 640K, absolute maximum */
  15. struct paging_config {
  16. unsigned long trampoline_start;
  17. unsigned long l5_required;
  18. };
  19. /* Buffer to preserve trampoline memory */
  20. static char trampoline_save[TRAMPOLINE_32BIT_SIZE];
  21. /*
  22. * Trampoline address will be printed by extract_kernel() for debugging
  23. * purposes.
  24. *
  25. * Avoid putting the pointer into .bss as it will be cleared between
  26. * paging_prepare() and extract_kernel().
  27. */
  28. unsigned long *trampoline_32bit __section(.data);
  29. extern struct boot_params *boot_params;
  30. int cmdline_find_option_bool(const char *option);
  31. static unsigned long find_trampoline_placement(void)
  32. {
  33. unsigned long bios_start, ebda_start;
  34. unsigned long trampoline_start;
  35. struct boot_e820_entry *entry;
  36. int i;
  37. /*
  38. * Find a suitable spot for the trampoline.
  39. * This code is based on reserve_bios_regions().
  40. */
  41. ebda_start = *(unsigned short *)0x40e << 4;
  42. bios_start = *(unsigned short *)0x413 << 10;
  43. if (bios_start < BIOS_START_MIN || bios_start > BIOS_START_MAX)
  44. bios_start = BIOS_START_MAX;
  45. if (ebda_start > BIOS_START_MIN && ebda_start < bios_start)
  46. bios_start = ebda_start;
  47. bios_start = round_down(bios_start, PAGE_SIZE);
  48. /* Find the first usable memory region under bios_start. */
  49. for (i = boot_params->e820_entries - 1; i >= 0; i--) {
  50. entry = &boot_params->e820_table[i];
  51. /* Skip all entries above bios_start. */
  52. if (bios_start <= entry->addr)
  53. continue;
  54. /* Skip non-RAM entries. */
  55. if (entry->type != E820_TYPE_RAM)
  56. continue;
  57. /* Adjust bios_start to the end of the entry if needed. */
  58. if (bios_start > entry->addr + entry->size)
  59. bios_start = entry->addr + entry->size;
  60. /* Keep bios_start page-aligned. */
  61. bios_start = round_down(bios_start, PAGE_SIZE);
  62. /* Skip the entry if it's too small. */
  63. if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
  64. continue;
  65. break;
  66. }
  67. /* Place the trampoline just below the end of low memory */
  68. return bios_start - TRAMPOLINE_32BIT_SIZE;
  69. }
  70. struct paging_config paging_prepare(void *rmode)
  71. {
  72. struct paging_config paging_config = {};
  73. /* Initialize boot_params. Required for cmdline_find_option_bool(). */
  74. boot_params = rmode;
  75. /*
  76. * Check if LA57 is desired and supported.
  77. *
  78. * There are several parts to the check:
  79. * - if the kernel supports 5-level paging: CONFIG_X86_5LEVEL=y
  80. * - if user asked to disable 5-level paging: no5lvl in cmdline
  81. * - if the machine supports 5-level paging:
  82. * + CPUID leaf 7 is supported
  83. * + the leaf has the feature bit set
  84. *
  85. * That's substitute for boot_cpu_has() in early boot code.
  86. */
  87. if (IS_ENABLED(CONFIG_X86_5LEVEL) &&
  88. !cmdline_find_option_bool("no5lvl") &&
  89. native_cpuid_eax(0) >= 7 &&
  90. (native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31)))) {
  91. paging_config.l5_required = 1;
  92. }
  93. paging_config.trampoline_start = find_trampoline_placement();
  94. trampoline_32bit = (unsigned long *)paging_config.trampoline_start;
  95. /* Preserve trampoline memory */
  96. memcpy(trampoline_save, trampoline_32bit, TRAMPOLINE_32BIT_SIZE);
  97. /* Clear trampoline memory first */
  98. memset(trampoline_32bit, 0, TRAMPOLINE_32BIT_SIZE);
  99. /* Copy trampoline code in place */
  100. memcpy(trampoline_32bit + TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long),
  101. &trampoline_32bit_src, TRAMPOLINE_32BIT_CODE_SIZE);
  102. /*
  103. * The code below prepares page table in trampoline memory.
  104. *
  105. * The new page table will be used by trampoline code for switching
  106. * from 4- to 5-level paging or vice versa.
  107. *
  108. * If switching is not required, the page table is unused: trampoline
  109. * code wouldn't touch CR3.
  110. */
  111. /*
  112. * We are not going to use the page table in trampoline memory if we
  113. * are already in the desired paging mode.
  114. */
  115. if (paging_config.l5_required == !!(native_read_cr4() & X86_CR4_LA57))
  116. goto out;
  117. if (paging_config.l5_required) {
  118. /*
  119. * For 4- to 5-level paging transition, set up current CR3 as
  120. * the first and the only entry in a new top-level page table.
  121. */
  122. trampoline_32bit[TRAMPOLINE_32BIT_PGTABLE_OFFSET] = __native_read_cr3() | _PAGE_TABLE_NOENC;
  123. } else {
  124. unsigned long src;
  125. /*
  126. * For 5- to 4-level paging transition, copy page table pointed
  127. * by first entry in the current top-level page table as our
  128. * new top-level page table.
  129. *
  130. * We cannot just point to the page table from trampoline as it
  131. * may be above 4G.
  132. */
  133. src = *(unsigned long *)__native_read_cr3() & PAGE_MASK;
  134. memcpy(trampoline_32bit + TRAMPOLINE_32BIT_PGTABLE_OFFSET / sizeof(unsigned long),
  135. (void *)src, PAGE_SIZE);
  136. }
  137. out:
  138. return paging_config;
  139. }
  140. void cleanup_trampoline(void *pgtable)
  141. {
  142. void *trampoline_pgtable;
  143. trampoline_pgtable = trampoline_32bit + TRAMPOLINE_32BIT_PGTABLE_OFFSET / sizeof(unsigned long);
  144. /*
  145. * Move the top level page table out of trampoline memory,
  146. * if it's there.
  147. */
  148. if ((void *)__native_read_cr3() == trampoline_pgtable) {
  149. memcpy(pgtable, trampoline_pgtable, PAGE_SIZE);
  150. native_write_cr3((unsigned long)pgtable);
  151. }
  152. /* Restore trampoline memory */
  153. memcpy(trampoline_32bit, trampoline_save, TRAMPOLINE_32BIT_SIZE);
  154. }