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