1129198Scognet/* $NetBSD: arm32_machdep.c,v 1.44 2004/03/24 15:34:47 atatat Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 2004 Olivier Houchard 5129198Scognet * Copyright (c) 1994-1998 Mark Brinicombe. 6129198Scognet * Copyright (c) 1994 Brini. 7129198Scognet * All rights reserved. 8129198Scognet * 9129198Scognet * This code is derived from software written for Brini by Mark Brinicombe 10129198Scognet * 11129198Scognet * Redistribution and use in source and binary forms, with or without 12129198Scognet * modification, are permitted provided that the following conditions 13129198Scognet * are met: 14129198Scognet * 1. Redistributions of source code must retain the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer. 16129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 17129198Scognet * notice, this list of conditions and the following disclaimer in the 18129198Scognet * documentation and/or other materials provided with the distribution. 19129198Scognet * 3. All advertising materials mentioning features or use of this software 20129198Scognet * must display the following acknowledgement: 21129198Scognet * This product includes software developed by Mark Brinicombe 22129198Scognet * for the NetBSD Project. 23129198Scognet * 4. The name of the company nor the name of the author may be used to 24129198Scognet * endorse or promote products derived from this software without specific 25129198Scognet * prior written permission. 26129198Scognet * 27129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 28129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 29129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30129198Scognet * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 31129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37129198Scognet * SUCH DAMAGE. 38129198Scognet * 39299069Spfg * Machine dependent functions for kernel setup 40129198Scognet * 41129198Scognet * Created : 17/09/94 42129198Scognet * Updated : 18/04/01 updated for new wscons 43129198Scognet */ 44129198Scognet 45129198Scognet#include "opt_compat.h" 46177883Simp#include "opt_ddb.h" 47285627Szbb#include "opt_kstack_pages.h" 48242531Sandrew#include "opt_platform.h" 49247195Smav#include "opt_sched.h" 50239268Sgonzo#include "opt_timer.h" 51177883Simp 52129198Scognet#include <sys/cdefs.h> 53129198Scognet__FBSDID("$FreeBSD: stable/11/sys/arm/arm/machdep.c 355346 2019-12-03 18:28:39Z kevans $"); 54129198Scognet 55129198Scognet#include <sys/param.h> 56141249Snjl#include <sys/buf.h> 57141249Snjl#include <sys/bus.h> 58141378Snjl#include <sys/cons.h> 59141237Snjl#include <sys/cpu.h> 60298627Sbr#include <sys/devmap.h> 61283426Sandrew#include <sys/efi.h> 62129198Scognet#include <sys/imgact.h> 63242531Sandrew#include <sys/kdb.h> 64129198Scognet#include <sys/kernel.h> 65129198Scognet#include <sys/linker.h> 66242531Sandrew#include <sys/msgbuf.h> 67331524Sian#include <sys/reboot.h> 68248084Sattilio#include <sys/rwlock.h> 69247195Smav#include <sys/sched.h> 70209613Sjhb#include <sys/syscallsubr.h> 71135653Scognet#include <sys/sysent.h> 72141378Snjl#include <sys/sysproto.h> 73331017Skevans#include <sys/vmmeter.h> 74129198Scognet 75129198Scognet#include <vm/vm_object.h> 76129198Scognet#include <vm/vm_page.h> 77129198Scognet#include <vm/vm_pager.h> 78141378Snjl 79294740Szbb#include <machine/debug_monitor.h> 80141378Snjl#include <machine/machdep.h> 81141378Snjl#include <machine/metadata.h> 82141378Snjl#include <machine/pcb.h> 83261643Sian#include <machine/physmem.h> 84266301Sandrew#include <machine/platform.h> 85317004Smmel#include <machine/sysarch.h> 86141378Snjl#include <machine/undefined.h> 87263913Sandrew#include <machine/vfp.h> 88129198Scognet#include <machine/vmparam.h> 89129198Scognet 90242531Sandrew#ifdef FDT 91242531Sandrew#include <dev/fdt/fdt_common.h> 92317004Smmel#include <machine/ofw_machdep.h> 93242531Sandrew#endif 94242531Sandrew 95242531Sandrew#ifdef DEBUG 96242531Sandrew#define debugf(fmt, args...) printf(fmt, ##args) 97242531Sandrew#else 98242531Sandrew#define debugf(fmt, args...) 99242531Sandrew#endif 100242531Sandrew 101296981Sandrew#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 102296981Sandrew defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) || \ 103296981Sandrew defined(COMPAT_FREEBSD9) 104296981Sandrew#error FreeBSD/arm doesn't provide compatibility with releases prior to 10 105296981Sandrew#endif 106296981Sandrew 107239268Sgonzostruct pcpu __pcpu[MAXCPU]; 108239268Sgonzostruct pcpu *pcpup = &__pcpu[0]; 109239268Sgonzo 110236828Sandrewstatic struct trapframe proc0_tf; 111129198Scognetuint32_t cpu_reset_address = 0; 112129198Scognetint cold = 1; 113129198Scognetvm_offset_t vector_page; 114129198Scognet 115150870Scognetint (*_arm_memcpy)(void *, void *, int, int) = NULL; 116150870Scognetint (*_arm_bzero)(void *, int, int) = NULL; 117150870Scognetint _min_memcpy_size = 0; 118150870Scognetint _min_bzero_size = 0; 119150870Scognet 120177883Simpextern int *end; 121177883Simp 122242531Sandrew#ifdef FDT 123280712Sianvm_paddr_t pmap_pa; 124295036Smmel#if __ARM_ARCH >= 6 125280712Sianvm_offset_t systempage; 126280712Sianvm_offset_t irqstack; 127280712Sianvm_offset_t undstack; 128280712Sianvm_offset_t abtstack; 129280712Sian#else 130242531Sandrew/* 131242531Sandrew * This is the number of L2 page tables required for covering max 132242531Sandrew * (hypothetical) memsize of 4GB and all kernel mappings (vectors, msgbuf, 133242531Sandrew * stacks etc.), uprounded to be divisible by 4. 134242531Sandrew */ 135242531Sandrew#define KERNEL_PT_MAX 78 136242531Sandrewstatic struct pv_addr kernel_pt_table[KERNEL_PT_MAX]; 137242531Sandrewstruct pv_addr systempage; 138242531Sandrewstatic struct pv_addr msgbufpv; 139242531Sandrewstruct pv_addr irqstack; 140242531Sandrewstruct pv_addr undstack; 141242531Sandrewstruct pv_addr abtstack; 142242531Sandrewstatic struct pv_addr kernelstack; 143317004Smmel#endif /* __ARM_ARCH >= 6 */ 144317004Smmel#endif /* FDT */ 145242531Sandrew 146298854Sandrew#ifdef MULTIDELAY 147298854Sandrewstatic delay_func *delay_impl; 148298854Sandrewstatic void *delay_arg; 149298854Sandrew#endif 150237044Simp 151129198Scognetstruct kva_md_info kmi; 152129198Scognet 153129198Scognet/* 154129198Scognet * arm32_vector_init: 155129198Scognet * 156129198Scognet * Initialize the vector page, and select whether or not to 157129198Scognet * relocate the vectors. 158129198Scognet * 159129198Scognet * NOTE: We expect the vector page to be mapped at its expected 160129198Scognet * destination. 161129198Scognet */ 162129198Scognet 163129198Scognetextern unsigned int page0[], page0_data[]; 164129198Scognetvoid 165129198Scognetarm_vector_init(vm_offset_t va, int which) 166129198Scognet{ 167129198Scognet unsigned int *vectors = (int *) va; 168129198Scognet unsigned int *vectors_data = vectors + (page0_data - page0); 169129198Scognet int vec; 170129198Scognet 171129198Scognet /* 172129198Scognet * Loop through the vectors we're taking over, and copy the 173129198Scognet * vector's insn and data word. 174129198Scognet */ 175129198Scognet for (vec = 0; vec < ARM_NVEC; vec++) { 176129198Scognet if ((which & (1 << vec)) == 0) { 177129198Scognet /* Don't want to take over this vector. */ 178129198Scognet continue; 179129198Scognet } 180129198Scognet vectors[vec] = page0[vec]; 181129198Scognet vectors_data[vec] = page0_data[vec]; 182129198Scognet } 183129198Scognet 184129198Scognet /* Now sync the vectors. */ 185295319Smmel icache_sync(va, (ARM_NVEC * 2) * sizeof(u_int)); 186129198Scognet 187129198Scognet vector_page = va; 188317003Smmel#if __ARM_ARCH < 6 189129198Scognet if (va == ARM_VECTORS_HIGH) { 190129198Scognet /* 191300533Sian * Enable high vectors in the system control reg (SCTLR). 192129198Scognet * 193300533Sian * Assume the MD caller knows what it's doing here, and really 194300533Sian * does want the vector page relocated. 195300533Sian * 196129198Scognet * Note: This has to be done here (and not just in 197129198Scognet * cpu_setup()) because the vector page needs to be 198129198Scognet * accessible *before* cpu_startup() is called. 199129198Scognet * Think ddb(9) ... 200129198Scognet */ 201129198Scognet cpu_control(CPU_CONTROL_VECRELOC, CPU_CONTROL_VECRELOC); 202129198Scognet } 203317003Smmel#endif 204129198Scognet} 205129198Scognet 206129198Scognetstatic void 207129198Scognetcpu_startup(void *dummy) 208129198Scognet{ 209129198Scognet struct pcb *pcb = thread0.td_pcb; 210261643Sian const unsigned int mbyte = 1024 * 1024; 211295068Smmel#if __ARM_ARCH < 6 && !defined(ARM_CACHE_LOCK_ENABLE) 212142570Scognet vm_page_t m; 213142570Scognet#endif 214137215Scognet 215158590Sbenno identify_arm_cpu(); 216158590Sbenno 217261643Sian vm_ksubmap_init(&kmi); 218158590Sbenno 219158590Sbenno /* 220158590Sbenno * Display the RAM layout. 221158590Sbenno */ 222283366Sandrew printf("real memory = %ju (%ju MB)\n", 223261643Sian (uintmax_t)arm32_ptob(realmem), 224261643Sian (uintmax_t)arm32_ptob(realmem) / mbyte); 225261643Sian printf("avail memory = %ju (%ju MB)\n", 226263620Sbdrewery (uintmax_t)arm32_ptob(vm_cnt.v_free_count), 227263620Sbdrewery (uintmax_t)arm32_ptob(vm_cnt.v_free_count) / mbyte); 228158590Sbenno if (bootverbose) { 229261643Sian arm_physmem_print_tables(); 230298627Sbr devmap_print_table(); 231158590Sbenno } 232158590Sbenno 233129198Scognet bufinit(); 234129198Scognet vm_pager_bufferinit(); 235276190Sian pcb->pcb_regs.sf_sp = (u_int)thread0.td_kstack + 236129198Scognet USPACE_SVC_STACK_TOP; 237295042Sskra pmap_set_pcb_pagedir(kernel_pmap, pcb); 238295068Smmel#if __ARM_ARCH < 6 239129198Scognet vector_page_setprot(VM_PROT_READ); 240152128Scognet pmap_postinit(); 241142570Scognet#ifdef ARM_CACHE_LOCK_ENABLE 242142570Scognet pmap_kenter_user(ARM_TP_ADDRESS, ARM_TP_ADDRESS); 243142570Scognet arm_lock_cache_line(ARM_TP_ADDRESS); 244142570Scognet#else 245142570Scognet m = vm_page_alloc(NULL, 0, VM_ALLOC_NOOBJ | VM_ALLOC_ZERO); 246142570Scognet pmap_kenter_user(ARM_TP_ADDRESS, VM_PAGE_TO_PHYS(m)); 247142570Scognet#endif 248226441Scognet *(uint32_t *)ARM_RAS_START = 0; 249226441Scognet *(uint32_t *)ARM_RAS_END = 0xffffffff; 250239268Sgonzo#endif 251129198Scognet} 252129198Scognet 253177253SrwatsonSYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); 254129198Scognet 255192323Smarcel/* 256192323Smarcel * Flush the D-cache for non-DMA I/O so that the I-cache can 257192323Smarcel * be made coherent later. 258192323Smarcel */ 259192323Smarcelvoid 260192323Smarcelcpu_flush_dcache(void *ptr, size_t len) 261192323Smarcel{ 262192323Smarcel 263295319Smmel dcache_wb_poc((vm_offset_t)ptr, (vm_paddr_t)vtophys(ptr), len); 264192323Smarcel} 265192323Smarcel 266141237Snjl/* Get current clock frequency for the given cpu id. */ 267141237Snjlint 268141237Snjlcpu_est_clockrate(int cpu_id, uint64_t *rate) 269141237Snjl{ 270141237Snjl 271141237Snjl return (ENXIO); 272141237Snjl} 273141237Snjl 274129198Scognetvoid 275178471Sjeffcpu_idle(int busy) 276129198Scognet{ 277283366Sandrew 278265914Sian CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", busy, curcpu); 279265913Sian spinlock_enter(); 280239268Sgonzo#ifndef NO_EVENTTIMERS 281265914Sian if (!busy) 282239268Sgonzo cpu_idleclock(); 283239268Sgonzo#endif 284247195Smav if (!sched_runnable()) 285247195Smav cpu_sleep(0); 286239268Sgonzo#ifndef NO_EVENTTIMERS 287265914Sian if (!busy) 288239268Sgonzo cpu_activeclock(); 289239268Sgonzo#endif 290265913Sian spinlock_exit(); 291265914Sian CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", busy, curcpu); 292129198Scognet} 293129198Scognet 294129198Scognetint 295178471Sjeffcpu_idle_wakeup(int cpu) 296178471Sjeff{ 297178471Sjeff 298178471Sjeff return (0); 299178471Sjeff} 300178471Sjeff 301262534Sian/* 302262534Sian * Most ARM platforms don't need to do anything special to init their clocks 303262534Sian * (they get intialized during normal device attachment), and by not defining a 304262534Sian * cpu_initclocks() function they get this generic one. Any platform that needs 305262534Sian * to do something special can just provide their own implementation, which will 306262534Sian * override this one due to the weak linkage. 307262534Sian */ 308262534Sianvoid 309262534Sianarm_generic_initclocks(void) 310262534Sian{ 311262534Sian 312262534Sian#ifndef NO_EVENTTIMERS 313262534Sian#ifdef SMP 314262534Sian if (PCPU_GET(cpuid) == 0) 315262534Sian cpu_initclocks_bsp(); 316262534Sian else 317262534Sian cpu_initclocks_ap(); 318262534Sian#else 319262534Sian cpu_initclocks_bsp(); 320262534Sian#endif 321262534Sian#endif 322262534Sian} 323262534Sian__weak_reference(arm_generic_initclocks, cpu_initclocks); 324262534Sian 325298854Sandrew#ifdef MULTIDELAY 326298854Sandrewvoid 327298854Sandrewarm_set_delay(delay_func *impl, void *arg) 328298854Sandrew{ 329298854Sandrew 330298854Sandrew KASSERT(impl != NULL, ("No DELAY implementation")); 331298854Sandrew delay_impl = impl; 332298854Sandrew delay_arg = arg; 333298854Sandrew} 334298854Sandrew 335298854Sandrewvoid 336298854SandrewDELAY(int usec) 337298854Sandrew{ 338298854Sandrew 339298854Sandrew delay_impl(usec, delay_arg); 340298854Sandrew} 341298854Sandrew#endif 342298854Sandrew 343129198Scognetvoid 344129198Scognetcpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) 345129198Scognet{ 346129198Scognet} 347129198Scognet 348144637Sjhbvoid 349144637Sjhbspinlock_enter(void) 350144637Sjhb{ 351144637Sjhb struct thread *td; 352214835Sjhb register_t cspr; 353144637Sjhb 354144637Sjhb td = curthread; 355214835Sjhb if (td->td_md.md_spinlock_count == 0) { 356271398Sandrew cspr = disable_interrupts(PSR_I | PSR_F); 357214835Sjhb td->td_md.md_spinlock_count = 1; 358214835Sjhb td->td_md.md_saved_cspr = cspr; 359214835Sjhb } else 360214835Sjhb td->td_md.md_spinlock_count++; 361144637Sjhb critical_enter(); 362144637Sjhb} 363144637Sjhb 364144637Sjhbvoid 365144637Sjhbspinlock_exit(void) 366144637Sjhb{ 367144637Sjhb struct thread *td; 368214835Sjhb register_t cspr; 369144637Sjhb 370144637Sjhb td = curthread; 371144637Sjhb critical_exit(); 372214835Sjhb cspr = td->td_md.md_saved_cspr; 373144637Sjhb td->td_md.md_spinlock_count--; 374144637Sjhb if (td->td_md.md_spinlock_count == 0) 375214835Sjhb restore_interrupts(cspr); 376144637Sjhb} 377144637Sjhb 378129198Scognet/* 379129198Scognet * Clear registers on exec 380129198Scognet */ 381129198Scognetvoid 382205642Snwhitehornexec_setregs(struct thread *td, struct image_params *imgp, u_long stack) 383129198Scognet{ 384129198Scognet struct trapframe *tf = td->td_frame; 385129198Scognet 386129198Scognet memset(tf, 0, sizeof(*tf)); 387129198Scognet tf->tf_usr_sp = stack; 388205642Snwhitehorn tf->tf_usr_lr = imgp->entry_addr; 389129198Scognet tf->tf_svc_lr = 0x77777777; 390205642Snwhitehorn tf->tf_pc = imgp->entry_addr; 391129198Scognet tf->tf_spsr = PSR_USR32_MODE; 392129198Scognet} 393129198Scognet 394317005Smmel 395317005Smmel#ifdef VFP 396129198Scognet/* 397317005Smmel * Get machine VFP context. 398317005Smmel */ 399325831Sjhbvoid 400317005Smmelget_vfpcontext(struct thread *td, mcontext_vfp_t *vfp) 401317005Smmel{ 402325831Sjhb struct pcb *pcb; 403317005Smmel 404325831Sjhb pcb = td->td_pcb; 405325831Sjhb if (td == curthread) { 406325831Sjhb critical_enter(); 407325831Sjhb vfp_store(&pcb->pcb_vfpstate, false); 408325831Sjhb critical_exit(); 409325831Sjhb } else 410325831Sjhb MPASS(TD_IS_SUSPENDED(td)); 411325831Sjhb memcpy(vfp->mcv_reg, pcb->pcb_vfpstate.reg, 412317005Smmel sizeof(vfp->mcv_reg)); 413325831Sjhb vfp->mcv_fpscr = pcb->pcb_vfpstate.fpscr; 414317005Smmel} 415317005Smmel 416317005Smmel/* 417317005Smmel * Set machine VFP context. 418317005Smmel */ 419325831Sjhbvoid 420317005Smmelset_vfpcontext(struct thread *td, mcontext_vfp_t *vfp) 421317005Smmel{ 422325831Sjhb struct pcb *pcb; 423317005Smmel 424325831Sjhb pcb = td->td_pcb; 425325831Sjhb if (td == curthread) { 426325831Sjhb critical_enter(); 427325831Sjhb vfp_discard(td); 428325831Sjhb critical_exit(); 429325831Sjhb } else 430325831Sjhb MPASS(TD_IS_SUSPENDED(td)); 431325831Sjhb memcpy(pcb->pcb_vfpstate.reg, vfp->mcv_reg, 432325831Sjhb sizeof(pcb->pcb_vfpstate.reg)); 433325831Sjhb pcb->pcb_vfpstate.fpscr = vfp->mcv_fpscr; 434317005Smmel} 435317005Smmel#endif 436317005Smmel 437325307Smmelint 438325307Smmelarm_get_vfpstate(struct thread *td, void *args) 439325307Smmel{ 440325307Smmel int rv; 441325307Smmel struct arm_get_vfpstate_args ua; 442325307Smmel mcontext_vfp_t mcontext_vfp; 443325307Smmel 444325307Smmel rv = copyin(args, &ua, sizeof(ua)); 445325307Smmel if (rv != 0) 446325307Smmel return (rv); 447325307Smmel if (ua.mc_vfp_size != sizeof(mcontext_vfp_t)) 448325307Smmel return (EINVAL); 449325307Smmel#ifdef VFP 450325307Smmel get_vfpcontext(td, &mcontext_vfp); 451325307Smmel#else 452325307Smmel bzero(&mcontext_vfp, sizeof(mcontext_vfp)); 453325307Smmel#endif 454325307Smmel 455325307Smmel rv = copyout(&mcontext_vfp, ua.mc_vfp, sizeof(mcontext_vfp)); 456325307Smmel if (rv != 0) 457325307Smmel return (rv); 458325307Smmel return (0); 459325307Smmel} 460325307Smmel 461317005Smmel/* 462129198Scognet * Get machine context. 463129198Scognet */ 464129198Scognetint 465129198Scognetget_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret) 466129198Scognet{ 467129198Scognet struct trapframe *tf = td->td_frame; 468129198Scognet __greg_t *gr = mcp->__gregs; 469129198Scognet 470283887Sandrew if (clear_ret & GET_MC_CLEAR_RET) { 471137215Scognet gr[_REG_R0] = 0; 472283887Sandrew gr[_REG_CPSR] = tf->tf_spsr & ~PSR_C; 473283887Sandrew } else { 474137215Scognet gr[_REG_R0] = tf->tf_r0; 475283887Sandrew gr[_REG_CPSR] = tf->tf_spsr; 476283887Sandrew } 477129198Scognet gr[_REG_R1] = tf->tf_r1; 478129198Scognet gr[_REG_R2] = tf->tf_r2; 479129198Scognet gr[_REG_R3] = tf->tf_r3; 480129198Scognet gr[_REG_R4] = tf->tf_r4; 481129198Scognet gr[_REG_R5] = tf->tf_r5; 482129198Scognet gr[_REG_R6] = tf->tf_r6; 483129198Scognet gr[_REG_R7] = tf->tf_r7; 484129198Scognet gr[_REG_R8] = tf->tf_r8; 485129198Scognet gr[_REG_R9] = tf->tf_r9; 486129198Scognet gr[_REG_R10] = tf->tf_r10; 487129198Scognet gr[_REG_R11] = tf->tf_r11; 488129198Scognet gr[_REG_R12] = tf->tf_r12; 489129198Scognet gr[_REG_SP] = tf->tf_usr_sp; 490129198Scognet gr[_REG_LR] = tf->tf_usr_lr; 491129198Scognet gr[_REG_PC] = tf->tf_pc; 492129198Scognet 493317005Smmel mcp->mc_vfp_size = 0; 494317005Smmel mcp->mc_vfp_ptr = NULL; 495317005Smmel memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare)); 496317005Smmel 497129198Scognet return (0); 498129198Scognet} 499129198Scognet 500129198Scognet/* 501129198Scognet * Set machine context. 502129198Scognet * 503129198Scognet * However, we don't set any but the user modifiable flags, and we won't 504129198Scognet * touch the cs selector. 505129198Scognet */ 506129198Scognetint 507278001Skibset_mcontext(struct thread *td, mcontext_t *mcp) 508129198Scognet{ 509317005Smmel mcontext_vfp_t mc_vfp, *vfp; 510137215Scognet struct trapframe *tf = td->td_frame; 511169764Scognet const __greg_t *gr = mcp->__gregs; 512326313Sandrew int spsr; 513137215Scognet 514326313Sandrew /* 515326313Sandrew * Make sure the processor mode has not been tampered with and 516326313Sandrew * interrupts have not been disabled. 517326313Sandrew */ 518326313Sandrew spsr = gr[_REG_CPSR]; 519326313Sandrew if ((spsr & PSR_MODE) != PSR_USR32_MODE || 520326313Sandrew (spsr & (PSR_I | PSR_F)) != 0) 521326313Sandrew return (EINVAL); 522326313Sandrew 523317005Smmel#ifdef WITNESS 524317005Smmel if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(mc_vfp)) { 525317005Smmel printf("%s: %s: Malformed mc_vfp_size: %d (0x%08X)\n", 526317005Smmel td->td_proc->p_comm, __func__, 527317005Smmel mcp->mc_vfp_size, mcp->mc_vfp_size); 528317005Smmel } else if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr == NULL) { 529317005Smmel printf("%s: %s: c_vfp_size != 0 but mc_vfp_ptr == NULL\n", 530317005Smmel td->td_proc->p_comm, __func__); 531317005Smmel } 532317005Smmel#endif 533317005Smmel 534317005Smmel if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != NULL) { 535317005Smmel if (copyin(mcp->mc_vfp_ptr, &mc_vfp, sizeof(mc_vfp)) != 0) 536317005Smmel return (EFAULT); 537317005Smmel vfp = &mc_vfp; 538317005Smmel } else { 539317005Smmel vfp = NULL; 540317005Smmel } 541317005Smmel 542137215Scognet tf->tf_r0 = gr[_REG_R0]; 543137215Scognet tf->tf_r1 = gr[_REG_R1]; 544137215Scognet tf->tf_r2 = gr[_REG_R2]; 545137215Scognet tf->tf_r3 = gr[_REG_R3]; 546137215Scognet tf->tf_r4 = gr[_REG_R4]; 547137215Scognet tf->tf_r5 = gr[_REG_R5]; 548137215Scognet tf->tf_r6 = gr[_REG_R6]; 549137215Scognet tf->tf_r7 = gr[_REG_R7]; 550137215Scognet tf->tf_r8 = gr[_REG_R8]; 551137215Scognet tf->tf_r9 = gr[_REG_R9]; 552137215Scognet tf->tf_r10 = gr[_REG_R10]; 553137215Scognet tf->tf_r11 = gr[_REG_R11]; 554137215Scognet tf->tf_r12 = gr[_REG_R12]; 555137215Scognet tf->tf_usr_sp = gr[_REG_SP]; 556137215Scognet tf->tf_usr_lr = gr[_REG_LR]; 557137215Scognet tf->tf_pc = gr[_REG_PC]; 558137215Scognet tf->tf_spsr = gr[_REG_CPSR]; 559317005Smmel#ifdef VFP 560317005Smmel if (vfp != NULL) 561317005Smmel set_vfpcontext(td, vfp); 562317005Smmel#endif 563129198Scognet return (0); 564129198Scognet} 565129198Scognet 566317005Smmelvoid 567317005Smmelsendsig(catcher, ksi, mask) 568317005Smmel sig_t catcher; 569317005Smmel ksiginfo_t *ksi; 570317005Smmel sigset_t *mask; 571317005Smmel{ 572317005Smmel struct thread *td; 573317005Smmel struct proc *p; 574317005Smmel struct trapframe *tf; 575317005Smmel struct sigframe *fp, frame; 576317005Smmel struct sigacts *psp; 577317005Smmel struct sysentvec *sysent; 578317005Smmel int onstack; 579317005Smmel int sig; 580317005Smmel int code; 581317005Smmel 582317005Smmel td = curthread; 583317005Smmel p = td->td_proc; 584317005Smmel PROC_LOCK_ASSERT(p, MA_OWNED); 585317005Smmel sig = ksi->ksi_signo; 586317005Smmel code = ksi->ksi_code; 587317005Smmel psp = p->p_sigacts; 588317005Smmel mtx_assert(&psp->ps_mtx, MA_OWNED); 589317005Smmel tf = td->td_frame; 590317005Smmel onstack = sigonstack(tf->tf_usr_sp); 591317005Smmel 592317005Smmel CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, 593317005Smmel catcher, sig); 594317005Smmel 595317005Smmel /* Allocate and validate space for the signal handler context. */ 596317005Smmel if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) && 597317005Smmel SIGISMEMBER(psp->ps_sigonstack, sig)) { 598317005Smmel fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp + 599317005Smmel td->td_sigstk.ss_size); 600317005Smmel#if defined(COMPAT_43) 601317005Smmel td->td_sigstk.ss_flags |= SS_ONSTACK; 602317005Smmel#endif 603317005Smmel } else 604317005Smmel fp = (struct sigframe *)td->td_frame->tf_usr_sp; 605317005Smmel 606317005Smmel /* make room on the stack */ 607317005Smmel fp--; 608317005Smmel 609317005Smmel /* make the stack aligned */ 610317005Smmel fp = (struct sigframe *)STACKALIGN(fp); 611317005Smmel /* Populate the siginfo frame. */ 612341166Svangyzen bzero(&frame, sizeof(frame)); 613317005Smmel get_mcontext(td, &frame.sf_uc.uc_mcontext, 0); 614317005Smmel#ifdef VFP 615317005Smmel get_vfpcontext(td, &frame.sf_vfp); 616317005Smmel frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp); 617317005Smmel frame.sf_uc.uc_mcontext.mc_vfp_ptr = &fp->sf_vfp; 618317005Smmel#else 619317005Smmel frame.sf_uc.uc_mcontext.mc_vfp_size = 0; 620317005Smmel frame.sf_uc.uc_mcontext.mc_vfp_ptr = NULL; 621317005Smmel#endif 622317005Smmel frame.sf_si = ksi->ksi_info; 623317005Smmel frame.sf_uc.uc_sigmask = *mask; 624317005Smmel frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK ) 625317005Smmel ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE; 626317005Smmel frame.sf_uc.uc_stack = td->td_sigstk; 627317005Smmel mtx_unlock(&psp->ps_mtx); 628317005Smmel PROC_UNLOCK(td->td_proc); 629317005Smmel 630317005Smmel /* Copy the sigframe out to the user's stack. */ 631317005Smmel if (copyout(&frame, fp, sizeof(*fp)) != 0) { 632317005Smmel /* Process has trashed its stack. Kill it. */ 633317005Smmel CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); 634317005Smmel PROC_LOCK(p); 635317005Smmel sigexit(td, SIGILL); 636317005Smmel } 637317005Smmel 638317005Smmel /* 639317005Smmel * Build context to run handler in. We invoke the handler 640317005Smmel * directly, only returning via the trampoline. Note the 641317005Smmel * trampoline version numbers are coordinated with machine- 642317005Smmel * dependent code in libc. 643317005Smmel */ 644317005Smmel 645317005Smmel tf->tf_r0 = sig; 646317005Smmel tf->tf_r1 = (register_t)&fp->sf_si; 647317005Smmel tf->tf_r2 = (register_t)&fp->sf_uc; 648317005Smmel 649317005Smmel /* the trampoline uses r5 as the uc address */ 650317005Smmel tf->tf_r5 = (register_t)&fp->sf_uc; 651317005Smmel tf->tf_pc = (register_t)catcher; 652317005Smmel tf->tf_usr_sp = (register_t)fp; 653317005Smmel sysent = p->p_sysent; 654317005Smmel if (sysent->sv_sigcode_base != 0) 655317005Smmel tf->tf_usr_lr = (register_t)sysent->sv_sigcode_base; 656317005Smmel else 657317005Smmel tf->tf_usr_lr = (register_t)(sysent->sv_psstrings - 658317005Smmel *(sysent->sv_szsigcode)); 659317005Smmel /* Set the mode to enter in the signal handler */ 660317005Smmel#if __ARM_ARCH >= 7 661317005Smmel if ((register_t)catcher & 1) 662317005Smmel tf->tf_spsr |= PSR_T; 663317005Smmel else 664317005Smmel tf->tf_spsr &= ~PSR_T; 665317005Smmel#endif 666317005Smmel 667317005Smmel CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr, 668317005Smmel tf->tf_usr_sp); 669317005Smmel 670317005Smmel PROC_LOCK(p); 671317005Smmel mtx_lock(&psp->ps_mtx); 672317005Smmel} 673317005Smmel 674129198Scognetint 675225617Skmacysys_sigreturn(td, uap) 676129198Scognet struct thread *td; 677129198Scognet struct sigreturn_args /* { 678152753Sru const struct __ucontext *sigcntxp; 679129198Scognet } */ *uap; 680129198Scognet{ 681262903Sian ucontext_t uc; 682326313Sandrew int error; 683283366Sandrew 684135653Scognet if (uap == NULL) 685135653Scognet return (EFAULT); 686262903Sian if (copyin(uap->sigcntxp, &uc, sizeof(uc))) 687135653Scognet return (EFAULT); 688317005Smmel /* Restore register context. */ 689326313Sandrew error = set_mcontext(td, &uc.uc_mcontext); 690326313Sandrew if (error != 0) 691326313Sandrew return (error); 692135653Scognet 693135653Scognet /* Restore signal mask. */ 694262903Sian kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); 695135653Scognet 696135653Scognet return (EJUSTRETURN); 697129198Scognet} 698129198Scognet 699132054Scognet/* 700132054Scognet * Construct a PCB from a trapframe. This is called from kdb_trap() where 701132054Scognet * we want to start a backtrace from the function that caused us to enter 702132054Scognet * the debugger. We have the context in the trapframe, but base the trace 703132054Scognet * on the PCB. The PCB doesn't have to be perfect, as long as it contains 704132054Scognet * enough for a backtrace. 705132054Scognet */ 706132054Scognetvoid 707132054Scognetmakectx(struct trapframe *tf, struct pcb *pcb) 708132054Scognet{ 709276190Sian pcb->pcb_regs.sf_r4 = tf->tf_r4; 710276190Sian pcb->pcb_regs.sf_r5 = tf->tf_r5; 711276190Sian pcb->pcb_regs.sf_r6 = tf->tf_r6; 712276190Sian pcb->pcb_regs.sf_r7 = tf->tf_r7; 713276190Sian pcb->pcb_regs.sf_r8 = tf->tf_r8; 714276190Sian pcb->pcb_regs.sf_r9 = tf->tf_r9; 715276190Sian pcb->pcb_regs.sf_r10 = tf->tf_r10; 716276190Sian pcb->pcb_regs.sf_r11 = tf->tf_r11; 717276190Sian pcb->pcb_regs.sf_r12 = tf->tf_r12; 718276190Sian pcb->pcb_regs.sf_pc = tf->tf_pc; 719276190Sian pcb->pcb_regs.sf_lr = tf->tf_usr_lr; 720276190Sian pcb->pcb_regs.sf_sp = tf->tf_usr_sp; 721132054Scognet} 722177883Simp 723239268Sgonzovoid 724239268Sgonzopcpu0_init(void) 725239268Sgonzo{ 726284264Sandrew#if __ARM_ARCH >= 6 727261415Scognet set_curthread(&thread0); 728239268Sgonzo#endif 729239268Sgonzo pcpu_init(pcpup, 0, sizeof(struct pcpu)); 730239268Sgonzo PCPU_SET(curthread, &thread0); 731239268Sgonzo} 732239268Sgonzo 733236828Sandrew/* 734236828Sandrew * Initialize proc0 735236828Sandrew */ 736236828Sandrewvoid 737236828Sandrewinit_proc0(vm_offset_t kstack) 738236828Sandrew{ 739236828Sandrew proc_linkup0(&proc0, &thread0); 740236828Sandrew thread0.td_kstack = kstack; 741236828Sandrew thread0.td_pcb = (struct pcb *) 742286584Skib (thread0.td_kstack + kstack_pages * PAGE_SIZE) - 1; 743236828Sandrew thread0.td_pcb->pcb_flags = 0; 744262949Sian thread0.td_pcb->pcb_vfpcpu = -1; 745288492Skib thread0.td_pcb->pcb_vfpstate.fpscr = VFPSCR_DN; 746236828Sandrew thread0.td_frame = &proc0_tf; 747236828Sandrew pcpup->pc_curpcb = thread0.td_pcb; 748236828Sandrew} 749240802Sandrew 750295036Smmel#if __ARM_ARCH >= 6 751240802Sandrewvoid 752240802Sandrewset_stackptrs(int cpu) 753240802Sandrew{ 754240802Sandrew 755240802Sandrew set_stackptr(PSR_IRQ32_MODE, 756280712Sian irqstack + ((IRQ_STACK_SIZE * PAGE_SIZE) * (cpu + 1))); 757280712Sian set_stackptr(PSR_ABT32_MODE, 758280712Sian abtstack + ((ABT_STACK_SIZE * PAGE_SIZE) * (cpu + 1))); 759280712Sian set_stackptr(PSR_UND32_MODE, 760280712Sian undstack + ((UND_STACK_SIZE * PAGE_SIZE) * (cpu + 1))); 761280712Sian} 762280712Sian#else 763280712Sianvoid 764280712Sianset_stackptrs(int cpu) 765280712Sian{ 766280712Sian 767280712Sian set_stackptr(PSR_IRQ32_MODE, 768240802Sandrew irqstack.pv_va + ((IRQ_STACK_SIZE * PAGE_SIZE) * (cpu + 1))); 769240802Sandrew set_stackptr(PSR_ABT32_MODE, 770240802Sandrew abtstack.pv_va + ((ABT_STACK_SIZE * PAGE_SIZE) * (cpu + 1))); 771240802Sandrew set_stackptr(PSR_UND32_MODE, 772240802Sandrew undstack.pv_va + ((UND_STACK_SIZE * PAGE_SIZE) * (cpu + 1))); 773240802Sandrew} 774280712Sian#endif 775240802Sandrew 776331524Sianstatic void 777331524Sianarm_kdb_init(void) 778331524Sian{ 779283426Sandrew 780331524Sian kdb_init(); 781331524Sian#ifdef KDB 782331524Sian if (boothowto & RB_KDB) 783331524Sian kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 784331524Sian#endif 785331524Sian} 786331524Sian 787242531Sandrew#ifdef FDT 788295036Smmel#if __ARM_ARCH < 6 789242531Sandrewvoid * 790242531Sandrewinitarm(struct arm_boot_params *abp) 791242531Sandrew{ 792261643Sian struct mem_region mem_regions[FDT_MEM_REGIONS]; 793242531Sandrew struct pv_addr kernel_l1pt; 794242531Sandrew struct pv_addr dpcpu; 795242531Sandrew vm_offset_t dtbp, freemempos, l2_start, lastaddr; 796296265Sandrew uint64_t memsize; 797296189Swma uint32_t l2size; 798242531Sandrew char *env; 799242531Sandrew void *kmdp; 800242531Sandrew u_int l1pagetable; 801261643Sian int i, j, err_devmap, mem_regions_sz; 802242531Sandrew 803242531Sandrew lastaddr = parse_boot_param(abp); 804261649Sian arm_physmem_kernaddr = abp->abp_physaddr; 805261649Sian 806242531Sandrew memsize = 0; 807276333Sian 808276333Sian cpuinfo_init(); 809242531Sandrew set_cpufuncs(); 810242531Sandrew 811242531Sandrew /* 812242531Sandrew * Find the dtb passed in by the boot loader. 813242531Sandrew */ 814242531Sandrew kmdp = preload_search_by_type("elf kernel"); 815242531Sandrew if (kmdp != NULL) 816242531Sandrew dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t); 817242531Sandrew else 818242531Sandrew dtbp = (vm_offset_t)NULL; 819242531Sandrew 820242531Sandrew#if defined(FDT_DTB_STATIC) 821242531Sandrew /* 822242531Sandrew * In case the device tree blob was not retrieved (from metadata) try 823242531Sandrew * to use the statically embedded one. 824242531Sandrew */ 825242531Sandrew if (dtbp == (vm_offset_t)NULL) 826242531Sandrew dtbp = (vm_offset_t)&fdt_static_dtb; 827242531Sandrew#endif 828242531Sandrew 829242531Sandrew if (OF_install(OFW_FDT, 0) == FALSE) 830261789Simp panic("Cannot install FDT"); 831242531Sandrew 832242531Sandrew if (OF_init((void *)dtbp) != 0) 833261789Simp panic("OF_init failed with the found device tree"); 834242531Sandrew 835242531Sandrew /* Grab physical memory regions information from device tree. */ 836261643Sian if (fdt_get_mem_regions(mem_regions, &mem_regions_sz, &memsize) != 0) 837261643Sian panic("Cannot get physical memory regions"); 838261643Sian arm_physmem_hardware_regions(mem_regions, mem_regions_sz); 839242531Sandrew 840261643Sian /* Grab reserved memory regions information from device tree. */ 841261643Sian if (fdt_get_reserved_regions(mem_regions, &mem_regions_sz) == 0) 842283366Sandrew arm_physmem_exclude_regions(mem_regions, mem_regions_sz, 843261643Sian EXFLAG_NODUMP | EXFLAG_NOALLOC); 844243691Sgonzo 845242531Sandrew /* Platform-specific initialisation */ 846266301Sandrew platform_probe_and_attach(); 847242531Sandrew 848242531Sandrew pcpu0_init(); 849242531Sandrew 850242700Simp /* Do basic tuning, hz etc */ 851242700Simp init_param1(); 852242700Simp 853242531Sandrew /* Calculate number of L2 tables needed for mapping vm_page_array */ 854242531Sandrew l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page); 855242531Sandrew l2size = (l2size >> L1_S_SHIFT) + 1; 856242531Sandrew 857242531Sandrew /* 858242531Sandrew * Add one table for end of kernel map, one for stacks, msgbuf and 859242531Sandrew * L1 and L2 tables map and one for vectors map. 860242531Sandrew */ 861242531Sandrew l2size += 3; 862242531Sandrew 863242531Sandrew /* Make it divisible by 4 */ 864242531Sandrew l2size = (l2size + 3) & ~3; 865242531Sandrew 866242531Sandrew freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK; 867242531Sandrew 868242531Sandrew /* Define a macro to simplify memory allocation */ 869242700Simp#define valloc_pages(var, np) \ 870242700Simp alloc_pages((var).pv_va, (np)); \ 871261565Sandrew (var).pv_pa = (var).pv_va + (abp->abp_physaddr - KERNVIRTADDR); 872242531Sandrew 873242700Simp#define alloc_pages(var, np) \ 874242700Simp (var) = freemempos; \ 875242700Simp freemempos += (np * PAGE_SIZE); \ 876242531Sandrew memset((char *)(var), 0, ((np) * PAGE_SIZE)); 877242531Sandrew 878242531Sandrew while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) 879242531Sandrew freemempos += PAGE_SIZE; 880242531Sandrew valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); 881242531Sandrew 882261643Sian for (i = 0, j = 0; i < l2size; ++i) { 883242531Sandrew if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { 884242531Sandrew valloc_pages(kernel_pt_table[i], 885242531Sandrew L2_TABLE_SIZE / PAGE_SIZE); 886242531Sandrew j = i; 887242531Sandrew } else { 888242531Sandrew kernel_pt_table[i].pv_va = kernel_pt_table[j].pv_va + 889242531Sandrew L2_TABLE_SIZE_REAL * (i - j); 890242531Sandrew kernel_pt_table[i].pv_pa = 891242531Sandrew kernel_pt_table[i].pv_va - KERNVIRTADDR + 892261565Sandrew abp->abp_physaddr; 893242531Sandrew 894242531Sandrew } 895242531Sandrew } 896242531Sandrew /* 897242531Sandrew * Allocate a page for the system page mapped to 0x00000000 898242531Sandrew * or 0xffff0000. This page will just contain the system vectors 899242531Sandrew * and can be shared by all processes. 900242531Sandrew */ 901242531Sandrew valloc_pages(systempage, 1); 902242531Sandrew 903242531Sandrew /* Allocate dynamic per-cpu area. */ 904242531Sandrew valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE); 905242531Sandrew dpcpu_init((void *)dpcpu.pv_va, 0); 906242531Sandrew 907242531Sandrew /* Allocate stacks for all modes */ 908242746Simp valloc_pages(irqstack, IRQ_STACK_SIZE * MAXCPU); 909242746Simp valloc_pages(abtstack, ABT_STACK_SIZE * MAXCPU); 910242746Simp valloc_pages(undstack, UND_STACK_SIZE * MAXCPU); 911355346Skevans valloc_pages(kernelstack, kstack_pages); 912242531Sandrew valloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE); 913242531Sandrew 914242531Sandrew /* 915242531Sandrew * Now we start construction of the L1 page table 916242531Sandrew * We start by mapping the L2 page tables into the L1. 917242531Sandrew * This means that we can replace L1 mappings later on if necessary 918242531Sandrew */ 919242531Sandrew l1pagetable = kernel_l1pt.pv_va; 920242531Sandrew 921242531Sandrew /* 922242531Sandrew * Try to map as much as possible of kernel text and data using 923242531Sandrew * 1MB section mapping and for the rest of initial kernel address 924242531Sandrew * space use L2 coarse tables. 925242531Sandrew * 926242531Sandrew * Link L2 tables for mapping remainder of kernel (modulo 1MB) 927242531Sandrew * and kernel structures 928242531Sandrew */ 929242531Sandrew l2_start = lastaddr & ~(L1_S_OFFSET); 930242531Sandrew for (i = 0 ; i < l2size - 1; i++) 931242531Sandrew pmap_link_l2pt(l1pagetable, l2_start + i * L1_S_SIZE, 932242531Sandrew &kernel_pt_table[i]); 933242531Sandrew 934242531Sandrew pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE; 935242531Sandrew 936242531Sandrew /* Map kernel code and data */ 937261565Sandrew pmap_map_chunk(l1pagetable, KERNVIRTADDR, abp->abp_physaddr, 938242531Sandrew (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK, 939242531Sandrew VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 940242531Sandrew 941242531Sandrew /* Map L1 directory and allocated L2 page tables */ 942242531Sandrew pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, 943242531Sandrew L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); 944242531Sandrew 945242531Sandrew pmap_map_chunk(l1pagetable, kernel_pt_table[0].pv_va, 946242531Sandrew kernel_pt_table[0].pv_pa, 947242531Sandrew L2_TABLE_SIZE_REAL * l2size, 948242531Sandrew VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); 949242531Sandrew 950242531Sandrew /* Map allocated DPCPU, stacks and msgbuf */ 951242531Sandrew pmap_map_chunk(l1pagetable, dpcpu.pv_va, dpcpu.pv_pa, 952242531Sandrew freemempos - dpcpu.pv_va, 953242531Sandrew VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 954242531Sandrew 955242531Sandrew /* Link and map the vector page */ 956242531Sandrew pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH, 957242531Sandrew &kernel_pt_table[l2size - 1]); 958242531Sandrew pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, 959242531Sandrew VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE); 960242531Sandrew 961257669Sian /* Establish static device mappings. */ 962266301Sandrew err_devmap = platform_devmap_init(); 963298627Sbr devmap_bootstrap(l1pagetable, NULL); 964266301Sandrew vm_max_kernel_address = platform_lastaddr(); 965242531Sandrew 966242700Simp cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) | DOMAIN_CLIENT); 967242531Sandrew pmap_pa = kernel_l1pt.pv_pa; 968295213Smmel cpu_setttb(kernel_l1pt.pv_pa); 969242531Sandrew cpu_tlb_flushID(); 970242531Sandrew cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)); 971242531Sandrew 972242531Sandrew /* 973258392Sian * Now that proper page tables are installed, call cpu_setup() to enable 974258392Sian * instruction and data caches and other chip-specific features. 975258392Sian */ 976280823Sandrew cpu_setup(); 977258392Sian 978258392Sian /* 979242531Sandrew * Only after the SOC registers block is mapped we can perform device 980242531Sandrew * tree fixups, as they may attempt to read parameters from hardware. 981242531Sandrew */ 982242531Sandrew OF_interpret("perform-fixup", 0); 983242531Sandrew 984266301Sandrew platform_gpio_init(); 985242531Sandrew 986242531Sandrew cninit(); 987242531Sandrew 988242531Sandrew debugf("initarm: console initialized\n"); 989242531Sandrew debugf(" arg1 kmdp = 0x%08x\n", (uint32_t)kmdp); 990242531Sandrew debugf(" boothowto = 0x%08x\n", boothowto); 991242531Sandrew debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp); 992317004Smmel arm_print_kenv(); 993242531Sandrew 994273174Sdavide env = kern_getenv("kernelname"); 995273908Skevlo if (env != NULL) { 996242531Sandrew strlcpy(kernelname, env, sizeof(kernelname)); 997273908Skevlo freeenv(env); 998273908Skevlo } 999242531Sandrew 1000242531Sandrew if (err_devmap != 0) 1001242531Sandrew printf("WARNING: could not fully configure devmap, error=%d\n", 1002242531Sandrew err_devmap); 1003242531Sandrew 1004266301Sandrew platform_late_init(); 1005242531Sandrew 1006242531Sandrew /* 1007242531Sandrew * Pages were allocated during the secondary bootstrap for the 1008242531Sandrew * stacks for different CPU modes. 1009242531Sandrew * We must now set the r13 registers in the different CPU modes to 1010242531Sandrew * point to these stacks. 1011242531Sandrew * Since the ARM stacks use STMFD etc. we must set r13 to the top end 1012242531Sandrew * of the stack memory. 1013242531Sandrew */ 1014242531Sandrew cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE); 1015242531Sandrew 1016242531Sandrew set_stackptrs(0); 1017242531Sandrew 1018242531Sandrew /* 1019242531Sandrew * We must now clean the cache again.... 1020242531Sandrew * Cleaning may be done by reading new data to displace any 1021295213Smmel * dirty data in the cache. This will have happened in cpu_setttb() 1022242531Sandrew * but since we are boot strapping the addresses used for the read 1023242531Sandrew * may have just been remapped and thus the cache could be out 1024242531Sandrew * of sync. A re-clean after the switch will cure this. 1025242531Sandrew * After booting there are no gross relocations of the kernel thus 1026242531Sandrew * this problem will not occur after initarm(). 1027242531Sandrew */ 1028242531Sandrew cpu_idcache_wbinv_all(); 1029242531Sandrew 1030242531Sandrew undefined_init(); 1031242531Sandrew 1032242531Sandrew init_proc0(kernelstack.pv_va); 1033242531Sandrew 1034242531Sandrew arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); 1035247046Salc pmap_bootstrap(freemempos, &kernel_l1pt); 1036242531Sandrew msgbufp = (void *)msgbufpv.pv_va; 1037242531Sandrew msgbufinit(msgbufp, msgbufsize); 1038242531Sandrew mutex_init(); 1039242531Sandrew 1040242531Sandrew /* 1041261643Sian * Exclude the kernel (and all the things we allocated which immediately 1042261643Sian * follow the kernel) from the VM allocation pool but not from crash 1043261643Sian * dumps. virtual_avail is a global variable which tracks the kva we've 1044261643Sian * "allocated" while setting up pmaps. 1045261643Sian * 1046261643Sian * Prepare the list of physical memory available to the vm subsystem. 1047242531Sandrew */ 1048283366Sandrew arm_physmem_exclude_region(abp->abp_physaddr, 1049261643Sian (virtual_avail - KERNVIRTADDR), EXFLAG_NOALLOC); 1050261643Sian arm_physmem_init_kernel_globals(); 1051242531Sandrew 1052242531Sandrew init_param2(physmem); 1053294740Szbb dbg_monitor_init(); 1054331524Sian arm_kdb_init(); 1055242531Sandrew 1056242531Sandrew return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - 1057242531Sandrew sizeof(struct pcb))); 1058242531Sandrew} 1059295036Smmel#else /* __ARM_ARCH < 6 */ 1060280712Sianvoid * 1061280712Sianinitarm(struct arm_boot_params *abp) 1062280712Sian{ 1063280712Sian struct mem_region mem_regions[FDT_MEM_REGIONS]; 1064280712Sian vm_paddr_t lastaddr; 1065280712Sian vm_offset_t dtbp, kernelstack, dpcpu; 1066280712Sian char *env; 1067280712Sian void *kmdp; 1068280712Sian int err_devmap, mem_regions_sz; 1069283426Sandrew#ifdef EFI 1070283426Sandrew struct efi_map_header *efihdr; 1071283426Sandrew#endif 1072280712Sian 1073280712Sian /* get last allocated physical address */ 1074280712Sian arm_physmem_kernaddr = abp->abp_physaddr; 1075280712Sian lastaddr = parse_boot_param(abp) - KERNVIRTADDR + arm_physmem_kernaddr; 1076280712Sian 1077280712Sian set_cpufuncs(); 1078280712Sian cpuinfo_init(); 1079280712Sian 1080280712Sian /* 1081280712Sian * Find the dtb passed in by the boot loader. 1082280712Sian */ 1083280712Sian kmdp = preload_search_by_type("elf kernel"); 1084287000Sroyger dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t); 1085280712Sian#if defined(FDT_DTB_STATIC) 1086280712Sian /* 1087280712Sian * In case the device tree blob was not retrieved (from metadata) try 1088280712Sian * to use the statically embedded one. 1089280712Sian */ 1090280712Sian if (dtbp == (vm_offset_t)NULL) 1091280712Sian dtbp = (vm_offset_t)&fdt_static_dtb; 1092242531Sandrew#endif 1093280712Sian 1094280712Sian if (OF_install(OFW_FDT, 0) == FALSE) 1095280712Sian panic("Cannot install FDT"); 1096280712Sian 1097280712Sian if (OF_init((void *)dtbp) != 0) 1098280712Sian panic("OF_init failed with the found device tree"); 1099280712Sian 1100297286Smmel#if defined(LINUX_BOOT_ABI) 1101317004Smmel arm_parse_fdt_bootargs(); 1102297286Smmel#endif 1103297286Smmel 1104283426Sandrew#ifdef EFI 1105283426Sandrew efihdr = (struct efi_map_header *)preload_search_info(kmdp, 1106283426Sandrew MODINFO_METADATA | MODINFOMD_EFI_MAP); 1107283426Sandrew if (efihdr != NULL) { 1108317004Smmel arm_add_efi_map_entries(efihdr, mem_regions, &mem_regions_sz); 1109283426Sandrew } else 1110283426Sandrew#endif 1111283426Sandrew { 1112283426Sandrew /* Grab physical memory regions information from device tree. */ 1113296258Sandrew if (fdt_get_mem_regions(mem_regions, &mem_regions_sz,NULL) != 0) 1114283426Sandrew panic("Cannot get physical memory regions"); 1115283426Sandrew } 1116280712Sian arm_physmem_hardware_regions(mem_regions, mem_regions_sz); 1117280712Sian 1118280712Sian /* Grab reserved memory regions information from device tree. */ 1119280712Sian if (fdt_get_reserved_regions(mem_regions, &mem_regions_sz) == 0) 1120280712Sian arm_physmem_exclude_regions(mem_regions, mem_regions_sz, 1121280712Sian EXFLAG_NODUMP | EXFLAG_NOALLOC); 1122280712Sian 1123280712Sian /* 1124280712Sian * Set TEX remapping registers. 1125280712Sian * Setup kernel page tables and switch to kernel L1 page table. 1126280712Sian */ 1127280712Sian pmap_set_tex(); 1128280712Sian pmap_bootstrap_prepare(lastaddr); 1129280712Sian 1130280712Sian /* 1131327656Sian * If EARLY_PRINTF support is enabled, we need to re-establish the 1132327656Sian * mapping after pmap_bootstrap_prepare() switches to new page tables. 1133327656Sian * Note that we can only do the remapping if the VA is outside the 1134327656Sian * kernel, now that we have real virtual (not VA=PA) mappings in effect. 1135327656Sian * Early printf does not work between the time pmap_set_tex() does 1136327656Sian * cp15_prrr_set() and this code remaps the VA. 1137327656Sian */ 1138327656Sian#if defined(EARLY_PRINTF) && defined(SOCDEV_PA) && defined(SOCDEV_VA) && SOCDEV_VA < KERNBASE 1139327656Sian pmap_preboot_map_attr(SOCDEV_PA, SOCDEV_VA, 1024 * 1024, 1140327656Sian VM_PROT_READ | VM_PROT_WRITE, VM_MEMATTR_DEVICE); 1141327656Sian#endif 1142327656Sian 1143327656Sian /* 1144280712Sian * Now that proper page tables are installed, call cpu_setup() to enable 1145280712Sian * instruction and data caches and other chip-specific features. 1146280712Sian */ 1147280823Sandrew cpu_setup(); 1148280712Sian 1149280712Sian /* Platform-specific initialisation */ 1150280712Sian platform_probe_and_attach(); 1151280712Sian pcpu0_init(); 1152280712Sian 1153280712Sian /* Do basic tuning, hz etc */ 1154280712Sian init_param1(); 1155280712Sian 1156280712Sian /* 1157280712Sian * Allocate a page for the system page mapped to 0xffff0000 1158280712Sian * This page will just contain the system vectors and can be 1159280712Sian * shared by all processes. 1160280712Sian */ 1161280712Sian systempage = pmap_preboot_get_pages(1); 1162280712Sian 1163280712Sian /* Map the vector page. */ 1164280712Sian pmap_preboot_map_pages(systempage, ARM_VECTORS_HIGH, 1); 1165280712Sian if (virtual_end >= ARM_VECTORS_HIGH) 1166280712Sian virtual_end = ARM_VECTORS_HIGH - 1; 1167280712Sian 1168280712Sian /* Allocate dynamic per-cpu area. */ 1169280712Sian dpcpu = pmap_preboot_get_vpages(DPCPU_SIZE / PAGE_SIZE); 1170280712Sian dpcpu_init((void *)dpcpu, 0); 1171280712Sian 1172280712Sian /* Allocate stacks for all modes */ 1173280712Sian irqstack = pmap_preboot_get_vpages(IRQ_STACK_SIZE * MAXCPU); 1174280712Sian abtstack = pmap_preboot_get_vpages(ABT_STACK_SIZE * MAXCPU); 1175280712Sian undstack = pmap_preboot_get_vpages(UND_STACK_SIZE * MAXCPU ); 1176355346Skevans kernelstack = pmap_preboot_get_vpages(kstack_pages); 1177280712Sian 1178280712Sian /* Allocate message buffer. */ 1179280712Sian msgbufp = (void *)pmap_preboot_get_vpages( 1180280712Sian round_page(msgbufsize) / PAGE_SIZE); 1181280712Sian 1182280712Sian /* 1183280712Sian * Pages were allocated during the secondary bootstrap for the 1184280712Sian * stacks for different CPU modes. 1185280712Sian * We must now set the r13 registers in the different CPU modes to 1186280712Sian * point to these stacks. 1187280712Sian * Since the ARM stacks use STMFD etc. we must set r13 to the top end 1188280712Sian * of the stack memory. 1189280712Sian */ 1190280712Sian set_stackptrs(0); 1191280712Sian mutex_init(); 1192280712Sian 1193280712Sian /* Establish static device mappings. */ 1194280712Sian err_devmap = platform_devmap_init(); 1195298627Sbr devmap_bootstrap(0, NULL); 1196280712Sian vm_max_kernel_address = platform_lastaddr(); 1197280712Sian 1198280712Sian /* 1199280712Sian * Only after the SOC registers block is mapped we can perform device 1200280712Sian * tree fixups, as they may attempt to read parameters from hardware. 1201280712Sian */ 1202280712Sian OF_interpret("perform-fixup", 0); 1203280712Sian platform_gpio_init(); 1204280712Sian cninit(); 1205280712Sian 1206327656Sian /* 1207327656Sian * If we made a mapping for EARLY_PRINTF after pmap_bootstrap_prepare(), 1208327656Sian * undo it now that the normal console printf works. 1209327656Sian */ 1210327656Sian#if defined(EARLY_PRINTF) && defined(SOCDEV_PA) && defined(SOCDEV_VA) && SOCDEV_VA < KERNBASE 1211327656Sian pmap_kremove(SOCDEV_VA); 1212327656Sian#endif 1213327656Sian 1214280712Sian debugf("initarm: console initialized\n"); 1215280712Sian debugf(" arg1 kmdp = 0x%08x\n", (uint32_t)kmdp); 1216280712Sian debugf(" boothowto = 0x%08x\n", boothowto); 1217280712Sian debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp); 1218280712Sian debugf(" lastaddr1: 0x%08x\n", lastaddr); 1219317004Smmel arm_print_kenv(); 1220280712Sian 1221280712Sian env = kern_getenv("kernelname"); 1222280712Sian if (env != NULL) 1223280712Sian strlcpy(kernelname, env, sizeof(kernelname)); 1224280712Sian 1225280712Sian if (err_devmap != 0) 1226280712Sian printf("WARNING: could not fully configure devmap, error=%d\n", 1227280712Sian err_devmap); 1228280712Sian 1229280712Sian platform_late_init(); 1230280712Sian 1231280712Sian /* 1232280712Sian * We must now clean the cache again.... 1233280712Sian * Cleaning may be done by reading new data to displace any 1234295213Smmel * dirty data in the cache. This will have happened in cpu_setttb() 1235280712Sian * but since we are boot strapping the addresses used for the read 1236280712Sian * may have just been remapped and thus the cache could be out 1237280712Sian * of sync. A re-clean after the switch will cure this. 1238280712Sian * After booting there are no gross relocations of the kernel thus 1239280712Sian * this problem will not occur after initarm(). 1240280712Sian */ 1241280712Sian /* Set stack for exception handlers */ 1242280712Sian undefined_init(); 1243280712Sian init_proc0(kernelstack); 1244280712Sian arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); 1245280712Sian enable_interrupts(PSR_A); 1246280712Sian pmap_bootstrap(0); 1247280712Sian 1248280712Sian /* Exclude the kernel (and all the things we allocated which immediately 1249280712Sian * follow the kernel) from the VM allocation pool but not from crash 1250280712Sian * dumps. virtual_avail is a global variable which tracks the kva we've 1251280712Sian * "allocated" while setting up pmaps. 1252280712Sian * 1253280712Sian * Prepare the list of physical memory available to the vm subsystem. 1254280712Sian */ 1255280712Sian arm_physmem_exclude_region(abp->abp_physaddr, 1256280712Sian pmap_preboot_get_pages(0) - abp->abp_physaddr, EXFLAG_NOALLOC); 1257280712Sian arm_physmem_init_kernel_globals(); 1258280712Sian 1259280712Sian init_param2(physmem); 1260280712Sian /* Init message buffer. */ 1261280712Sian msgbufinit(msgbufp, msgbufsize); 1262294740Szbb dbg_monitor_init(); 1263331524Sian arm_kdb_init(); 1264331988Smmel /* Apply possible BP hardening. */ 1265331988Smmel cpuinfo_init_bp_hardening(); 1266280712Sian return ((void *)STACKALIGN(thread0.td_pcb)); 1267280712Sian 1268280712Sian} 1269280712Sian 1270295036Smmel#endif /* __ARM_ARCH < 6 */ 1271280712Sian#endif /* FDT */ 1272