xref: /freebsd/stand/kboot/kboot/arch/aarch64/tramp.S (revision 5f757f3f)
1/*
2 * Copyright (c) 2022, Netflix, Inc.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7/*
8 * This is the trampoline that starts the FreeBSD kernel. Since the Linux kernel
9 * calls this routine with no args, and has a different environment than the boot
10 * loader provides and that the kernel expects, this code is responsible for setting
11 * all that up and calling the normal kernel entry point. It's analogous ot the
12 * "purgatory" code in the linux kernel. Details about these operations are
13 * contained in comments below. On aarch64, the kernel will start all the APs so
14 * we don't have to worry about them here.
15 */
16
17/*
18 * Keep in sync with exec.c. Kexec starts aarch64_tramp w/o any
19 * parameters, so store them here.
20 *
21 * struct trampoline_data {
22 *	uint64_t	entry;			//  0 (PA where kernel loaded)
23 *	uint64_t	modulep;		//  8 module metadata
24 *	uint64_t	memmap_src;		// 16 Linux-provided memory map PA
25 *	uint64_t	memmap_dst;		// 24 Module data copy PA
26 *	uint64_t	memmap_len;		// 32 Length to copy
27 * };
28 *
29 * FreeBSD's arm64 entry point is _start which assumes:
30 *  MMU      on with an identity map, or off
31 *  D-Cache: off
32 *  I-Cache: on or off
33 *  We are loaded at a 2MiB aligned address
34 *  Module data (modulep) pointer in x0
35 *
36 * The rest of the boot loader tells Linux to land the kernel in its final
37 * location with the needed alignment, etc. It does this, and then we take over.
38 *
39 * The linux kernel will helpfully turn off the MMU, flush the caches, disables
40 * them, etc. It calls the tramp with two args: FDT blob address in x0 and the
41 * EL2 vectors in x1. Currently, we make use of neither of these parameters: we
42 * pass whatever dtb we think we need as part of the module data and we're a bit
43 * weak on hypervisor support at the moment. _start's requirements are all
44 * satisifed.
45 *
46 * This trampoline sets up the arguments the kernel expects and jumps to the
47 * kernel _start address. We pass the modulep pointer in x0, as _start
48 * expects. We assume that the various cache flushing, invalidation, etc that
49 * linux did during or after copying the data down is sufficient, though we may
50 * need to be mindful of cache flushing if we run in EL2 (TBD).
51 *
52 * Note, if TRAMP_MEMMAP_SRC is non-zero, then we have to copy the Linux
53 * provided UEFI memory map. It's easier to do that here. In kboot we couldn't
54 * access the physical memory, and it's a chicken and egg problem later in the
55 * kernel.
56 */
57
58#define TRAMP_ENTRY		0
59#define TRAMP_MODULEP		8
60#define TRAMP_MEMMAP_SRC	16
61#define TRAMP_MEMMAP_DST	24
62#define TRAMP_MEMMAP_LEN	32
63#define TRAMP_TOTAL		40
64
65	.text
66	.globl	tramp
67tramp:
68	adr	x8, trampoline_data
69	ldr	x10, [x8, #TRAMP_MEMMAP_SRC]
70	cmp	x10, xzr
71	b.eq	9f
72
73	/*
74	 * Copy over the memory map into area we have reserved for it. Assume
75	 * the copy is a multiple of 8, since we know table entries are made up
76	 * of several 64-bit quantities.
77	 */
78	ldp	x11, x12, [x8, #TRAMP_MEMMAP_DST]	/* x12 = len */
791:
80	ldr	x13, [x10], #8
81	str	x13, [x11], #8
82	subs	x12, x12, #8
83	b.hi	1b
849:
85	ldp	x9, x0, [x8, #TRAMP_ENTRY]		/* x0 = modulep */
86	br	x9
87
88	.p2align 4
89trampoline_data:
90	.space TRAMP_TOTAL
91#define TMPSTACKSIZE	48	/* 16 bytes for args +8 for pushq/popfq + 24 spare */
92	.space	TMPSTACKSIZE
93tramp_end:			/* padding doubles as stack */
94
95	.data
96	.globl	tramp_size
97tramp_size:
98	.long	tramp_end-tramp
99	.globl	tramp_data_offset
100tramp_data_offset:
101	.long	trampoline_data-tramp
102