The trampoline_start64() vector is used when a secondary CPU starts in
64-bit mode. The current implementation directly enters compatibility
mode. It is necessary to disable paging and re-enable it in the correct
paging mode: either 4- or 5-level, depending on the configuration.
The X86S[1] ISA does not support compatibility mode in ring 0, and
paging cannot be disabled.
The trampoline_start64() function is reworked to only enter compatibility
mode if it is necessary to change the paging mode. If the CPU is already
in the desired paging mode, it will proceed in long mode.
This change will allow a secondary CPU to boot on an X86S machine as
long as the CPU is already in the correct paging mode.
In the future, there will be a mechanism to switch between paging modes
without disabling paging.
[1] https://www.intel.com/content/www/us/en/developer/articles/technical/envisioning-future-simplified-architecture.html
Signed-off-by: Kirill A. Shutemov <[email protected]>
Reviewed-by: Andi Kleen <[email protected]>
Cc: Sean Christopherson <[email protected]>
---
arch/x86/realmode/rm/trampoline_64.S | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index c9f76fae902e..70c6dff658e6 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -220,6 +220,33 @@ SYM_CODE_START(trampoline_start64)
lidt tr_idt(%rip)
lgdt tr_gdt64(%rip)
+ /* Check if paging mode has to be changed */
+ movq %cr4, %rax
+ xorq pa_tr_cr4, %rax
+ andq $X86_CR4_LA57, %rax
+ jnz .L_switch_paging
+
+ /* Paging mode is correct proceed in 64-bit mode */
+
+ LOCK_AND_LOAD_REALMODE_ESP lock_pa=1
+
+ movw $__KERNEL_DS, %dx
+ movl %edx, %ss
+ addl $pa_real_mode_base, %esp
+ movl %edx, %ds
+ movl %edx, %es
+ movl %edx, %fs
+ movl %edx, %gs
+
+ movl $pa_trampoline_pgd, %eax
+ movq %rax, %cr3
+
+ jmpq *tr_start(%rip)
+.L_switch_paging:
+ /*
+ * To switch between 4- and 5-level paging modes, it is necessary
+ * to disable paging. This must be done in the compatibility mode.
+ */
ljmpl *tr_compat(%rip)
SYM_CODE_END(trampoline_start64)
--
2.41.0
Hi Kirill,
kernel test robot noticed the following build errors:
[auto build test ERROR on tip/master]
[also build test ERROR on tip/x86/core tip/auto-latest linus/master v6.7-rc8 next-20240105]
[cannot apply to bp/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Kirill-A-Shutemov/x86-trampoline-Bypass-compat-mode-in-trampoline_start64-if-not-needed/20240106-090311
base: tip/master
patch link: https://lore.kernel.org/r/20240106010106.25772-1-kirill.shutemov%40linux.intel.com
patch subject: [PATCH] x86/trampoline: Bypass compat mode in trampoline_start64() if not needed
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20240107/[email protected]/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240107/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
as: arch/x86/realmode/rm/trampoline_64.o: unsupported relocation type: 0x185
arch/x86/realmode/rm/trampoline_64.S: Assembler messages:
>> arch/x86/realmode/rm/trampoline_64.S:225: Error: cannot represent relocation type BFD_RELOC_X86_64_32S
as: arch/x86/realmode/rm/trampoline_64.o: unsupported relocation type: 0x185
arch/x86/realmode/rm/trampoline_64.S:231: Error: cannot represent relocation type BFD_RELOC_X86_64_32S
vim +225 arch/x86/realmode/rm/trampoline_64.S
211
212 SYM_CODE_START(trampoline_start64)
213 /*
214 * APs start here on a direct transfer from 64-bit BIOS with identity
215 * mapped page tables. Load the kernel's GDT in order to gear down to
216 * 32-bit mode (to handle 4-level vs. 5-level paging), and to (re)load
217 * segment registers. Load the zero IDT so any fault triggers a
218 * shutdown instead of jumping back into BIOS.
219 */
220 lidt tr_idt(%rip)
221 lgdt tr_gdt64(%rip)
222
223 /* Check if paging mode has to be changed */
224 movq %cr4, %rax
> 225 xorq pa_tr_cr4, %rax
226 andq $X86_CR4_LA57, %rax
227 jnz .L_switch_paging
228
229 /* Paging mode is correct proceed in 64-bit mode */
230
231 LOCK_AND_LOAD_REALMODE_ESP lock_pa=1
232
233 movw $__KERNEL_DS, %dx
234 movl %edx, %ss
235 addl $pa_real_mode_base, %esp
236 movl %edx, %ds
237 movl %edx, %es
238 movl %edx, %fs
239 movl %edx, %gs
240
241 movl $pa_trampoline_pgd, %eax
242 movq %rax, %cr3
243
244 jmpq *tr_start(%rip)
245 .L_switch_paging:
246 /*
247 * To switch between 4- and 5-level paging modes, it is necessary
248 * to disable paging. This must be done in the compatibility mode.
249 */
250 ljmpl *tr_compat(%rip)
251 SYM_CODE_END(trampoline_start64)
252
253 .section ".rodata","a"
254 # Duplicate the global descriptor table
255 # so the kernel can live anywhere
256 .balign 16
257 SYM_DATA_START(tr_gdt)
258 .short tr_gdt_end - tr_gdt - 1 # gdt limit
259 .long pa_tr_gdt
260 .short 0
261 .quad 0x00cf9b000000ffff # __KERNEL32_CS
262 .quad 0x00af9b000000ffff # __KERNEL_CS
263 .quad 0x00cf93000000ffff # __KERNEL_DS
264 SYM_DATA_END_LABEL(tr_gdt, SYM_L_LOCAL, tr_gdt_end)
265
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki