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
cpu_get_dcache_line_size(void)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
cpu_flush_dcache(vaddr_t addr,vsize_t len)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
cpu_inval_icache(void)82 cpu_inval_icache(void)
83 {
84 __asm volatile(
85 "ic ialluis \n"
86 "dsb ish \n"
87 : : : "memory");
88 }
89
90 void
run_loadfile(uint64_t * marks,int howto)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