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