xref: /haiku/src/system/boot/platform/efi/arch/x86_64/arch_smp_64.cpp (revision 46b7da1f4f40f7157d74fc7fb26ff9ec7f2416f2)
1 /*
2  * Copyright 2021-2022 Haiku, Inc. All rights reserved.
3  * Released under the terms of the MIT License.
4  *
5  * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
6  * Copyright 2004-2010, Axel Dörfler, axeld@pinc-software.de.
7  * Distributed under the terms of the MIT License.
8  *
9  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
10  * Distributed under the terms of the NewOS License.
11  */
12 
13 
14 #include "arch_smp.h"
15 
16 #include <boot/stage2.h>
17 
18 
19 //#define TRACE_SMP
20 #ifdef TRACE_SMP
21 #	define TRACE(x...) dprintf(x)
22 #else
23 #	define TRACE(x...) ;
24 #endif
25 
26 
27 extern "C" void long_smp_trampoline(void);
28 extern "C" void long_smp_trampoline_args(void);
29 extern "C" void long_smp_trampoline_end(void);
30 extern "C" uint64 gLongGDTR;
31 
32 struct gdtr {
33     uint16 limit;
34     uint32 base;
35     unsigned char null[8];
36     unsigned char code[8];
37     unsigned char data[8];
38 } __attribute__((packed));
39 
40 // Arguments passed to the SMP trampoline.
41 struct long_trampoline_args {
42 	uint32 trampoline;        // Trampoline address
43 	uint32 gdt32;             // 32-bit GDTR
44 	uint32 pml4;              // 64-bit PML4
45 	uint32 gdt64;             // 64-bit GDTR
46 	uint64 kernel_entry;      // Kernel entry point
47 	uint64 kernel_args;       // Kernel arguments
48 	uint64 current_cpu;       // CPU number
49 	uint64 stack_top;         // Kernel stack
50 	volatile uint64 sentinel; // Sentinel, AP sets to 0 when finished
51 
52 	// smp_boot_other_cpus puts the GDTR here.
53 	struct gdtr gdtr;
54 };
55 
56 
57 void
copy_trampoline_code(uint64 trampolineCode,uint64 trampolineStack)58 copy_trampoline_code(uint64 trampolineCode, uint64 trampolineStack)
59 {
60 	TRACE("copying the trampoline code to %p from %p\n", (char*)trampolineCode, (const void*)&long_smp_trampoline);
61 	TRACE("size of trampoline code = %" PRIu64 " bytes\n", (uint64)&long_smp_trampoline_end - (uint64)&long_smp_trampoline);
62 	memcpy((char *)trampolineCode, (const void*)&long_smp_trampoline,
63 		(uint64)&long_smp_trampoline_end - (uint64)&long_smp_trampoline);
64 }
65 
66 
67 void
prepare_trampoline_args(uint64 trampolineCode,uint64 trampolineStack,uint32 pagedir,uint64 kernelEntry,addr_t virtKernelArgs,uint32 currentCpu)68 prepare_trampoline_args(uint64 trampolineCode, uint64 trampolineStack,
69 	uint32 pagedir, uint64 kernelEntry, addr_t virtKernelArgs,
70 	uint32 currentCpu)
71 {
72 	long_trampoline_args* args = (long_trampoline_args *)trampolineStack;
73 	args->trampoline = trampolineCode;
74 
75 	args->gdt32 = (uint64) &args->gdtr;
76 	args->gdtr.limit = 23;
77 	args->gdtr.base = (uint32)(uint64)args->gdtr.null;
78 	#define COPY_ARRAY(A, X0, X1, X2, X3, X4, X5, X6, X7) \
79 		{ A[0] = X0; A[1] = X1; A[2] = X2; A[3] = X3; A[4] = X4; A[5] = X5; A[6] = X6; A[7] = X7; }
80 	COPY_ARRAY(args->gdtr.null, 0, 0, 0, 0, 0, 0, 0, 0);
81 	COPY_ARRAY(args->gdtr.code, 0xff, 0xff, 0, 0, 0, 0x9a, 0xcf, 0);
82 	COPY_ARRAY(args->gdtr.data, 0xff, 0xff, 0, 0, 0, 0x92, 0xcf, 0);
83 	#undef COPY_ARRAY
84 	args->gdt64 = (uint32_t)(uint64_t)&gLongGDTR;
85 
86 	args->pml4 = pagedir;
87 	args->kernel_entry = kernelEntry;
88 	args->kernel_args = virtKernelArgs;
89 	args->current_cpu = currentCpu;
90 	args->stack_top = gKernelArgs.cpu_kstack[currentCpu].start
91 		+ gKernelArgs.cpu_kstack[currentCpu].size;
92 	args->sentinel = 1;
93 
94 	// put the args in the right place
95 	uint32 * args_ptr =
96 		(uint32 *)(trampolineCode + (uint64)long_smp_trampoline_args - (uint64)long_smp_trampoline);
97 	*args_ptr = (uint32)trampolineStack;
98 }
99 
100 
101 uint32
get_sentinel(uint64 trampolineStack)102 get_sentinel(uint64 trampolineStack)
103 {
104 	long_trampoline_args* args = (long_trampoline_args *)trampolineStack;
105 	return args->sentinel;
106 }
107