pgtable_64.c 6.1 KB

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