root/arch/x86/boot/compressed/pgtable_64.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_trampoline_placement
  2. paging_prepare
  3. cleanup_trampoline

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

/* [<][>][^][v][top][bottom][index][help] */