xref: /openbsd/sys/arch/arm64/stand/efiboot/exec.c (revision 73471bf0)
1 /*	$OpenBSD: exec.c,v 1.8 2020/05/10 11:55:42 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2006, 2016 Mark Kettenis
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/reboot.h>
21 #include <dev/cons.h>
22 
23 #include <lib/libkern/libkern.h>
24 #include <lib/libsa/loadfile.h>
25 #include <sys/exec_elf.h>
26 
27 #include <efi.h>
28 #include <stand/boot/cmd.h>
29 
30 #include <machine/armreg.h>
31 
32 #include "efiboot.h"
33 #include "libsa.h"
34 #include "fdt.h"
35 
36 typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn));
37 
38 unsigned int cpu_get_dcache_line_size(void);
39 void cpu_flush_dcache(vaddr_t, vsize_t);
40 void cpu_inval_icache(void);
41 
42 unsigned int
43 cpu_get_dcache_line_size(void)
44 {
45 	uint64_t ctr;
46 	unsigned int dcl_size;
47 
48 	/* Accessible from all security levels */
49 	ctr = READ_SPECIALREG(ctr_el0);
50 
51 	/*
52 	 * Relevant field [19:16] is LOG2
53 	 * of the number of words in DCache line
54 	 */
55 	dcl_size = CTR_DLINE_SIZE(ctr);
56 
57 	/* Size of word shifted by cache line size */
58 	return (sizeof(int) << dcl_size);
59 }
60 
61 void
62 cpu_flush_dcache(vaddr_t addr, vsize_t len)
63 {
64 	uint64_t cl_size;
65 	vaddr_t end;
66 
67 	cl_size = cpu_get_dcache_line_size();
68 
69 	/* Calculate end address to clean */
70 	end = addr + len;
71 	/* Align start address to cache line */
72 	addr = addr & ~(cl_size - 1);
73 
74 	for (; addr < end; addr += cl_size)
75 		__asm volatile("dc civac, %0" :: "r" (addr) : "memory");
76 
77 	/* Full system DSB */
78 	__asm volatile("dsb sy" ::: "memory");
79 }
80 
81 void
82 cpu_inval_icache(void)
83 {
84 	__asm volatile(
85 	    "ic		ialluis	\n"
86 	    "dsb	ish	\n"
87 	    : : : "memory");
88 }
89 
90 void
91 run_loadfile(uint64_t *marks, int howto)
92 {
93 	char args[256];
94 	char *cp;
95 	void *fdt;
96 
97 	strlcpy(args, cmd.path, sizeof(args));
98 	cp = args + strlen(args);
99 
100 	*cp++ = ' ';
101 	*cp = '-';
102 	if (howto & RB_ASKNAME)
103 		*++cp = 'a';
104 	if (howto & RB_CONFIG)
105 		*++cp = 'c';
106 	if (howto & RB_SINGLE)
107 		*++cp = 's';
108 	if (howto & RB_KDB)
109 		*++cp = 'd';
110 	if (*cp == '-')
111 		*--cp = 0;
112 	else
113 		*++cp = 0;
114 
115 	fdt = efi_makebootargs(args, howto);
116 
117 	efi_cleanup();
118 
119 	cpu_flush_dcache(marks[MARK_ENTRY], marks[MARK_END] - marks[MARK_ENTRY]);
120 	cpu_inval_icache();
121 
122 	cpu_flush_dcache((vaddr_t)fdt, fdt_get_size(fdt));
123 
124 	(*(startfuncp)(marks[MARK_ENTRY]))((void *)marks[MARK_END], 0, fdt);
125 
126 	/* NOTREACHED */
127 }
128