[v3,2/2] x86/head64: Replace pointer fixups with RIP_RELATIVE_ADDR()
Commit Message
Now that we have RIP_RELATIVE_ADDR(), we can replace the "fixup_*()"
family of functions in head64.c with the new macro for cleaner code.
Signed-off-by: Kevin Loughlin <kevinloughlin@google.com>
---
arch/x86/kernel/head64.c | 63 +++++++++++++++-------------------------
1 file changed, 24 insertions(+), 39 deletions(-)
Comments
On Tue, Jan 30, 2024 at 10:08:45PM +0000, Kevin Loughlin wrote:
> @@ -594,15 +579,15 @@ static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler)
> /* This runs while still in the direct mapping */
> static void __head startup_64_load_idt(unsigned long physbase)
> {
> - struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase);
> - gate_desc *idt = fixup_pointer(bringup_idt_table, physbase);
> + struct desc_ptr *desc = RIP_RELATIVE_ADDR(bringup_idt_descr);
> + gate_desc *idt = RIP_RELATIVE_ADDR(bringup_idt_table);
>
>
> if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
> void *handler;
>
> /* VMM Communication Exception */
> - handler = fixup_pointer(vc_no_ghcb, physbase);
> + handler = RIP_RELATIVE_ADDR(vc_no_ghcb);
> set_bringup_idt_handler(idt, X86_TRAP_VC, handler);
> }
>
Looks like you removed all physbase users in the function. No need to pass
it to it.
> @@ -629,7 +614,7 @@ void early_setup_idt(void)
> void __head startup_64_setup_env(unsigned long physbase)
> {
> /* Load GDT */
> - startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase);
> + startup_gdt_descr.address = (unsigned long)RIP_RELATIVE_ADDR(startup_gdt);
> native_load_gdt(&startup_gdt_descr);
>
> /* New GDT is live - reload data segment registers */
With startup_64_load_idt() fixed, no users for physbase in this function
either.
On 1/30/24 16:08, Kevin Loughlin wrote:
> Now that we have RIP_RELATIVE_ADDR(), we can replace the "fixup_*()"
> family of functions in head64.c with the new macro for cleaner code.
If this series is purely for backporting, this specific patch isn't
needed, right? Since this all works today with clang?
Thanks,
Tom
>
> Signed-off-by: Kevin Loughlin <kevinloughlin@google.com>
> ---
> arch/x86/kernel/head64.c | 63 +++++++++++++++-------------------------
> 1 file changed, 24 insertions(+), 39 deletions(-)
>
> diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
> index d159239997f4..e782149eefc4 100644
> --- a/arch/x86/kernel/head64.c
> +++ b/arch/x86/kernel/head64.c
> @@ -85,23 +85,8 @@ static struct desc_ptr startup_gdt_descr __initdata = {
> .address = 0,
> };
>
> -static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
> -{
> - return ptr - (void *)_text + (void *)physaddr;
> -}
> -
> -static unsigned long __head *fixup_long(void *ptr, unsigned long physaddr)
> -{
> - return fixup_pointer(ptr, physaddr);
> -}
> -
> #ifdef CONFIG_X86_5LEVEL
> -static unsigned int __head *fixup_int(void *ptr, unsigned long physaddr)
> -{
> - return fixup_pointer(ptr, physaddr);
> -}
> -
> -static bool __head check_la57_support(unsigned long physaddr)
> +static bool __head check_la57_support(void)
> {
> /*
> * 5-level paging is detected and enabled at kernel decompression
> @@ -110,17 +95,17 @@ static bool __head check_la57_support(unsigned long physaddr)
> if (!(native_read_cr4() & X86_CR4_LA57))
> return false;
>
> - *fixup_int(&__pgtable_l5_enabled, physaddr) = 1;
> - *fixup_int(&pgdir_shift, physaddr) = 48;
> - *fixup_int(&ptrs_per_p4d, physaddr) = 512;
> - *fixup_long(&page_offset_base, physaddr) = __PAGE_OFFSET_BASE_L5;
> - *fixup_long(&vmalloc_base, physaddr) = __VMALLOC_BASE_L5;
> - *fixup_long(&vmemmap_base, physaddr) = __VMEMMAP_BASE_L5;
> + *((unsigned int *)RIP_RELATIVE_ADDR(__pgtable_l5_enabled)) = 1;
> + *((unsigned int *)RIP_RELATIVE_ADDR(pgdir_shift)) = 48;
> + *((unsigned int *)RIP_RELATIVE_ADDR(ptrs_per_p4d)) = 512;
> + *((unsigned long *)RIP_RELATIVE_ADDR(page_offset_base)) = __PAGE_OFFSET_BASE_L5;
> + *((unsigned long *)RIP_RELATIVE_ADDR(vmalloc_base)) = __VMALLOC_BASE_L5;
> + *((unsigned long *)RIP_RELATIVE_ADDR(vmemmap_base)) = __VMEMMAP_BASE_L5;
>
> return true;
> }
> #else
> -static bool __head check_la57_support(unsigned long physaddr)
> +static bool __head check_la57_support(void)
> {
> return false;
> }
> @@ -175,8 +160,8 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv
> * Code in __startup_64() can be relocated during execution, but the compiler
> * doesn't have to generate PC-relative relocations when accessing globals from
> * that function. Clang actually does not generate them, which leads to
> - * boot-time crashes. To work around this problem, every global pointer must
> - * be adjusted using fixup_pointer() or RIP_RELATIVE_ADDR().
> + * boot-time crashes. To work around this problem, every global variable access
> + * must be adjusted using RIP_RELATIVE_ADDR().
> */
> unsigned long __head __startup_64(unsigned long physaddr,
> struct boot_params *bp)
> @@ -194,7 +179,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
> int i;
> unsigned int *next_pgt_ptr;
>
> - la57 = check_la57_support(physaddr);
> + la57 = check_la57_support();
>
> /* Is the address too large? */
> if (physaddr >> MAX_PHYSMEM_BITS)
> @@ -215,7 +200,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
>
> /* Fixup the physical addresses in the page table */
>
> - pgd = fixup_pointer(early_top_pgt, physaddr);
> + pgd = RIP_RELATIVE_ADDR(early_top_pgt);
> p = pgd + pgd_index(__START_KERNEL_map);
> if (la57)
> *p = (unsigned long)level4_kernel_pgt;
> @@ -224,15 +209,15 @@ unsigned long __head __startup_64(unsigned long physaddr,
> *p += _PAGE_TABLE_NOENC - __START_KERNEL_map + load_delta;
>
> if (la57) {
> - p4d = fixup_pointer(level4_kernel_pgt, physaddr);
> + p4d = RIP_RELATIVE_ADDR(level4_kernel_pgt);
> p4d[511] += load_delta;
> }
>
> - pud = fixup_pointer(level3_kernel_pgt, physaddr);
> + pud = RIP_RELATIVE_ADDR(level3_kernel_pgt);
> pud[510] += load_delta;
> pud[511] += load_delta;
>
> - pmd = fixup_pointer(level2_fixmap_pgt, physaddr);
> + pmd = RIP_RELATIVE_ADDR(level2_fixmap_pgt);
> for (i = FIXMAP_PMD_TOP; i > FIXMAP_PMD_TOP - FIXMAP_PMD_NUM; i--)
> pmd[i] += load_delta;
>
> @@ -243,8 +228,8 @@ unsigned long __head __startup_64(unsigned long physaddr,
> * it avoids problems around wraparound.
> */
>
> - next_pgt_ptr = fixup_pointer(&next_early_pgt, physaddr);
> - early_dynamic_pgts_ptr = fixup_pointer(early_dynamic_pgts, physaddr);
> + early_dynamic_pgts_ptr = RIP_RELATIVE_ADDR(early_dynamic_pgts);
> + next_pgt_ptr = RIP_RELATIVE_ADDR(next_early_pgt);
> pud = (pudval_t *) early_dynamic_pgts_ptr[(*next_pgt_ptr)++];
> pmd = (pmdval_t *) early_dynamic_pgts_ptr[(*next_pgt_ptr)++];
>
> @@ -272,7 +257,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
>
> pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
> /* Filter out unsupported __PAGE_KERNEL_* bits: */
> - mask_ptr = fixup_pointer(&__supported_pte_mask, physaddr);
> + mask_ptr = RIP_RELATIVE_ADDR(__supported_pte_mask);
> pmd_entry &= *mask_ptr;
> pmd_entry += sme_me_mask_fixed_up;
> pmd_entry += physaddr;
> @@ -299,7 +284,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
> * error, causing the BIOS to halt the system.
> */
>
> - pmd = fixup_pointer(level2_kernel_pgt, physaddr);
> + pmd = RIP_RELATIVE_ADDR(level2_kernel_pgt);
>
> /* invalidate pages before the kernel image */
> for (i = 0; i < pmd_index((unsigned long)_text); i++)
> @@ -318,7 +303,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
> * Fixup phys_base - remove the memory encryption mask to obtain
> * the true physical address.
> */
> - *fixup_long(&phys_base, physaddr) += load_delta - sme_me_mask_fixed_up;
> + *((unsigned long *)RIP_RELATIVE_ADDR(phys_base)) += load_delta - sme_me_mask_fixed_up;
>
> return sme_postprocess_startup(bp, pmd);
> }
> @@ -594,15 +579,15 @@ static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler)
> /* This runs while still in the direct mapping */
> static void __head startup_64_load_idt(unsigned long physbase)
> {
> - struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase);
> - gate_desc *idt = fixup_pointer(bringup_idt_table, physbase);
> + struct desc_ptr *desc = RIP_RELATIVE_ADDR(bringup_idt_descr);
> + gate_desc *idt = RIP_RELATIVE_ADDR(bringup_idt_table);
>
>
> if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
> void *handler;
>
> /* VMM Communication Exception */
> - handler = fixup_pointer(vc_no_ghcb, physbase);
> + handler = RIP_RELATIVE_ADDR(vc_no_ghcb);
> set_bringup_idt_handler(idt, X86_TRAP_VC, handler);
> }
>
> @@ -629,7 +614,7 @@ void early_setup_idt(void)
> void __head startup_64_setup_env(unsigned long physbase)
> {
> /* Load GDT */
> - startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase);
> + startup_gdt_descr.address = (unsigned long)RIP_RELATIVE_ADDR(startup_gdt);
> native_load_gdt(&startup_gdt_descr);
>
> /* New GDT is live - reload data segment registers */
On Wed, Jan 31, 2024 at 09:30:10AM -0600, Tom Lendacky wrote:
> On 1/30/24 16:08, Kevin Loughlin wrote:
> > Now that we have RIP_RELATIVE_ADDR(), we can replace the "fixup_*()"
> > family of functions in head64.c with the new macro for cleaner code.
>
> If this series is purely for backporting, this specific patch isn't needed,
> right? Since this all works today with clang?
That's true. However, temporary things often end up becoming permanent :/
On Wed, Jan 31, 2024 at 12:24 AM Kirill A. Shutemov
<kirill.shutemov@linux.intel.com> wrote:
>
> On Tue, Jan 30, 2024 at 10:08:45PM +0000, Kevin Loughlin wrote:
> > @@ -594,15 +579,15 @@ static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler)
> > /* This runs while still in the direct mapping */
> > static void __head startup_64_load_idt(unsigned long physbase)
> > {
> > - struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase);
> > - gate_desc *idt = fixup_pointer(bringup_idt_table, physbase);
> > + struct desc_ptr *desc = RIP_RELATIVE_ADDR(bringup_idt_descr);
> > + gate_desc *idt = RIP_RELATIVE_ADDR(bringup_idt_table);
> >
> >
> > if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
> > void *handler;
> >
> > /* VMM Communication Exception */
> > - handler = fixup_pointer(vc_no_ghcb, physbase);
> > + handler = RIP_RELATIVE_ADDR(vc_no_ghcb);
> > set_bringup_idt_handler(idt, X86_TRAP_VC, handler);
> > }
> >
>
> Looks like you removed all physbase users in the function. No need to pass
> it to it.
Thanks, will fix.
>
> > @@ -629,7 +614,7 @@ void early_setup_idt(void)
> > void __head startup_64_setup_env(unsigned long physbase)
> > {
> > /* Load GDT */
> > - startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase);
> > + startup_gdt_descr.address = (unsigned long)RIP_RELATIVE_ADDR(startup_gdt);
> > native_load_gdt(&startup_gdt_descr);
> >
> > /* New GDT is live - reload data segment registers */
>
> With startup_64_load_idt() fixed, no users for physbase in this function
> either.
Ditto.
@@ -85,23 +85,8 @@ static struct desc_ptr startup_gdt_descr __initdata = {
.address = 0,
};
-static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
-{
- return ptr - (void *)_text + (void *)physaddr;
-}
-
-static unsigned long __head *fixup_long(void *ptr, unsigned long physaddr)
-{
- return fixup_pointer(ptr, physaddr);
-}
-
#ifdef CONFIG_X86_5LEVEL
-static unsigned int __head *fixup_int(void *ptr, unsigned long physaddr)
-{
- return fixup_pointer(ptr, physaddr);
-}
-
-static bool __head check_la57_support(unsigned long physaddr)
+static bool __head check_la57_support(void)
{
/*
* 5-level paging is detected and enabled at kernel decompression
@@ -110,17 +95,17 @@ static bool __head check_la57_support(unsigned long physaddr)
if (!(native_read_cr4() & X86_CR4_LA57))
return false;
- *fixup_int(&__pgtable_l5_enabled, physaddr) = 1;
- *fixup_int(&pgdir_shift, physaddr) = 48;
- *fixup_int(&ptrs_per_p4d, physaddr) = 512;
- *fixup_long(&page_offset_base, physaddr) = __PAGE_OFFSET_BASE_L5;
- *fixup_long(&vmalloc_base, physaddr) = __VMALLOC_BASE_L5;
- *fixup_long(&vmemmap_base, physaddr) = __VMEMMAP_BASE_L5;
+ *((unsigned int *)RIP_RELATIVE_ADDR(__pgtable_l5_enabled)) = 1;
+ *((unsigned int *)RIP_RELATIVE_ADDR(pgdir_shift)) = 48;
+ *((unsigned int *)RIP_RELATIVE_ADDR(ptrs_per_p4d)) = 512;
+ *((unsigned long *)RIP_RELATIVE_ADDR(page_offset_base)) = __PAGE_OFFSET_BASE_L5;
+ *((unsigned long *)RIP_RELATIVE_ADDR(vmalloc_base)) = __VMALLOC_BASE_L5;
+ *((unsigned long *)RIP_RELATIVE_ADDR(vmemmap_base)) = __VMEMMAP_BASE_L5;
return true;
}
#else
-static bool __head check_la57_support(unsigned long physaddr)
+static bool __head check_la57_support(void)
{
return false;
}
@@ -175,8 +160,8 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv
* Code in __startup_64() can be relocated during execution, but the compiler
* doesn't have to generate PC-relative relocations when accessing globals from
* that function. Clang actually does not generate them, which leads to
- * boot-time crashes. To work around this problem, every global pointer must
- * be adjusted using fixup_pointer() or RIP_RELATIVE_ADDR().
+ * boot-time crashes. To work around this problem, every global variable access
+ * must be adjusted using RIP_RELATIVE_ADDR().
*/
unsigned long __head __startup_64(unsigned long physaddr,
struct boot_params *bp)
@@ -194,7 +179,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
int i;
unsigned int *next_pgt_ptr;
- la57 = check_la57_support(physaddr);
+ la57 = check_la57_support();
/* Is the address too large? */
if (physaddr >> MAX_PHYSMEM_BITS)
@@ -215,7 +200,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
/* Fixup the physical addresses in the page table */
- pgd = fixup_pointer(early_top_pgt, physaddr);
+ pgd = RIP_RELATIVE_ADDR(early_top_pgt);
p = pgd + pgd_index(__START_KERNEL_map);
if (la57)
*p = (unsigned long)level4_kernel_pgt;
@@ -224,15 +209,15 @@ unsigned long __head __startup_64(unsigned long physaddr,
*p += _PAGE_TABLE_NOENC - __START_KERNEL_map + load_delta;
if (la57) {
- p4d = fixup_pointer(level4_kernel_pgt, physaddr);
+ p4d = RIP_RELATIVE_ADDR(level4_kernel_pgt);
p4d[511] += load_delta;
}
- pud = fixup_pointer(level3_kernel_pgt, physaddr);
+ pud = RIP_RELATIVE_ADDR(level3_kernel_pgt);
pud[510] += load_delta;
pud[511] += load_delta;
- pmd = fixup_pointer(level2_fixmap_pgt, physaddr);
+ pmd = RIP_RELATIVE_ADDR(level2_fixmap_pgt);
for (i = FIXMAP_PMD_TOP; i > FIXMAP_PMD_TOP - FIXMAP_PMD_NUM; i--)
pmd[i] += load_delta;
@@ -243,8 +228,8 @@ unsigned long __head __startup_64(unsigned long physaddr,
* it avoids problems around wraparound.
*/
- next_pgt_ptr = fixup_pointer(&next_early_pgt, physaddr);
- early_dynamic_pgts_ptr = fixup_pointer(early_dynamic_pgts, physaddr);
+ early_dynamic_pgts_ptr = RIP_RELATIVE_ADDR(early_dynamic_pgts);
+ next_pgt_ptr = RIP_RELATIVE_ADDR(next_early_pgt);
pud = (pudval_t *) early_dynamic_pgts_ptr[(*next_pgt_ptr)++];
pmd = (pmdval_t *) early_dynamic_pgts_ptr[(*next_pgt_ptr)++];
@@ -272,7 +257,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
/* Filter out unsupported __PAGE_KERNEL_* bits: */
- mask_ptr = fixup_pointer(&__supported_pte_mask, physaddr);
+ mask_ptr = RIP_RELATIVE_ADDR(__supported_pte_mask);
pmd_entry &= *mask_ptr;
pmd_entry += sme_me_mask_fixed_up;
pmd_entry += physaddr;
@@ -299,7 +284,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
* error, causing the BIOS to halt the system.
*/
- pmd = fixup_pointer(level2_kernel_pgt, physaddr);
+ pmd = RIP_RELATIVE_ADDR(level2_kernel_pgt);
/* invalidate pages before the kernel image */
for (i = 0; i < pmd_index((unsigned long)_text); i++)
@@ -318,7 +303,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
* Fixup phys_base - remove the memory encryption mask to obtain
* the true physical address.
*/
- *fixup_long(&phys_base, physaddr) += load_delta - sme_me_mask_fixed_up;
+ *((unsigned long *)RIP_RELATIVE_ADDR(phys_base)) += load_delta - sme_me_mask_fixed_up;
return sme_postprocess_startup(bp, pmd);
}
@@ -594,15 +579,15 @@ static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler)
/* This runs while still in the direct mapping */
static void __head startup_64_load_idt(unsigned long physbase)
{
- struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase);
- gate_desc *idt = fixup_pointer(bringup_idt_table, physbase);
+ struct desc_ptr *desc = RIP_RELATIVE_ADDR(bringup_idt_descr);
+ gate_desc *idt = RIP_RELATIVE_ADDR(bringup_idt_table);
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
void *handler;
/* VMM Communication Exception */
- handler = fixup_pointer(vc_no_ghcb, physbase);
+ handler = RIP_RELATIVE_ADDR(vc_no_ghcb);
set_bringup_idt_handler(idt, X86_TRAP_VC, handler);
}
@@ -629,7 +614,7 @@ void early_setup_idt(void)
void __head startup_64_setup_env(unsigned long physbase)
{
/* Load GDT */
- startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase);
+ startup_gdt_descr.address = (unsigned long)RIP_RELATIVE_ADDR(startup_gdt);
native_load_gdt(&startup_gdt_descr);
/* New GDT is live - reload data segment registers */