x86/trampoline: Bypass compat mode in trampoline_start64() if not needed

Message ID 20240106010106.25772-1-kirill.shutemov@linux.intel.com
State New
Headers
Series x86/trampoline: Bypass compat mode in trampoline_start64() if not needed |

Commit Message

Kirill A. Shutemov Jan. 6, 2024, 1:01 a.m. UTC
  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 <kirill.shutemov@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Sean Christopherson <seanjc@google.com>
---
 arch/x86/realmode/rm/trampoline_64.S | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
  

Comments

kernel test robot Jan. 6, 2024, 10:17 p.m. UTC | #1
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/202401070610.WkJiWgWO-lkp@intel.com/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/202401070610.WkJiWgWO-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401070610.WkJiWgWO-lkp@intel.com/

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
  

Patch

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)