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
27extern "C" void smp_trampoline(void);
28extern "C" void smp_trampoline_args(void);
29extern "C" void smp_trampoline_end(void);
30
31struct gdtr {
32    uint16 limit;
33    uint32 base;
34    unsigned char null[8];
35    unsigned char code[8];
36    unsigned char data[8];
37} __attribute__((packed));
38
39// Arguments passed to the SMP trampoline.
40struct trampoline_args {
41	uint32 trampoline;		// Trampoline address
42	uint32 gdt;			// GDTR
43	uint32 page_dir;		// page directory
44	uint32 kernel_entry;		// Kernel entry point
45	uint32 kernel_args;		// Kernel arguments
46	uint32 current_cpu;		// CPU number
47	uint32 stack_top;		// Kernel stack
48	volatile uint32 sentinel;	// Sentinel, AP sets to 0 when finished
49
50	// smp_boot_other_cpus puts the GDTR here.
51	struct gdtr gdtr;
52};
53
54
55void
56copy_trampoline_code(uint64 trampolineCode, uint64 trampolineStack)
57{
58	TRACE("copying the trampoline code to %p from %p\n", (char*)trampolineCode, (const void*)&smp_trampoline);
59	TRACE("size of trampoline code = %" PRIu64 " bytes\n", (uint64)&smp_trampoline_end - (uint64)&smp_trampoline);
60	memcpy((char *)trampolineCode, (const void*)&smp_trampoline,
61		(uint64)&smp_trampoline_end - (uint64)&smp_trampoline);
62}
63
64
65void
66prepare_trampoline_args(uint64 trampolineCode, uint64 trampolineStack,
67	uint32 pagedir, uint64 kernelEntry, addr_t virtKernelArgs,
68	uint32 currentCpu)
69{
70	trampoline_args* args = (trampoline_args *)trampolineStack;
71	args->trampoline = trampolineCode;
72
73	args->gdt = (uint32) &args->gdtr;
74	args->gdtr.limit = 23;
75	args->gdtr.base = (uint32)(uint64)args->gdtr.null;
76	#define COPY_ARRAY(A, X0, X1, X2, X3, X4, X5, X6, X7) \
77		{ A[0] = X0; A[1] = X1; A[2] = X2; A[3] = X3; A[4] = X4; A[5] = X5; A[6] = X6; A[7] = X7; }
78	COPY_ARRAY(args->gdtr.null, 0, 0, 0, 0, 0, 0, 0, 0);
79	COPY_ARRAY(args->gdtr.code, 0xff, 0xff, 0, 0, 0, 0x9a, 0xcf, 0);
80	COPY_ARRAY(args->gdtr.data, 0xff, 0xff, 0, 0, 0, 0x92, 0xcf, 0);
81	#undef COPY_ARRAY
82	//TODO: final GDT
83
84	args->page_dir = pagedir;
85	args->kernel_entry = kernelEntry;
86	args->kernel_args = virtKernelArgs;
87	args->current_cpu = currentCpu;
88	args->stack_top = gKernelArgs.cpu_kstack[currentCpu].start
89		+ gKernelArgs.cpu_kstack[currentCpu].size;
90	args->sentinel = 1;
91
92	// put the args in the right place
93	uint32 * args_ptr =
94		(uint32 *)(trampolineCode + (uint64)smp_trampoline_args - (uint64)smp_trampoline);
95	*args_ptr = (uint32)trampolineStack;
96}
97
98
99uint32
100get_sentinel(uint64 trampolineStack)
101{
102	trampoline_args* args = (trampoline_args *)trampolineStack;
103	return args->sentinel;
104}
105