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 <fengwei.yin@intel.com>
Signed-off-by: Zide Chen <zide.chen@intel.com>
This commit is contained in:
Zide Chen 2020-03-02 18:16:50 +00:00 committed by wenlingz
parent 2aa8c9e5d4
commit 49ffe168af
5 changed files with 48 additions and 20 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -20,6 +20,7 @@ SECTIONS
.entry :
{
KEEP(*(entry)) ;
ld_entry_end = . ;
} > ram

View File

@ -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;