0001
0002 #include "misc.h"
0003 #include <asm/e820/types.h>
0004 #include <asm/processor.h>
0005 #include "pgtable.h"
0006 #include "../string.h"
0007 #include "efi.h"
0008
0009 #define BIOS_START_MIN 0x20000U
0010 #define BIOS_START_MAX 0x9f000U
0011
0012 #ifdef CONFIG_X86_5LEVEL
0013
0014 unsigned int __section(".data") __pgtable_l5_enabled;
0015 unsigned int __section(".data") pgdir_shift = 39;
0016 unsigned int __section(".data") ptrs_per_p4d = 1;
0017 #endif
0018
0019 struct paging_config {
0020 unsigned long trampoline_start;
0021 unsigned long l5_required;
0022 };
0023
0024
0025 static char trampoline_save[TRAMPOLINE_32BIT_SIZE];
0026
0027
0028
0029
0030
0031
0032
0033
0034 unsigned long *trampoline_32bit __section(".data");
0035
0036 extern struct boot_params *boot_params;
0037 int cmdline_find_option_bool(const char *option);
0038
0039 static unsigned long find_trampoline_placement(void)
0040 {
0041 unsigned long bios_start = 0, ebda_start = 0;
0042 struct boot_e820_entry *entry;
0043 char *signature;
0044 int i;
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 signature = (char *)&boot_params->efi_info.efi_loader_signature;
0058 if (strncmp(signature, EFI32_LOADER_SIGNATURE, 4) &&
0059 strncmp(signature, EFI64_LOADER_SIGNATURE, 4)) {
0060 ebda_start = *(unsigned short *)0x40e << 4;
0061 bios_start = *(unsigned short *)0x413 << 10;
0062 }
0063
0064 if (bios_start < BIOS_START_MIN || bios_start > BIOS_START_MAX)
0065 bios_start = BIOS_START_MAX;
0066
0067 if (ebda_start > BIOS_START_MIN && ebda_start < bios_start)
0068 bios_start = ebda_start;
0069
0070 bios_start = round_down(bios_start, PAGE_SIZE);
0071
0072
0073 for (i = boot_params->e820_entries - 1; i >= 0; i--) {
0074 unsigned long new = bios_start;
0075
0076 entry = &boot_params->e820_table[i];
0077
0078
0079 if (bios_start <= entry->addr)
0080 continue;
0081
0082
0083 if (entry->type != E820_TYPE_RAM)
0084 continue;
0085
0086
0087 if (bios_start > entry->addr + entry->size)
0088 new = entry->addr + entry->size;
0089
0090
0091 new = round_down(new, PAGE_SIZE);
0092
0093
0094 if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
0095 continue;
0096
0097
0098 if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
0099 break;
0100
0101 bios_start = new;
0102 break;
0103 }
0104
0105
0106 return bios_start - TRAMPOLINE_32BIT_SIZE;
0107 }
0108
0109 struct paging_config paging_prepare(void *rmode)
0110 {
0111 struct paging_config paging_config = {};
0112
0113
0114 boot_params = rmode;
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128 if (IS_ENABLED(CONFIG_X86_5LEVEL) &&
0129 !cmdline_find_option_bool("no5lvl") &&
0130 native_cpuid_eax(0) >= 7 &&
0131 (native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31)))) {
0132 paging_config.l5_required = 1;
0133 }
0134
0135 paging_config.trampoline_start = find_trampoline_placement();
0136
0137 trampoline_32bit = (unsigned long *)paging_config.trampoline_start;
0138
0139
0140 memcpy(trampoline_save, trampoline_32bit, TRAMPOLINE_32BIT_SIZE);
0141
0142
0143 memset(trampoline_32bit, 0, TRAMPOLINE_32BIT_SIZE);
0144
0145
0146 memcpy(trampoline_32bit + TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long),
0147 &trampoline_32bit_src, TRAMPOLINE_32BIT_CODE_SIZE);
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 if (paging_config.l5_required == !!(native_read_cr4() & X86_CR4_LA57))
0164 goto out;
0165
0166 if (paging_config.l5_required) {
0167
0168
0169
0170
0171 trampoline_32bit[TRAMPOLINE_32BIT_PGTABLE_OFFSET] = __native_read_cr3() | _PAGE_TABLE_NOENC;
0172 } else {
0173 unsigned long src;
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 src = *(unsigned long *)__native_read_cr3() & PAGE_MASK;
0184 memcpy(trampoline_32bit + TRAMPOLINE_32BIT_PGTABLE_OFFSET / sizeof(unsigned long),
0185 (void *)src, PAGE_SIZE);
0186 }
0187
0188 out:
0189 return paging_config;
0190 }
0191
0192 void cleanup_trampoline(void *pgtable)
0193 {
0194 void *trampoline_pgtable;
0195
0196 trampoline_pgtable = trampoline_32bit + TRAMPOLINE_32BIT_PGTABLE_OFFSET / sizeof(unsigned long);
0197
0198
0199
0200
0201
0202 if ((void *)__native_read_cr3() == trampoline_pgtable) {
0203 memcpy(pgtable, trampoline_pgtable, PAGE_SIZE);
0204 native_write_cr3((unsigned long)pgtable);
0205 }
0206
0207
0208 memcpy(trampoline_32bit, trampoline_save, TRAMPOLINE_32BIT_SIZE);
0209
0210
0211 #ifdef CONFIG_X86_5LEVEL
0212 if (__read_cr4() & X86_CR4_LA57) {
0213 __pgtable_l5_enabled = 1;
0214 pgdir_shift = 48;
0215 ptrs_per_p4d = 512;
0216 }
0217 #endif
0218 }