From 49ffe168af44ac061d060300624ef2352a97fc3b Mon Sep 17 00:00:00 2001 From: Zide Chen Date: Mon, 2 Mar 2020 18:16:50 +0000 Subject: [PATCH] hv: fixup relocation delta for symbols belong to entry section This is to enable relocation for code32. - RIP relative addressing is available in x86-64 only so we manually add relocation delta to the target symbols to fixup code32. - both code32 and code64 need to load GDT hence both need to fixup GDT pointer. This patch declares separate GDT pointer cpu_primary64_gdt_ptr for code64 to avoid double fixup. - manually fixup cpu_primary64_gdt_ptr in code64, but not rely on relocate() to do that. Otherwise it's very confusing that symbols from same file could be fixed up externally by relocate() or self-relocated. - to make it clear, define a new symbol ld_entry_end representing the end of the boot code that needs manually fixup, and use this symbol in relocate() to filter out all symbols belong to the entry sections. Tracked-On: #4441 Reviewed-by: Fengwei Yin Signed-off-by: Zide Chen --- hypervisor/arch/x86/boot/cpu_primary.S | 47 ++++++++++++++++++++--- hypervisor/boot/include/reloc.h | 3 -- hypervisor/boot/reloc.c | 16 +++----- hypervisor/bsp/ld/link_ram.ld.in | 1 + hypervisor/include/arch/x86/boot/ld_sym.h | 1 + 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/hypervisor/arch/x86/boot/cpu_primary.S b/hypervisor/arch/x86/boot/cpu_primary.S index 4879c2bdd..a22364e98 100644 --- a/hypervisor/arch/x86/boot/cpu_primary.S +++ b/hypervisor/arch/x86/boot/cpu_primary.S @@ -122,9 +122,18 @@ mb2_header_end: .global cpu_primary_start_32 cpu_primary_start_32: + + /* + * Calculate the relocation delta between where we were compiled to run + * at and where we were actually loaded at. + */ + call 0f +0: pop %esi + sub $0b, %esi + /* save the MULTBOOT magic number & MBI */ - movl %eax, (boot_regs) - movl %ebx, (boot_regs+4) + movl %eax, boot_regs(%esi) + movl %ebx, (boot_regs+4)(%esi) /* Disable interrupts */ cli @@ -156,8 +165,16 @@ cpu_primary_start_32: movl $0x00000668, %eax mov %eax, %cr4 + /* fixup page table pointers with relocation delta */ + addl %esi, cpu_primary32_pdpt_addr(%esi) + addl %esi, (cpu_primary32_pdpt_addr+8)(%esi) + addl %esi, (cpu_primary32_pdpt_addr+16)(%esi) + addl %esi, (cpu_primary32_pdpt_addr+24)(%esi) + /* Set CR3 to PML4 table address */ movl $cpu_boot32_page_tables_start, %edi + addl %esi, %edi + addl %esi, (%edi) mov %edi, %cr3 /* Set LME bit in EFER */ @@ -178,11 +195,20 @@ cpu_primary_start_32: /* Load temportary GDT pointer value */ mov $cpu_primary32_gdt_ptr, %ebx + addl %esi, %ebx + addl %esi, 2(%ebx) lgdt (%ebx) /* Perform a long jump based to start executing in 64-bit mode */ + movl $jmpbuf_32, %eax + addl %esi, %eax + addl %esi, (%eax) + ljmp *(%eax) + +jmpbuf_32: + .long primary_start_long_mode /* 0x0008 = HOST_GDT_RING0_CODE_SEL */ - ljmp $0x0008, $primary_start_long_mode + .word 0x0008 .code64 .org 0x200 @@ -212,17 +238,22 @@ primary_start_long_mode: */ call relocate + call 0f +0: pop %rsi + sub $0b, %rsi /* relocation delta */ + /* Load temportary GDT pointer value */ - lea cpu_primary32_gdt_ptr(%rip), %rbx + lea cpu_primary64_gdt_ptr(%rip), %rbx + addq %rsi, 2(%rbx) lgdt (%ebx) /* Set the correct long jump address */ - lea jmpbuf(%rip), %rax + lea jmpbuf_64(%rip), %rax lea after(%rip), %rbx mov %rbx, (%rax) rex.w ljmp *(%rax) .data -jmpbuf: .quad 0 +jmpbuf_64: .quad 0 /* 0x0008 = HOST_GDT_RING0_CODE_SEL */ .word 0x0008 .text @@ -261,6 +292,10 @@ cpu_primary32_gdt_ptr: .short (cpu_primary32_gdt_end - cpu_primary32_gdt) - 1 .quad cpu_primary32_gdt +cpu_primary64_gdt_ptr: + .short (cpu_primary32_gdt_end - cpu_primary32_gdt) - 1 + .quad cpu_primary32_gdt + /* PML4, PDPT, and PD tables initialized to map first 4 GBytes of memory */ /*0x1000 = PAGE_SIZE*/ .align 0x1000 diff --git a/hypervisor/boot/include/reloc.h b/hypervisor/boot/include/reloc.h index b6c97c941..ace752727 100644 --- a/hypervisor/boot/include/reloc.h +++ b/hypervisor/boot/include/reloc.h @@ -13,7 +13,4 @@ extern uint64_t get_hv_image_base(void); /* external symbols that are helpful for relocation */ extern uint8_t _DYNAMIC[1]; -extern uint8_t cpu_primary_start_32; -extern uint8_t cpu_primary_start_64; - #endif /* RELOCATE_H */ diff --git a/hypervisor/boot/reloc.c b/hypervisor/boot/reloc.c index 6ad42c7bc..dea5a694d 100644 --- a/hypervisor/boot/reloc.c +++ b/hypervisor/boot/reloc.c @@ -64,7 +64,7 @@ void relocate(void) uint64_t rela_size = 0; uint64_t delta, entry_size = 0; uint64_t trampoline_end; - uint64_t primary_32_start, primary_32_end; + uint64_t primary_entry_end; uint64_t *addr; /* get the delta that needs to be patched */ @@ -94,8 +94,7 @@ void relocate(void) * absolute addresses */ trampoline_end = (uint64_t)(&ld_trampoline_end) - delta; - primary_32_start = (uint64_t)(&cpu_primary_start_32) - delta; - primary_32_end = (uint64_t)(&cpu_primary_start_64) - delta; + primary_entry_end = (uint64_t)(&ld_entry_end) - delta; rela_end = rela_start + rela_size; while (rela_start < rela_end) { @@ -104,22 +103,17 @@ void relocate(void) addr = (uint64_t *)(delta + entry->r_offset); /* - * we won't fixup any trampoline.S and cpu_primary.S here + * we won't fixup any symbols from trampoline.S or cpu_primary.S * for a number of reasons: * * - trampoline code itself takes another relocation, * so any entries for trampoline symbols can't be fixed up * through .rela sections - * - In cpu_primary.S, the 32 bits code doesn't need relocation * - Linker option "-z noreloc-overflow" could force R_X86_32 * to R_X86_64 in the relocation sections, which could make - * the fixed up code dirty. Even if relocation for 32 bits - * is needed in the future, it's recommended to do it - * explicitly in the assembly code to avoid confusion. + * the fixed up code dirty. */ - if ((entry->r_offset > trampoline_end) && - ((entry->r_offset < primary_32_start) || - (entry->r_offset > primary_32_end))) { + if ((entry->r_offset > trampoline_end) && (entry->r_offset > primary_entry_end)) { *addr += delta; } } diff --git a/hypervisor/bsp/ld/link_ram.ld.in b/hypervisor/bsp/ld/link_ram.ld.in index bd5f0488f..dd331f2ef 100644 --- a/hypervisor/bsp/ld/link_ram.ld.in +++ b/hypervisor/bsp/ld/link_ram.ld.in @@ -20,6 +20,7 @@ SECTIONS .entry : { KEEP(*(entry)) ; + ld_entry_end = . ; } > ram diff --git a/hypervisor/include/arch/x86/boot/ld_sym.h b/hypervisor/include/arch/x86/boot/ld_sym.h index f5941361b..ee5d637f5 100644 --- a/hypervisor/include/arch/x86/boot/ld_sym.h +++ b/hypervisor/include/arch/x86/boot/ld_sym.h @@ -10,6 +10,7 @@ extern uint8_t ld_text_end; extern uint8_t ld_bss_start; extern uint8_t ld_bss_end; +extern uint8_t ld_entry_end; extern const uint8_t ld_trampoline_load; extern uint8_t ld_trampoline_start; extern uint8_t ld_trampoline_end;