1 /*
2 * Copyright (C) 2018-2022 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <types.h>
8 #include <asm/mmu.h>
9 #include <asm/per_cpu.h>
10 #include <asm/trampoline.h>
11 #include <reloc.h>
12 #include <asm/boot/ld_sym.h>
13 #include <asm/e820.h>
14
15 static uint64_t trampoline_start16_paddr;
16
17 /*
18 * Because trampoline code is relocated in different way, if HV code
19 * accesses trampoline using relative addressing, it needs to take
20 * out the HV relocation delta
21 *
22 * This function is valid if:
23 * - The hpa of HV code is always higher than trampoline code
24 * - The HV code is always relocated to higher address, compared
25 * with CONFIG_HV_RAM_START
26 */
trampoline_relo_addr(const void * addr)27 static uint64_t trampoline_relo_addr(const void *addr)
28 {
29 return (uint64_t)addr - get_hv_image_delta();
30 }
31
read_trampoline_sym(const void * sym)32 uint64_t read_trampoline_sym(const void *sym)
33 {
34 uint64_t *hva = (uint64_t *)(hpa2hva(trampoline_start16_paddr) + trampoline_relo_addr(sym));
35 return *hva;
36 }
37
write_trampoline_sym(const void * sym,uint64_t val)38 void write_trampoline_sym(const void *sym, uint64_t val)
39 {
40 uint64_t *hva = (uint64_t *)(hpa2hva(trampoline_start16_paddr) + trampoline_relo_addr(sym));
41 *hva = val;
42 clflush(hva);
43 }
44
write_trampoline_stack_sym(uint16_t pcpu_id)45 void write_trampoline_stack_sym(uint16_t pcpu_id)
46 {
47 uint64_t *hva, stack_sym_addr;
48 hva = (uint64_t *)(hpa2hva(trampoline_start16_paddr) + trampoline_relo_addr(secondary_cpu_stack));
49
50 stack_sym_addr = (uint64_t)&per_cpu(stack, pcpu_id)[CONFIG_STACK_SIZE - 1];
51 stack_sym_addr &= ~(CPU_STACK_ALIGN - 1UL);
52 *hva = stack_sym_addr;
53
54 clflush(hva);
55 }
56
get_trampoline_start16_paddr(void)57 uint64_t get_trampoline_start16_paddr(void)
58 {
59 return trampoline_start16_paddr;
60 }
61
update_trampoline_code_refs(uint64_t dest_pa)62 static void update_trampoline_code_refs(uint64_t dest_pa)
63 {
64 void *ptr;
65 uint64_t val;
66 uint32_t i;
67
68 /*
69 * calculate the fixup CS:IP according to fixup target address
70 * dynamically.
71 *
72 * trampoline code starts in real mode,
73 * so the target addres is HPA
74 */
75 val = dest_pa + trampoline_relo_addr(&trampoline_fixup_target);
76
77 ptr = hpa2hva(dest_pa + trampoline_relo_addr(&trampoline_fixup_cs));
78 *(uint16_t *)(ptr) = (uint16_t)((val >> 4U) & 0xFFFFU);
79
80 ptr = hpa2hva(dest_pa + trampoline_relo_addr(&trampoline_fixup_ip));
81 *(uint16_t *)(ptr) = (uint16_t)(val & 0xfU);
82
83 /* Update temporary page tables */
84 ptr = hpa2hva(dest_pa + trampoline_relo_addr(&cpu_boot_page_tables_ptr));
85 *(uint32_t *)(ptr) += (uint32_t)dest_pa;
86
87 ptr = hpa2hva(dest_pa + trampoline_relo_addr(&cpu_boot_page_tables_start));
88 *(uint64_t *)(ptr) += dest_pa;
89
90 ptr = hpa2hva(dest_pa + trampoline_relo_addr(&trampoline_pdpt_addr));
91 for (i = 0U; i < 4U; i++) {
92 *(uint64_t *)(ptr + sizeof(uint64_t) * i) += dest_pa;
93 }
94
95 /* update the gdt base pointer with relocated offset */
96 ptr = hpa2hva(dest_pa + trampoline_relo_addr(&trampoline_gdt_ptr));
97 *(uint64_t *)(ptr + 2) += dest_pa;
98
99 /* update trampoline jump pointer with relocated offset */
100 ptr = hpa2hva(dest_pa + trampoline_relo_addr(&trampoline_start64_fixup));
101 *(uint32_t *)ptr += (uint32_t)dest_pa;
102
103 /* update trampoline's main entry pointer */
104 ptr = hpa2hva(dest_pa + trampoline_relo_addr(main_entry));
105 *(uint64_t *)ptr += get_hv_image_delta();
106 }
107
prepare_trampoline(void)108 uint64_t prepare_trampoline(void)
109 {
110 uint64_t trampline_size, trampoline_pa;
111
112 trampline_size = (uint64_t)(&ld_trampoline_end - &ld_trampoline_start);
113 trampoline_pa = e820_alloc_memory(trampline_size, MEM_1M);
114
115 pr_dbg("trampoline code: %lx trampline_size %x", trampoline_pa, trampline_size);
116
117 /* Copy segment for AP initialization code below 1MB */
118 (void)memcpy_s(hpa2hva(trampoline_pa), (size_t)trampline_size, &ld_trampoline_load,
119 (size_t)trampline_size);
120 update_trampoline_code_refs(trampoline_pa);
121
122 cpu_memory_barrier();
123 flush_cache_range(hpa2hva(trampoline_pa), trampline_size);
124
125 trampoline_start16_paddr = trampoline_pa;
126
127 return trampoline_pa;
128 }
129