1 /* $NetBSD: arm32_machdep.c,v 1.24 2002/05/05 16:26:30 jdolecek 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 int loop; 194 paddr_t minaddr; 195 paddr_t maxaddr; 196 caddr_t sysbase; 197 caddr_t size; 198 vsize_t bufsize; 199 int base, residual; 200 char pbuf[9]; 201 202 proc0paddr = (struct user *)kernelstack.pv_va; 203 proc0.p_addr = proc0paddr; 204 205 /* Set the cpu control register */ 206 cpu_setup(boot_args); 207 208 /* All domains MUST be clients, permissions are VERY important */ 209 cpu_domains(DOMAIN_CLIENT); 210 211 /* Lock down zero page */ 212 vector_page_setprot(VM_PROT_READ); 213 214 /* 215 * Give pmap a chance to set up a few more things now the vm 216 * is initialised 217 */ 218 pmap_postinit(); 219 220 /* 221 * Initialize error message buffer (at end of core). 222 */ 223 224 /* msgbufphys was setup during the secondary boot strap */ 225 for (loop = 0; loop < btoc(MSGBUFSIZE); ++loop) 226 pmap_kenter_pa((vaddr_t)msgbufaddr + loop * NBPG, 227 msgbufphys + loop * NBPG, VM_PROT_READ|VM_PROT_WRITE); 228 pmap_update(pmap_kernel()); 229 initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE)); 230 231 /* 232 * Identify ourselves for the msgbuf (everything printed earlier will 233 * not be buffered). 234 */ 235 printf(version); 236 237 format_bytes(pbuf, sizeof(pbuf), arm_ptob(physmem)); 238 printf("total memory = %s\n", pbuf); 239 240 /* 241 * Find out how much space we need, allocate it, 242 * and then give everything true virtual addresses. 243 */ 244 size = allocsys(NULL, NULL); 245 sysbase = (caddr_t)uvm_km_zalloc(kernel_map, round_page((vaddr_t)size)); 246 if (sysbase == 0) 247 panic( 248 "cpu_startup: no room for system tables; %d bytes required", 249 (u_int)size); 250 if ((caddr_t)((allocsys(sysbase, NULL) - sysbase)) != size) 251 panic("cpu_startup: system table size inconsistency"); 252 253 /* 254 * Now allocate buffers proper. They are different than the above 255 * in that they usually occupy more virtual memory than physical. 256 */ 257 bufsize = MAXBSIZE * nbuf; 258 if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(bufsize), 259 NULL, UVM_UNKNOWN_OFFSET, 0, 260 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, 261 UVM_ADV_NORMAL, 0)) != 0) 262 panic("cpu_startup: cannot allocate UVM space for buffers"); 263 minaddr = (vaddr_t)buffers; 264 if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { 265 /* don't want to alloc more physical mem than needed */ 266 bufpages = btoc(MAXBSIZE) * nbuf; 267 } 268 269 base = bufpages / nbuf; 270 residual = bufpages % nbuf; 271 for (loop = 0; loop < nbuf; ++loop) { 272 vsize_t curbufsize; 273 vaddr_t curbuf; 274 struct vm_page *pg; 275 276 /* 277 * Each buffer has MAXBSIZE bytes of VM space allocated. Of 278 * that MAXBSIZE space, we allocate and map (base+1) pages 279 * for the first "residual" buffers, and then we allocate 280 * "base" pages for the rest. 281 */ 282 curbuf = (vaddr_t) buffers + (loop * MAXBSIZE); 283 curbufsize = NBPG * ((loop < residual) ? (base+1) : base); 284 285 while (curbufsize) { 286 pg = uvm_pagealloc(NULL, 0, NULL, 0); 287 if (pg == NULL) 288 panic("cpu_startup: not enough memory for buffer cache"); 289 pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), 290 VM_PROT_READ|VM_PROT_WRITE); 291 curbuf += PAGE_SIZE; 292 curbufsize -= PAGE_SIZE; 293 } 294 } 295 pmap_update(pmap_kernel()); 296 297 /* 298 * Allocate a submap for exec arguments. This map effectively 299 * limits the number of processes exec'ing at any time. 300 */ 301 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 302 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 303 304 /* 305 * Allocate a submap for physio 306 */ 307 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 308 VM_PHYS_SIZE, 0, FALSE, NULL); 309 310 /* 311 * Finally, allocate mbuf cluster submap. 312 */ 313 mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 314 nmbclusters * mclbytes, VM_MAP_INTRSAFE, 315 FALSE, NULL); 316 317 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 318 printf("avail memory = %s\n", pbuf); 319 format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG); 320 printf("using %d buffers containing %s of memory\n", nbuf, pbuf); 321 322 /* 323 * Set up buffers, so they can be used to read disk labels. 324 */ 325 bufinit(); 326 327 curpcb = &proc0.p_addr->u_pcb; 328 curpcb->pcb_flags = 0; 329 curpcb->pcb_un.un_32.pcb32_und_sp = (u_int)proc0.p_addr + 330 USPACE_UNDEF_STACK_TOP; 331 curpcb->pcb_un.un_32.pcb32_sp = (u_int)proc0.p_addr + 332 USPACE_SVC_STACK_TOP; 333 (void) pmap_extract(pmap_kernel(), (vaddr_t)(pmap_kernel())->pm_pdir, 334 (paddr_t *)&curpcb->pcb_pagedir); 335 336 curpcb->pcb_tf = (struct trapframe *)curpcb->pcb_un.un_32.pcb32_sp - 1; 337 } 338 339 /* 340 * machine dependent system variables. 341 */ 342 343 int 344 cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 345 int *name; 346 u_int namelen; 347 void *oldp; 348 size_t *oldlenp; 349 void *newp; 350 size_t newlen; 351 struct proc *p; 352 { 353 /* all sysctl names at this level are terminal */ 354 if (namelen != 1) 355 return (ENOTDIR); /* overloaded */ 356 357 switch (name[0]) { 358 case CPU_DEBUG: 359 return(sysctl_int(oldp, oldlenp, newp, newlen, &kernel_debug)); 360 361 case CPU_BOOTED_DEVICE: 362 if (booted_device != NULL) 363 return (sysctl_rdstring(oldp, oldlenp, newp, 364 booted_device->dv_xname)); 365 return (EOPNOTSUPP); 366 367 case CPU_CONSDEV: { 368 dev_t consdev; 369 if (cn_tab != NULL) 370 consdev = cn_tab->cn_dev; 371 else 372 consdev = NODEV; 373 return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, 374 sizeof consdev)); 375 } 376 case CPU_BOOTED_KERNEL: { 377 if (booted_kernel != NULL && booted_kernel[0] != '\0') 378 return sysctl_rdstring(oldp, oldlenp, newp, 379 booted_kernel); 380 return (EOPNOTSUPP); 381 } 382 383 default: 384 return (EOPNOTSUPP); 385 } 386 /* NOTREACHED */ 387 } 388 389 void 390 parse_mi_bootargs(args) 391 char *args; 392 { 393 int integer; 394 395 if (get_bootconf_option(args, "single", BOOTOPT_TYPE_BOOLEAN, &integer) 396 || get_bootconf_option(args, "-s", BOOTOPT_TYPE_BOOLEAN, &integer)) 397 if (integer) 398 boothowto |= RB_SINGLE; 399 if (get_bootconf_option(args, "kdb", BOOTOPT_TYPE_BOOLEAN, &integer) 400 || get_bootconf_option(args, "-k", BOOTOPT_TYPE_BOOLEAN, &integer)) 401 if (integer) 402 boothowto |= RB_KDB; 403 if (get_bootconf_option(args, "ask", BOOTOPT_TYPE_BOOLEAN, &integer) 404 || get_bootconf_option(args, "-a", BOOTOPT_TYPE_BOOLEAN, &integer)) 405 if (integer) 406 boothowto |= RB_ASKNAME; 407 408 #ifdef PMAP_DEBUG 409 if (get_bootconf_option(args, "pmapdebug", BOOTOPT_TYPE_INT, &integer)) { 410 pmap_debug_level = integer; 411 pmap_debug(pmap_debug_level); 412 } 413 #endif /* PMAP_DEBUG */ 414 415 /* if (get_bootconf_option(args, "nbuf", BOOTOPT_TYPE_INT, &integer)) 416 bufpages = integer;*/ 417 418 #ifndef PMAP_STATIC_L1S 419 if (get_bootconf_option(args, "maxproc", BOOTOPT_TYPE_INT, &integer)) { 420 max_processes = integer; 421 if (max_processes < 16) 422 max_processes = 16; 423 /* Limit is PDSIZE * (max_processes + 1) <= 4MB */ 424 if (max_processes > 255) 425 max_processes = 255; 426 } 427 #endif /* !PMAP_STATUC_L1S */ 428 #if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE) 429 if (get_bootconf_option(args, "memorydisc", BOOTOPT_TYPE_INT, &integer) 430 || get_bootconf_option(args, "memorydisk", BOOTOPT_TYPE_INT, &integer)) { 431 md_root_size = integer; 432 md_root_size *= 1024; 433 if (md_root_size < 32*1024) 434 md_root_size = 32*1024; 435 if (md_root_size > 2048*1024) 436 md_root_size = 2048*1024; 437 } 438 #endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */ 439 440 if (get_bootconf_option(args, "quiet", BOOTOPT_TYPE_BOOLEAN, &integer) 441 || get_bootconf_option(args, "-q", BOOTOPT_TYPE_BOOLEAN, &integer)) 442 if (integer) 443 boothowto |= AB_QUIET; 444 if (get_bootconf_option(args, "verbose", BOOTOPT_TYPE_BOOLEAN, &integer) 445 || get_bootconf_option(args, "-v", BOOTOPT_TYPE_BOOLEAN, &integer)) 446 if (integer) 447 boothowto |= AB_VERBOSE; 448 } 449