1 /* $NetBSD: arm32_machdep.c,v 1.34 2003/06/04 13:30:05 simonb 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 #if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) 77 extern size_t md_root_size; /* Memory disc size */ 78 #endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ 79 80 pv_addr_t kernelstack; 81 82 /* the following is used externally (sysctl_hw) */ 83 char machine[] = MACHINE; /* from <machine/param.h> */ 84 char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */ 85 86 /* Our exported CPU info; we can have only one. */ 87 struct cpu_info cpu_info_store; 88 89 caddr_t msgbufaddr; 90 extern paddr_t msgbufphys; 91 92 int kernel_debug = 0; 93 94 struct user *proc0paddr; 95 96 /* exported variable to be filled in by the bootloaders */ 97 char *booted_kernel; 98 99 100 /* Prototypes */ 101 102 void data_abort_handler __P((trapframe_t *frame)); 103 void prefetch_abort_handler __P((trapframe_t *frame)); 104 extern void configure __P((void)); 105 106 /* 107 * arm32_vector_init: 108 * 109 * Initialize the vector page, and select whether or not to 110 * relocate the vectors. 111 * 112 * NOTE: We expect the vector page to be mapped at its expected 113 * destination. 114 */ 115 void 116 arm32_vector_init(vaddr_t va, int which) 117 { 118 extern unsigned int page0[], page0_data[]; 119 unsigned int *vectors = (int *) va; 120 unsigned int *vectors_data = vectors + (page0_data - page0); 121 int vec; 122 123 /* 124 * Loop through the vectors we're taking over, and copy the 125 * vector's insn and data word. 126 */ 127 for (vec = 0; vec < ARM_NVEC; vec++) { 128 if ((which & (1 << vec)) == 0) { 129 /* Don't want to take over this vector. */ 130 continue; 131 } 132 vectors[vec] = page0[vec]; 133 vectors_data[vec] = page0_data[vec]; 134 } 135 136 /* Now sync the vectors. */ 137 cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int)); 138 139 vector_page = va; 140 141 if (va == ARM_VECTORS_HIGH) { 142 /* 143 * Assume the MD caller knows what it's doing here, and 144 * really does want the vector page relocated. 145 * 146 * Note: This has to be done here (and not just in 147 * cpu_setup()) because the vector page needs to be 148 * accessible *before* cpu_startup() is called. 149 * Think ddb(9) ... 150 * 151 * NOTE: If the CPU control register is not readable, 152 * this will totally fail! We'll just assume that 153 * any system that has high vector support has a 154 * readable CPU control register, for now. If we 155 * ever encounter one that does not, we'll have to 156 * rethink this. 157 */ 158 cpu_control(CPU_CONTROL_VECRELOC, CPU_CONTROL_VECRELOC); 159 } 160 } 161 162 /* 163 * Debug function just to park the CPU 164 */ 165 166 void 167 halt() 168 { 169 while (1) 170 cpu_sleep(0); 171 } 172 173 174 /* Sync the discs and unmount the filesystems */ 175 176 void 177 bootsync(void) 178 { 179 static int bootsyncdone = 0; 180 181 if (bootsyncdone) return; 182 183 bootsyncdone = 1; 184 185 /* Make sure we can still manage to do things */ 186 if (GetCPSR() & I32_bit) { 187 /* 188 * If we get here then boot has been called without RB_NOSYNC 189 * and interrupts were disabled. This means the boot() call 190 * did not come from a user process e.g. shutdown, but must 191 * have come from somewhere in the kernel. 192 */ 193 IRQenable; 194 printf("Warning IRQ's disabled during boot()\n"); 195 } 196 197 vfs_shutdown(); 198 } 199 200 /* 201 * void cpu_startup(void) 202 * 203 * Machine dependant startup code. 204 * 205 */ 206 void 207 cpu_startup() 208 { 209 paddr_t minaddr; 210 paddr_t maxaddr; 211 caddr_t sysbase; 212 caddr_t size; 213 vsize_t bufsize; 214 u_int loop, base, residual; 215 char pbuf[9]; 216 217 /* Set the cpu control register */ 218 cpu_setup(boot_args); 219 220 /* Lock down zero page */ 221 vector_page_setprot(VM_PROT_READ); 222 223 /* 224 * Give pmap a chance to set up a few more things now the vm 225 * is initialised 226 */ 227 pmap_postinit(); 228 229 /* 230 * Initialize error message buffer (at end of core). 231 */ 232 233 /* msgbufphys was setup during the secondary boot strap */ 234 for (loop = 0; loop < btoc(MSGBUFSIZE); ++loop) 235 pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE, 236 msgbufphys + loop * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE); 237 pmap_update(pmap_kernel()); 238 initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE)); 239 240 /* 241 * Identify ourselves for the msgbuf (everything printed earlier will 242 * not be buffered). 243 */ 244 printf(version); 245 246 format_bytes(pbuf, sizeof(pbuf), arm_ptob(physmem)); 247 printf("total memory = %s\n", pbuf); 248 249 /* 250 * Find out how much space we need, allocate it, 251 * and then give everything true virtual addresses. 252 */ 253 size = allocsys(NULL, NULL); 254 sysbase = (caddr_t)uvm_km_zalloc(kernel_map, round_page((vaddr_t)size)); 255 if (sysbase == 0) 256 panic( 257 "cpu_startup: no room for system tables; %d bytes required", 258 (u_int)size); 259 if ((caddr_t)((allocsys(sysbase, NULL) - sysbase)) != size) 260 panic("cpu_startup: system table size inconsistency"); 261 262 /* 263 * Now allocate buffers proper. They are different than the above 264 * in that they usually occupy more virtual memory than physical. 265 */ 266 bufsize = MAXBSIZE * nbuf; 267 if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(bufsize), 268 NULL, UVM_UNKNOWN_OFFSET, 0, 269 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, 270 UVM_ADV_NORMAL, 0)) != 0) 271 panic("cpu_startup: cannot allocate UVM space for buffers"); 272 minaddr = (vaddr_t)buffers; 273 if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { 274 /* don't want to alloc more physical mem than needed */ 275 bufpages = btoc(MAXBSIZE) * nbuf; 276 } 277 278 base = bufpages / nbuf; 279 residual = bufpages % nbuf; 280 for (loop = 0; loop < nbuf; ++loop) { 281 vsize_t curbufsize; 282 vaddr_t curbuf; 283 struct vm_page *pg; 284 285 /* 286 * Each buffer has MAXBSIZE bytes of VM space allocated. Of 287 * that MAXBSIZE space, we allocate and map (base+1) pages 288 * for the first "residual" buffers, and then we allocate 289 * "base" pages for the rest. 290 */ 291 curbuf = (vaddr_t) buffers + (loop * MAXBSIZE); 292 curbufsize = PAGE_SIZE * ((loop < residual) ? (base+1) : base); 293 294 while (curbufsize) { 295 pg = uvm_pagealloc(NULL, 0, NULL, 0); 296 if (pg == NULL) 297 panic("cpu_startup: not enough memory for buffer cache"); 298 pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), 299 VM_PROT_READ|VM_PROT_WRITE); 300 curbuf += PAGE_SIZE; 301 curbufsize -= PAGE_SIZE; 302 } 303 } 304 pmap_update(pmap_kernel()); 305 306 /* 307 * Allocate a submap for exec arguments. This map effectively 308 * limits the number of processes exec'ing at any time. 309 */ 310 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 311 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 312 313 /* 314 * Allocate a submap for physio 315 */ 316 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 317 VM_PHYS_SIZE, 0, FALSE, NULL); 318 319 /* 320 * Finally, allocate mbuf cluster submap. 321 */ 322 mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 323 nmbclusters * mclbytes, VM_MAP_INTRSAFE, 324 FALSE, NULL); 325 326 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 327 printf("avail memory = %s\n", pbuf); 328 format_bytes(pbuf, sizeof(pbuf), bufpages * PAGE_SIZE); 329 printf("using %u buffers containing %s of memory\n", nbuf, pbuf); 330 331 /* 332 * Set up buffers, so they can be used to read disk labels. 333 */ 334 bufinit(); 335 336 curpcb = &lwp0.l_addr->u_pcb; 337 curpcb->pcb_flags = 0; 338 curpcb->pcb_un.un_32.pcb32_und_sp = (u_int)lwp0.l_addr + 339 USPACE_UNDEF_STACK_TOP; 340 curpcb->pcb_un.un_32.pcb32_sp = (u_int)lwp0.l_addr + 341 USPACE_SVC_STACK_TOP; 342 pmap_set_pcb_pagedir(pmap_kernel(), curpcb); 343 344 curpcb->pcb_tf = (struct trapframe *)curpcb->pcb_un.un_32.pcb32_sp - 1; 345 } 346 347 /* 348 * machine dependent system variables. 349 */ 350 351 int 352 cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 353 int *name; 354 u_int namelen; 355 void *oldp; 356 size_t *oldlenp; 357 void *newp; 358 size_t newlen; 359 struct proc *p; 360 { 361 /* all sysctl names at this level are terminal */ 362 if (namelen != 1) 363 return (ENOTDIR); /* overloaded */ 364 365 switch (name[0]) { 366 case CPU_DEBUG: 367 return(sysctl_int(oldp, oldlenp, newp, newlen, &kernel_debug)); 368 369 case CPU_BOOTED_DEVICE: 370 if (booted_device != NULL) 371 return (sysctl_rdstring(oldp, oldlenp, newp, 372 booted_device->dv_xname)); 373 return (EOPNOTSUPP); 374 375 case CPU_CONSDEV: { 376 dev_t consdev; 377 if (cn_tab != NULL) 378 consdev = cn_tab->cn_dev; 379 else 380 consdev = NODEV; 381 return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, 382 sizeof consdev)); 383 } 384 case CPU_BOOTED_KERNEL: { 385 if (booted_kernel != NULL && booted_kernel[0] != '\0') 386 return sysctl_rdstring(oldp, oldlenp, newp, 387 booted_kernel); 388 return (EOPNOTSUPP); 389 } 390 case CPU_POWERSAVE: { 391 int error, newval; 392 393 newval = cpu_do_powersave; 394 395 if (cpufuncs.cf_sleep == (void *) cpufunc_nullop) 396 error = sysctl_rdint(oldp, oldlenp, newp, newval); 397 else 398 error = sysctl_int(oldp, oldlenp, newp, newlen, 399 &newval); 400 if (error || newval == cpu_do_powersave) 401 return (error); 402 403 if (newval < 0 || newval > 1) 404 return (EINVAL); 405 406 cpu_do_powersave = newval; 407 return (0); 408 } 409 410 default: 411 return (EOPNOTSUPP); 412 } 413 /* NOTREACHED */ 414 } 415 416 void 417 parse_mi_bootargs(args) 418 char *args; 419 { 420 int integer; 421 422 if (get_bootconf_option(args, "single", BOOTOPT_TYPE_BOOLEAN, &integer) 423 || get_bootconf_option(args, "-s", BOOTOPT_TYPE_BOOLEAN, &integer)) 424 if (integer) 425 boothowto |= RB_SINGLE; 426 if (get_bootconf_option(args, "kdb", BOOTOPT_TYPE_BOOLEAN, &integer) 427 || get_bootconf_option(args, "-k", BOOTOPT_TYPE_BOOLEAN, &integer)) 428 if (integer) 429 boothowto |= RB_KDB; 430 if (get_bootconf_option(args, "ask", BOOTOPT_TYPE_BOOLEAN, &integer) 431 || get_bootconf_option(args, "-a", BOOTOPT_TYPE_BOOLEAN, &integer)) 432 if (integer) 433 boothowto |= RB_ASKNAME; 434 435 #ifdef PMAP_DEBUG 436 if (get_bootconf_option(args, "pmapdebug", BOOTOPT_TYPE_INT, &integer)) { 437 pmap_debug_level = integer; 438 pmap_debug(pmap_debug_level); 439 } 440 #endif /* PMAP_DEBUG */ 441 442 /* if (get_bootconf_option(args, "nbuf", BOOTOPT_TYPE_INT, &integer)) 443 bufpages = integer;*/ 444 445 #if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) 446 if (get_bootconf_option(args, "memorydisc", BOOTOPT_TYPE_INT, &integer) 447 || get_bootconf_option(args, "memorydisk", BOOTOPT_TYPE_INT, &integer)) { 448 md_root_size = integer; 449 md_root_size *= 1024; 450 if (md_root_size < 32*1024) 451 md_root_size = 32*1024; 452 if (md_root_size > 2048*1024) 453 md_root_size = 2048*1024; 454 } 455 #endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ 456 457 if (get_bootconf_option(args, "quiet", BOOTOPT_TYPE_BOOLEAN, &integer) 458 || get_bootconf_option(args, "-q", BOOTOPT_TYPE_BOOLEAN, &integer)) 459 if (integer) 460 boothowto |= AB_QUIET; 461 if (get_bootconf_option(args, "verbose", BOOTOPT_TYPE_BOOLEAN, &integer) 462 || get_bootconf_option(args, "-v", BOOTOPT_TYPE_BOOLEAN, &integer)) 463 if (integer) 464 boothowto |= AB_VERBOSE; 465 } 466