xref: /freebsd/stand/kboot/kboot/arch/amd64/amd64_tramp.S (revision d7e6ab7a9709c8fc986dedd4783d311d4fbb676e)
1/*-
2 * Copyright (c) 2022 Netflix, Inc
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26/*
27 * This is the trampoline that starts the FreeBSD kernel. Since the Linux kernel
28 * calls this routine with no args, and has a different environment than the
29 * boot loader provides and that the kernel expects, this code is responsible
30 * for setting all that up and calling the normal kernel entry point. It's
31 * analogous to the "purgatory" code in the linux kernel. Details about these
32 * operations are contained in comments below. On amd64, the kernel starts all
33 * the APs so we don't have to worry about them here.
34 */
35
36/*
37 * Keep in sync with elf64_freebsd.c. Kexec starts tramp w/o any parameters, so
38 * store them here. This is constructed to be a useful stack:
39 *
40 * struct trampoline_data {
41 * // %rsp points here on start and we pop the args off and then retq to 'entry'
42 *	uint64_t	memmap_src;		// Linux-provided memory map PA
43 *	uint64_t	memmap_dst;		// Module data copy PA
44 *	uint64_t	memmap_len;		// Length to copy
45 *	uint64_t	pt4;			// Page table address to pop
46 *	uint64_t	entry;			// return address to jump to kernel
47 *	uint32_t	fill1;			// 0
48 *	uint32_t	modulep;		// 4 module metadata
49 *	uint32_t	kernend;		// 8 kernel end
50 *	uint32_t	fill2;			// 12
51 * };
52 *
53 * loader.kboot will construct a stack that btext expects, which is arguments on
54 * the stack, not in registers, and these args are 32-bit not 64. The extra stuff
55 * is data the trampoline code consumes.
56 *
57 * Processor is already in long mode when we're called, paging is enabled and
58 * boot loader loads things such that:
59 * - kernel mapped at KERNBASE, aligned to 2MB, below 4GB, contiguous memory
60 * - %cr3 tells us our PA later in boot, so we install it before jumping
61 *   to the kernel.
62 * - there is a 2M hole at KERNBASE (KERNSTART = KERNBASE + 2M)
63 * - kernel is mapped with 2M superpages
64 * - The kernel, modules and metadata is in first 4GB which is unity mapped
65 * - There's additional memory after loader provided data for early allocations
66 *
67 * Unlike coming directly from loader.efi, we don't support copying the staging
68 * area. We tell Linux to land the kernel in its final location with the needed
69 * alignment, etc. We copy the trampoline code to 1MB offset above KERNBASE
70 * since that memory is otherwise free and safely above the lower 1MB swamp we
71 * inherited from IBM PC, though this code makes no assumptions about where that
72 * might be.
73 *
74 * Thus, the trampoline just needs to set %rsp to that stack pop the systab
75 * patch value, pop the %cr3 value, set it and then retq to jump to the kernel
76 * with its stack args filled in.  Since the handoff to this code used to be
77 * from 32-bit code, it uses the i386 calling conventions which put the
78 * arguments on the stack. The kernel's btext routine expects this setup.
79 */
80
81	.text
82	.globl	tramp
83tramp:
84	cli				/* Make sure we don't get interrupted. */
85	cld				/* Copy in a sane direction */
86	leaq	stack_start(%rip), %rsp	/* Setup our pre-filled-in stack */
87
88	/*
89	 * If we have a EFI memory map, copy it over. These data are always
90	 * on the stack, so we pop them all off before testing to skip the copy.
91	 */
92	popq	%rsi			/* memmap_src */
93	popq	%rdi			/* memmap_dst */
94	popq	%rcx			/* memmap_size */
95	testq	%rsi, %rsi
96	je	no_map_copy
97	rep	movsb			/* Make the copy */
98
99no_map_copy:
100	popq	%rax			/* Pop off the PT4 ptr for %cr3 */
101	movq	%rax, %cr3		/* set the page table */
102	retq				/* Return addr and args already on stack */
103/*
104 * The following is the stack for the above code. The stack will increase in
105 * address as things are popped off of it, so we start with the stack pointing
106 * to tramp_pt4.
107 */
108	.p2align	3		/* Stack has to be 8 byte aligned */
109trampoline_data:
110stack_start:				/* %rsp at start. */
111tramp_memmap_src:
112		.quad	0		/* SRC PA (data from Linux) */
113tramp_memmap_dst:
114		.quad	0		/* DST PA (data to FreeBSD's metadata */
115tramp_memmap_len:
116		.quad	0		/* Length */
117tramp_pt4:	.quad	0		/* New %cr3 value */
118tramp_entry:	.quad	0		/* Entry to kernel (btext) */
119	/* %rsp points here on entry to amd64 kernel's btext */
120		.long	0		/* 0 filler, ignored (current loaders set to 0) */
121tramp_modulep:	.long	0		/* 4 moudlep */
122tramp_kernend:	.long	0		/* 8 kernend */
123		.long	0		/* 12 alignment filler (also 0) */
124tramp_end:
125
126	.data
127	.type   tramp_size,@object
128	.globl	tramp_size
129tramp_size:
130	.long	tramp_end-tramp
131	.size	tramp_size, 4
132
133	.type   tramp_data_offset,@object
134	.globl	tramp_data_offset
135tramp_data_offset:
136	.long	trampoline_data-tramp
137	.size	tramp_data_offset, 4
138
139	.section .note.GNU-stack,"",%progbits
140