1 /* $NetBSD: arm32_machdep.c,v 1.26 2002/08/25 20:21:35 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1994-1998 Mark Brinicombe. 5 * Copyright (c) 1994 Brini. 6 * All rights reserved. 7 * 8 * This code is derived from software written for Brini by Mark Brinicombe 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Mark Brinicombe 21 * for the NetBSD Project. 22 * 4. The name of the company nor the name of the author may be used to 23 * endorse or promote products derived from this software without specific 24 * prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * Machine dependant functions for kernel setup 39 * 40 * Created : 17/09/94 41 * Updated : 18/04/01 updated for new wscons 42 */ 43 44 #include "opt_md.h" 45 #include "opt_pmap_debug.h" 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/reboot.h> 50 #include <sys/proc.h> 51 #include <sys/user.h> 52 #include <sys/kernel.h> 53 #include <sys/mbuf.h> 54 #include <sys/mount.h> 55 #include <sys/buf.h> 56 #include <sys/msgbuf.h> 57 #include <sys/device.h> 58 #include <uvm/uvm_extern.h> 59 #include <sys/sysctl.h> 60 61 #include <dev/cons.h> 62 63 #include <arm/arm32/katelib.h> 64 #include <arm/arm32/machdep.h> 65 #include <machine/bootconfig.h> 66 67 #include "opt_ipkdb.h" 68 #include "md.h" 69 70 struct vm_map *exec_map = NULL; 71 struct vm_map *mb_map = NULL; 72 struct vm_map *phys_map = NULL; 73 74 extern int physmem; 75 76 #ifndef PMAP_STATIC_L1S 77 extern int max_processes; 78 #endif /* !PMAP_STATIC_L1S */ 79 #if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) 80 extern size_t md_root_size; /* Memory disc size */ 81 #endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ 82 83 pv_addr_t kernelstack; 84 85 /* the following is used externally (sysctl_hw) */ 86 char machine[] = MACHINE; /* from <machine/param.h> */ 87 char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */ 88 89 /* Our exported CPU info; we can have only one. */ 90 struct cpu_info cpu_info_store; 91 92 caddr_t msgbufaddr; 93 extern paddr_t msgbufphys; 94 95 int kernel_debug = 0; 96 97 struct user *proc0paddr; 98 99 /* exported variable to be filled in by the bootloaders */ 100 char *booted_kernel; 101 102 103 /* Prototypes */ 104 105 u_long strtoul __P((const char *s, char **ptr, int base)); 106 void data_abort_handler __P((trapframe_t *frame)); 107 void prefetch_abort_handler __P((trapframe_t *frame)); 108 extern void configure __P((void)); 109 110 /* 111 * arm32_vector_init: 112 * 113 * Initialize the vector page, and select whether or not to 114 * relocate the vectors. 115 * 116 * NOTE: We expect the vector page to be mapped at its expected 117 * destination. 118 */ 119 void 120 arm32_vector_init(vaddr_t va, int which) 121 { 122 extern unsigned int page0[], page0_data[]; 123 unsigned int *vectors = (int *) va; 124 unsigned int *vectors_data = vectors + (page0_data - page0); 125 int vec; 126 127 /* 128 * Loop through the vectors we're taking over, and copy the 129 * vector's insn and data word. 130 */ 131 for (vec = 0; vec < ARM_NVEC; vec++) { 132 if ((which & (1 << vec)) == 0) { 133 /* Don't want to take over this vector. */ 134 continue; 135 } 136 vectors[vec] = page0[vec]; 137 vectors_data[vec] = page0_data[vec]; 138 } 139 140 /* Now sync the vectors. */ 141 cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int)); 142 143 vector_page = va; 144 } 145 146 /* 147 * Debug function just to park the CPU 148 */ 149 150 void 151 halt() 152 { 153 while (1) 154 cpu_sleep(0); 155 } 156 157 158 /* Sync the discs and unmount the filesystems */ 159 160 void 161 bootsync(void) 162 { 163 static int bootsyncdone = 0; 164 165 if (bootsyncdone) return; 166 167 bootsyncdone = 1; 168 169 /* Make sure we can still manage to do things */ 170 if (GetCPSR() & I32_bit) { 171 /* 172 * If we get here then boot has been called without RB_NOSYNC 173 * and interrupts were disabled. This means the boot() call 174 * did not come from a user process e.g. shutdown, but must 175 * have come from somewhere in the kernel. 176 */ 177 IRQenable; 178 printf("Warning IRQ's disabled during boot()\n"); 179 } 180 181 vfs_shutdown(); 182 } 183 184 /* 185 * void cpu_startup(void) 186 * 187 * Machine dependant startup code. 188 * 189 */ 190 void 191 cpu_startup() 192 { 193 paddr_t minaddr; 194 paddr_t maxaddr; 195 caddr_t sysbase; 196 caddr_t size; 197 vsize_t bufsize; 198 u_int loop, base, residual; 199 char pbuf[9]; 200 201 proc0paddr = (struct user *)kernelstack.pv_va; 202 proc0.p_addr = proc0paddr; 203 204 /* Set the cpu control register */ 205 cpu_setup(boot_args); 206 207 /* All domains MUST be clients, permissions are VERY important */ 208 cpu_domains(DOMAIN_CLIENT); 209 210 /* Lock down zero page */ 211 vector_page_setprot(VM_PROT_READ); 212 213 /* 214 * Give pmap a chance to set up a few more things now the vm 215 * is initialised 216 */ 217 pmap_postinit(); 218 219 /* 220 * Initialize error message buffer (at end of core). 221 */ 222 223 /* msgbufphys was setup during the secondary boot strap */ 224 for (loop = 0; loop < btoc(MSGBUFSIZE); ++loop) 225 pmap_kenter_pa((vaddr_t)msgbufaddr + loop * NBPG, 226 msgbufphys + loop * NBPG, VM_PROT_READ|VM_PROT_WRITE); 227 pmap_update(pmap_kernel()); 228 initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE)); 229 230 /* 231 * Identify ourselves for the msgbuf (everything printed earlier will 232 * not be buffered). 233 */ 234 printf(version); 235 236 format_bytes(pbuf, sizeof(pbuf), arm_ptob(physmem)); 237 printf("total memory = %s\n", pbuf); 238 239 /* 240 * Find out how much space we need, allocate it, 241 * and then give everything true virtual addresses. 242 */ 243 size = allocsys(NULL, NULL); 244 sysbase = (caddr_t)uvm_km_zalloc(kernel_map, round_page((vaddr_t)size)); 245 if (sysbase == 0) 246 panic( 247 "cpu_startup: no room for system tables; %d bytes required", 248 (u_int)size); 249 if ((caddr_t)((allocsys(sysbase, NULL) - sysbase)) != size) 250 panic("cpu_startup: system table size inconsistency"); 251 252 /* 253 * Now allocate buffers proper. They are different than the above 254 * in that they usually occupy more virtual memory than physical. 255 */ 256 bufsize = MAXBSIZE * nbuf; 257 if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(bufsize), 258 NULL, UVM_UNKNOWN_OFFSET, 0, 259 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, 260 UVM_ADV_NORMAL, 0)) != 0) 261 panic("cpu_startup: cannot allocate UVM space for buffers"); 262 minaddr = (vaddr_t)buffers; 263 if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { 264 /* don't want to alloc more physical mem than needed */ 265 bufpages = btoc(MAXBSIZE) * nbuf; 266 } 267 268 base = bufpages / nbuf; 269 residual = bufpages % nbuf; 270 for (loop = 0; loop < nbuf; ++loop) { 271 vsize_t curbufsize; 272 vaddr_t curbuf; 273 struct vm_page *pg; 274 275 /* 276 * Each buffer has MAXBSIZE bytes of VM space allocated. Of 277 * that MAXBSIZE space, we allocate and map (base+1) pages 278 * for the first "residual" buffers, and then we allocate 279 * "base" pages for the rest. 280 */ 281 curbuf = (vaddr_t) buffers + (loop * MAXBSIZE); 282 curbufsize = NBPG * ((loop < residual) ? (base+1) : base); 283 284 while (curbufsize) { 285 pg = uvm_pagealloc(NULL, 0, NULL, 0); 286 if (pg == NULL) 287 panic("cpu_startup: not enough memory for buffer cache"); 288 pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), 289 VM_PROT_READ|VM_PROT_WRITE); 290 curbuf += PAGE_SIZE; 291 curbufsize -= PAGE_SIZE; 292 } 293 } 294 pmap_update(pmap_kernel()); 295 296 /* 297 * Allocate a submap for exec arguments. This map effectively 298 * limits the number of processes exec'ing at any time. 299 */ 300 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 301 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 302 303 /* 304 * Allocate a submap for physio 305 */ 306 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 307 VM_PHYS_SIZE, 0, FALSE, NULL); 308 309 /* 310 * Finally, allocate mbuf cluster submap. 311 */ 312 mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 313 nmbclusters * mclbytes, VM_MAP_INTRSAFE, 314 FALSE, NULL); 315 316 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 317 printf("avail memory = %s\n", pbuf); 318 format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG); 319 printf("using %u buffers containing %s of memory\n", nbuf, pbuf); 320 321 /* 322 * Set up buffers, so they can be used to read disk labels. 323 */ 324 bufinit(); 325 326 curpcb = &proc0.p_addr->u_pcb; 327 curpcb->pcb_flags = 0; 328 curpcb->pcb_un.un_32.pcb32_und_sp = (u_int)proc0.p_addr + 329 USPACE_UNDEF_STACK_TOP; 330 curpcb->pcb_un.un_32.pcb32_sp = (u_int)proc0.p_addr + 331 USPACE_SVC_STACK_TOP; 332 (void) pmap_extract(pmap_kernel(), (vaddr_t)(pmap_kernel())->pm_pdir, 333 (paddr_t *)&curpcb->pcb_pagedir); 334 335 curpcb->pcb_tf = (struct trapframe *)curpcb->pcb_un.un_32.pcb32_sp - 1; 336 } 337 338 /* 339 * machine dependent system variables. 340 */ 341 342 int 343 cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 344 int *name; 345 u_int namelen; 346 void *oldp; 347 size_t *oldlenp; 348 void *newp; 349 size_t newlen; 350 struct proc *p; 351 { 352 /* all sysctl names at this level are terminal */ 353 if (namelen != 1) 354 return (ENOTDIR); /* overloaded */ 355 356 switch (name[0]) { 357 case CPU_DEBUG: 358 return(sysctl_int(oldp, oldlenp, newp, newlen, &kernel_debug)); 359 360 case CPU_BOOTED_DEVICE: 361 if (booted_device != NULL) 362 return (sysctl_rdstring(oldp, oldlenp, newp, 363 booted_device->dv_xname)); 364 return (EOPNOTSUPP); 365 366 case CPU_CONSDEV: { 367 dev_t consdev; 368 if (cn_tab != NULL) 369 consdev = cn_tab->cn_dev; 370 else 371 consdev = NODEV; 372 return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, 373 sizeof consdev)); 374 } 375 case CPU_BOOTED_KERNEL: { 376 if (booted_kernel != NULL && booted_kernel[0] != '\0') 377 return sysctl_rdstring(oldp, oldlenp, newp, 378 booted_kernel); 379 return (EOPNOTSUPP); 380 } 381 case CPU_POWERSAVE: { 382 int error, newval; 383 384 newval = cpu_do_powersave; 385 386 if (cpufuncs.cf_sleep == (void *) cpufunc_nullop) 387 error = sysctl_rdint(oldp, oldlenp, newp, newval); 388 else 389 error = sysctl_int(oldp, oldlenp, newp, newlen, 390 &newval); 391 if (error || newval == cpu_do_powersave) 392 return (error); 393 394 if (newval < 0 || newval > 1) 395 return (EINVAL); 396 397 cpu_do_powersave = newval; 398 return (0); 399 } 400 401 default: 402 return (EOPNOTSUPP); 403 } 404 /* NOTREACHED */ 405 } 406 407 void 408 parse_mi_bootargs(args) 409 char *args; 410 { 411 int integer; 412 413 if (get_bootconf_option(args, "single", BOOTOPT_TYPE_BOOLEAN, &integer) 414 || get_bootconf_option(args, "-s", BOOTOPT_TYPE_BOOLEAN, &integer)) 415 if (integer) 416 boothowto |= RB_SINGLE; 417 if (get_bootconf_option(args, "kdb", BOOTOPT_TYPE_BOOLEAN, &integer) 418 || get_bootconf_option(args, "-k", BOOTOPT_TYPE_BOOLEAN, &integer)) 419 if (integer) 420 boothowto |= RB_KDB; 421 if (get_bootconf_option(args, "ask", BOOTOPT_TYPE_BOOLEAN, &integer) 422 || get_bootconf_option(args, "-a", BOOTOPT_TYPE_BOOLEAN, &integer)) 423 if (integer) 424 boothowto |= RB_ASKNAME; 425 426 #ifdef PMAP_DEBUG 427 if (get_bootconf_option(args, "pmapdebug", BOOTOPT_TYPE_INT, &integer)) { 428 pmap_debug_level = integer; 429 pmap_debug(pmap_debug_level); 430 } 431 #endif /* PMAP_DEBUG */ 432 433 /* if (get_bootconf_option(args, "nbuf", BOOTOPT_TYPE_INT, &integer)) 434 bufpages = integer;*/ 435 436 #ifndef PMAP_STATIC_L1S 437 if (get_bootconf_option(args, "maxproc", BOOTOPT_TYPE_INT, &integer)) { 438 max_processes = integer; 439 if (max_processes < 16) 440 max_processes = 16; 441 /* Limit is PDSIZE * (max_processes + 1) <= 4MB */ 442 if (max_processes > 255) 443 max_processes = 255; 444 } 445 #endif /* !PMAP_STATUC_L1S */ 446 #if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) 447 if (get_bootconf_option(args, "memorydisc", BOOTOPT_TYPE_INT, &integer) 448 || get_bootconf_option(args, "memorydisk", BOOTOPT_TYPE_INT, &integer)) { 449 md_root_size = integer; 450 md_root_size *= 1024; 451 if (md_root_size < 32*1024) 452 md_root_size = 32*1024; 453 if (md_root_size > 2048*1024) 454 md_root_size = 2048*1024; 455 } 456 #endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ 457 458 if (get_bootconf_option(args, "quiet", BOOTOPT_TYPE_BOOLEAN, &integer) 459 || get_bootconf_option(args, "-q", BOOTOPT_TYPE_BOOLEAN, &integer)) 460 if (integer) 461 boothowto |= AB_QUIET; 462 if (get_bootconf_option(args, "verbose", BOOTOPT_TYPE_BOOLEAN, &integer) 463 || get_bootconf_option(args, "-v", BOOTOPT_TYPE_BOOLEAN, &integer)) 464 if (integer) 465 boothowto |= AB_VERBOSE; 466 } 467