xref: /openbsd/sys/arch/arm/arm/arm32_machdep.c (revision 3b372c34)
1 /*	$OpenBSD: arm32_machdep.c,v 1.63 2024/05/14 08:26:13 jsg Exp $	*/
2 /*	$NetBSD: arm32_machdep.c,v 1.42 2003/12/30 12:33:15 pk Exp $	*/
3 
4 /*
5  * Copyright (c) 1994-1998 Mark Brinicombe.
6  * Copyright (c) 1994 Brini.
7  * All rights reserved.
8  *
9  * This code is derived from software written for Brini by Mark Brinicombe
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by Mark Brinicombe
22  *	for the NetBSD Project.
23  * 4. The name of the company nor the name of the author may be used to
24  *    endorse or promote products derived from this software without specific
25  *    prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
28  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  * Machine dependant functions for kernel setup
40  *
41  * Created      : 17/09/94
42  * Updated	: 18/04/01 updated for new wscons
43  */
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/reboot.h>
48 #include <sys/proc.h>
49 #include <sys/user.h>
50 #include <sys/malloc.h>
51 #include <sys/mount.h>
52 #include <sys/buf.h>
53 #include <sys/msg.h>
54 #include <sys/msgbuf.h>
55 #include <sys/sysctl.h>
56 
57 #include <uvm/uvm_extern.h>
58 
59 #include <dev/cons.h>
60 #include <dev/ofw/openfirm.h>
61 
62 #include <arm/machdep.h>
63 
64 #ifdef CONF_HAVE_APM
65 #include "apm.h"
66 #else
67 #define NAPM	0
68 #endif
69 
70 struct vm_map *exec_map = NULL;
71 struct vm_map *phys_map = NULL;
72 
73 extern int physmem;
74 
75 struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
76 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
77 
78 int cold = 1;
79 
80 pv_addr_t kernelstack;
81 
82 /* the following is used externally (sysctl_hw) */
83 char	machine[] = MACHINE;		/* from <machine/param.h> */
84 
85 /* Statically defined CPU info. */
86 struct cpu_info cpu_info_primary;
87 struct cpu_info *cpu_info_list = &cpu_info_primary;
88 
89 #ifdef MULTIPROCESSOR
90 /*
91  * Array of CPU info structures.  Must be statically-allocated because
92  * curproc, etc. are used early.
93  */
94 struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary };
95 #endif
96 
97 caddr_t	msgbufaddr;
98 extern paddr_t msgbufphys;
99 
100 struct user *proc0paddr;
101 
102 #ifdef APERTURE
103 int allowaperture = 0;
104 #endif
105 
106 struct consdev *cn_tab;
107 
108 /* Prototypes */
109 
110 void data_abort_handler		(trapframe_t *frame);
111 void prefetch_abort_handler	(trapframe_t *frame);
112 
113 /*
114  * arm32_vector_init:
115  *
116  *	Initialize the vector page, and select whether or not to
117  *	relocate the vectors.
118  *
119  *	NOTE: We expect the vector page to be mapped at its expected
120  *	destination.
121  */
122 void
arm32_vector_init(vaddr_t va,int which)123 arm32_vector_init(vaddr_t va, int which)
124 {
125 	extern unsigned int page0[], page0_data[];
126 	unsigned int *vectors = (unsigned int *) va;
127 	unsigned int *vectors_data = vectors + (page0_data - page0);
128 	int vec;
129 
130 	/*
131 	 * Loop through the vectors we're taking over, and copy the
132 	 * vector's insn and data word.
133 	 */
134 	for (vec = 0; vec < ARM_NVEC; vec++) {
135 		if ((which & (1 << vec)) == 0) {
136 			/* Don't want to take over this vector. */
137 			continue;
138 		}
139 		vectors[vec] = page0[vec];
140 		vectors_data[vec] = page0_data[vec];
141 	}
142 
143 	/* Now sync the vectors. */
144 	cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int));
145 
146 	vector_page = va;
147 
148 	if (va == ARM_VECTORS_HIGH) {
149 		/*
150 		 * Assume the MD caller knows what it's doing here, and
151 		 * really does want the vector page relocated.
152 		 *
153 		 * Note: This has to be done here (and not just in
154 		 * cpu_setup()) because the vector page needs to be
155 		 * accessible *before* main() is called.
156 		 * Think ddb(9) ...
157 		 *
158 		 * NOTE: If the CPU control register is not readable,
159 		 * this will totally fail!  We'll just assume that
160 		 * any system that has high vector support has a
161 		 * readable CPU control register, for now.  If we
162 		 * ever encounter one that does not, we'll have to
163 		 * rethink this.
164 		 */
165 		cpu_control(CPU_CONTROL_VECRELOC, CPU_CONTROL_VECRELOC);
166 	}
167 }
168 
169 /*
170  * Debug function just to park the CPU
171  */
172 
173 void
halt(void)174 halt(void)
175 {
176 	while (1)
177 		cpu_sleep(0);
178 }
179 
180 
181 /* Sync the discs and unmount the filesystems */
182 
183 void
bootsync(int howto)184 bootsync(int howto)
185 {
186 	static int bootsyncdone = 0;
187 
188 	if (bootsyncdone)
189 		return;
190 
191 	bootsyncdone = 1;
192 
193 	/* Make sure we can still manage to do things */
194 	if (__get_cpsr() & PSR_I) {
195 		/*
196 		 * If we get here then boot has been called without RB_NOSYNC
197 		 * and interrupts were disabled. This means the boot() call
198 		 * did not come from a user process e.g. shutdown, but must
199 		 * have come from somewhere in the kernel.
200 		 */
201 		__set_cpsr_c(PSR_I, 0);
202 		printf("Warning IRQ's disabled during boot()\n");
203 	}
204 
205 	vfs_shutdown(curproc);
206 
207 	if ((howto & RB_TIMEBAD) == 0) {
208 		resettodr();
209 	} else {
210 		printf("WARNING: not updating battery clock\n");
211 	}
212 }
213 
214 /*
215  * void cpu_startup(void)
216  *
217  * Machine dependant startup code.
218  *
219  */
220 void
cpu_startup(void)221 cpu_startup(void)
222 {
223 	u_int loop;
224 	paddr_t minaddr;
225 	paddr_t maxaddr;
226 
227 	/* Lock down zero page */
228 	vector_page_setprot(PROT_READ | PROT_EXEC);
229 
230 	/*
231 	 * Give pmap a chance to set up a few more things now the vm
232 	 * is initialised
233 	 */
234 	pmap_postinit();
235 
236 	/*
237 	 * Allow per-board specific initialization
238 	 */
239 	board_startup();
240 
241 	/*
242 	 * Initialize error message buffer (at end of core).
243 	 */
244 
245 	/* msgbufphys was setup during the secondary boot strap */
246 	for (loop = 0; loop < atop(MSGBUFSIZE); ++loop)
247 		pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE,
248 		    msgbufphys + loop * PAGE_SIZE, PROT_READ | PROT_WRITE);
249 	pmap_update(pmap_kernel());
250 	initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE));
251 
252 	/*
253 	 * Identify ourselves for the msgbuf (everything printed earlier will
254 	 * not be buffered).
255 	 */
256 	printf("%s", version);
257 
258 	printf("real mem  = %lu (%luMB)\n", ptoa(physmem),
259 	    ptoa(physmem)/1024/1024);
260 
261 	/*
262 	 * Allocate a submap for exec arguments.  This map effectively
263 	 * limits the number of processes exec'ing at any time.
264 	 */
265 	minaddr = vm_map_min(kernel_map);
266 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
267 				   16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
268 
269 	/*
270 	 * Allocate a submap for physio
271 	 */
272 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
273 				   VM_PHYS_SIZE, 0, FALSE, NULL);
274 
275 	/*
276 	 * Set up buffers, so they can be used to read disk labels.
277 	 */
278 	bufinit();
279 
280 	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
281 	    ptoa(uvmexp.free)/1024/1024);
282 
283 	curpcb = &proc0.p_addr->u_pcb;
284 	curpcb->pcb_flags = 0;
285 	curpcb->pcb_un.un_32.pcb32_und_sp = (u_int)proc0.p_addr +
286 	    USPACE_UNDEF_STACK_TOP;
287 	curpcb->pcb_un.un_32.pcb32_sp = (u_int)proc0.p_addr +
288 	    USPACE_SVC_STACK_TOP;
289 	pmap_set_pcb_pagedir(pmap_kernel(), curpcb);
290 
291         curpcb->pcb_tf = (struct trapframe *)curpcb->pcb_un.un_32.pcb32_sp - 1;
292 }
293 
294 /*
295  * machine dependent system variables.
296  */
297 
298 int
cpu_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)299 cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
300     size_t newlen, struct proc *p)
301 {
302 	char *compatible;
303 	int node, len, error;
304 
305 	/* all sysctl names at this level are terminal */
306 	if (namelen != 1)
307 		return (ENOTDIR);		/* overloaded */
308 
309 	switch (name[0]) {
310 	case CPU_CONSDEV: {
311 		dev_t consdev;
312 		if (cn_tab != NULL)
313 			consdev = cn_tab->cn_dev;
314 		else
315 			consdev = NODEV;
316 		return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
317 			sizeof consdev));
318 	}
319 
320 	case CPU_ALLOWAPERTURE:
321 #ifdef APERTURE
322 		if (securelevel > 0)
323 			return (sysctl_int_lower(oldp, oldlenp, newp, newlen,
324 			    &allowaperture));
325 		else
326 			return (sysctl_int(oldp, oldlenp, newp, newlen,
327 			    &allowaperture));
328 #else
329 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
330 #endif
331 
332 	case CPU_COMPATIBLE:
333 		node = OF_finddevice("/");
334 		len = OF_getproplen(node, "compatible");
335 		if (len <= 0)
336 			return (EOPNOTSUPP);
337 		compatible = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
338 		OF_getprop(node, "compatible", compatible, len);
339 		compatible[len - 1] = 0;
340 		error = sysctl_rdstring(oldp, oldlenp, newp, compatible);
341 		free(compatible, M_TEMP, len);
342 		return error;
343 
344 	default:
345 		return (EOPNOTSUPP);
346 	}
347 	/* NOTREACHED */
348 }
349