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
70struct vm_map *exec_map = NULL;
71struct vm_map *phys_map = NULL;
72
73extern int physmem;
74
75struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
76struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
77
78int cold = 1;
79
80pv_addr_t kernelstack;
81
82/* the following is used externally (sysctl_hw) */
83char	machine[] = MACHINE;		/* from <machine/param.h> */
84
85/* Statically defined CPU info. */
86struct cpu_info cpu_info_primary;
87struct 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 */
94struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary };
95#endif
96
97caddr_t	msgbufaddr;
98extern paddr_t msgbufphys;
99
100struct user *proc0paddr;
101
102#ifdef APERTURE
103int allowaperture = 0;
104#endif
105
106struct consdev *cn_tab;
107
108/* Prototypes */
109
110void data_abort_handler		(trapframe_t *frame);
111void 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 */
122void
123arm32_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
173void
174halt(void)
175{
176	while (1)
177		cpu_sleep(0);
178}
179
180
181/* Sync the discs and unmount the filesystems */
182
183void
184bootsync(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 */
220void
221cpu_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
298int
299cpu_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