pgtable_64.c 6.0 KB

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