mirror of
https://github.com/Stichting-MINIX-Research-Foundation/netbsd.git
synced 2025-08-14 08:31:28 -04:00
470 lines
11 KiB
ArmAsm
470 lines
11 KiB
ArmAsm
/* $NetBSD: a9_mpsubr.S,v 1.10 2013/11/12 17:10:39 matt Exp $ */
|
|
/*-
|
|
* Copyright (c) 2012 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Matt Thomas of 3am Software Foundry.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "opt_cpuoptions.h"
|
|
#include "opt_cputypes.h"
|
|
#include "opt_multiprocessor.h"
|
|
|
|
#include <arm/asm.h>
|
|
#include <arm/armreg.h>
|
|
#include <arm/cortex/scu_reg.h>
|
|
#include "assym.h"
|
|
|
|
|
|
/* We'll modify va and pa at run time so we can use relocatable addresses. */
|
|
#define MMU_INIT(va,pa,n_sec,attr) \
|
|
.word va ; \
|
|
.word pa ; \
|
|
.word n_sec ; \
|
|
.word attr ;
|
|
|
|
/*
|
|
* Set up a preliminary mapping in the MMU to allow us to run
|
|
* at KERNEL_BASE with caches on.
|
|
*/
|
|
arm_boot_l1pt_init:
|
|
mov ip, r1 @ save mmu table addr
|
|
/* Build page table from scratch */
|
|
mov r1, r0 /* Start address to clear memory. */
|
|
/* Zero the entire table so all virtual addresses are invalid. */
|
|
mov r2, #L1_TABLE_SIZE /* in bytes */
|
|
mov r3, #0
|
|
mov r4, r3
|
|
mov r5, r3
|
|
mov r6, r3
|
|
mov r7, r3
|
|
mov r8, r3
|
|
mov r10, r3
|
|
mov r11, r3
|
|
1: stmia r1!, {r3-r8,r10-r11}
|
|
stmia r1!, {r3-r8,r10-r11}
|
|
stmia r1!, {r3-r8,r10-r11}
|
|
stmia r1!, {r3-r8,r10-r11}
|
|
subs r2, r2, #(4 * 4 * 8) /* bytes per loop */
|
|
bne 1b
|
|
|
|
/* Now create our entries per the mmu_init_table. */
|
|
l1table .req r0
|
|
va .req r1
|
|
pa .req r2
|
|
n_sec .req r3
|
|
attr .req r4
|
|
itable .req r5
|
|
|
|
mov itable, ip @ reclaim table address
|
|
b 3f
|
|
|
|
2: str pa, [l1table, va, lsl #2]
|
|
add va, va, #1
|
|
add pa, pa, #(L1_S_SIZE)
|
|
subs n_sec, n_sec, #1
|
|
bhi 2b
|
|
|
|
3: ldmia itable!, {va,pa,n_sec,attr}
|
|
/* Convert va to l1 offset: va = 4 * (va >> L1_S_SHIFT) */
|
|
lsr va, va, #L1_S_SHIFT
|
|
/* Convert pa to l1 entry: pa = (pa & L1_S_FRAME) | attr */
|
|
#ifdef _ARM_ARCH_7
|
|
bfc pa, #0, #L1_S_SHIFT
|
|
#else
|
|
lsr pa, pa, #L1_S_SHIFT
|
|
lsl pa, pa, #L1_S_SHIFT
|
|
#endif
|
|
orr pa, pa, attr
|
|
cmp n_sec, #0
|
|
bne 2b
|
|
bx lr @ return
|
|
|
|
.unreq va
|
|
.unreq pa
|
|
.unreq n_sec
|
|
.unreq attr
|
|
.unreq itable
|
|
.unreq l1table
|
|
|
|
#if defined(CPU_CORTEXA8)
|
|
#undef CPU_CONTROL_SWP_ENABLE // not present on A8
|
|
#define CPU_CONTROL_SWP_ENABLE 0
|
|
#endif
|
|
#ifdef __ARMEL__
|
|
#undef CPU_CONTROL_EX_BEND // needs to clear on LE systems
|
|
#define CPU_CONTROL_EX_BEND 0
|
|
#endif
|
|
#ifdef ARM32_DISABLE_ALIGNMENT_FAULTS
|
|
#undef CPU_CONTROL_AFLT_ENABLE
|
|
#define CPU_CONTROL_AFLT_ENABLE 0
|
|
#endif
|
|
|
|
#define CPU_CONTROL_SET \
|
|
(CPU_CONTROL_MMU_ENABLE | \
|
|
CPU_CONTROL_AFLT_ENABLE | \
|
|
CPU_CONTROL_EX_BEND | \
|
|
CPU_CONTROL_DC_ENABLE | \
|
|
CPU_CONTROL_SWP_ENABLE | \
|
|
CPU_CONTROL_BPRD_ENABLE | \
|
|
CPU_CONTROL_IC_ENABLE | \
|
|
CPU_CONTROL_UNAL_ENABLE)
|
|
|
|
arm_cpuinit:
|
|
/*
|
|
* In theory, because the MMU is off, we shouldn't need all of this,
|
|
* but let's not take any chances and do a typical sequence to set
|
|
* the Translation Table Base.
|
|
*/
|
|
mov ip, lr
|
|
mov r10, r0
|
|
|
|
mcr p15, 0, r10, c7, c5, 0 /* invalidate I cache */
|
|
|
|
mrc p15, 0, r2, c1, c0, 0 /* " " " */
|
|
bic r2, r2, #CPU_CONTROL_DC_ENABLE @ clear data cache enable
|
|
bic r2, r2, #CPU_CONTROL_IC_ENABLE @ clear instruction cache enable
|
|
mcr p15, 0, r2, c1, c0, 0 /* " " " */
|
|
|
|
XPUTC(#70)
|
|
mov r1, #0
|
|
mcr p15, 0, r1, c7, c10, 4 /* Drain the write buffers. */
|
|
|
|
XPUTC(#71)
|
|
mrc p15, 0, r2, c0, c0, 5 /* get MPIDR */
|
|
cmp r2, #0
|
|
orrlt r10, r10, #0x5b /* MP, cachable (Normal WB) */
|
|
orrge r10, r10, #0x1b /* Non-MP, cacheable, normal WB */
|
|
mcr p15, 0, r10, c2, c0, 0 /* Set Translation Table Base */
|
|
|
|
XPUTC(#49)
|
|
mcr p15, 0, r1, c2, c0, 2 /* Set Translation Table Control */
|
|
|
|
XPUTC(#72)
|
|
mov r1, #0
|
|
mcr p15, 0, r1, c8, c7, 0 /* Invalidate TLBs */
|
|
|
|
/* Set the Domain Access register. Very important! */
|
|
XPUTC(#73)
|
|
mov r1, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
|
|
mcr p15, 0, r1, c3, c0, 0
|
|
|
|
/*
|
|
* Enable the MMU, etc.
|
|
*/
|
|
XPUTC(#74)
|
|
mrc p15, 0, r0, c1, c0, 0
|
|
|
|
movw r3, #:lower16:CPU_CONTROL_SET
|
|
#if (CPU_CONTROL_SET & 0xffff0000)
|
|
movt r3, #:upper16:CPU_CONTROL_SET
|
|
#endif
|
|
orr r0, r0, r3
|
|
|
|
dsb
|
|
.align 5
|
|
@ turn mmu on!
|
|
mov r0, r0
|
|
mcr p15, 0, r0, c1, c0, 0
|
|
|
|
/*
|
|
* Ensure that the coprocessor has finished turning on the MMU.
|
|
*/
|
|
mrc p15, 0, r0, c0, c0, 0 /* Read an arbitrary value. */
|
|
mov r0, r0 /* Stall until read completes. */
|
|
XPUTC(#76)
|
|
|
|
bx ip /* return */
|
|
|
|
/*
|
|
* Coprocessor register initialization values
|
|
*/
|
|
|
|
.p2align 2
|
|
|
|
/* bits to set in the Control Register */
|
|
|
|
#if defined(VERBOSE_INIT_ARM) && XPUTC_COM
|
|
#define TIMO 0x25000
|
|
#ifndef COM_MULT
|
|
#define COM_MULT 1
|
|
#endif
|
|
xputc:
|
|
#ifdef MULTIPROCESSOR
|
|
mov r2, #1
|
|
ldr r3, .Lcomlock
|
|
10:
|
|
ldrex r1, [r3]
|
|
cmp r1, #0
|
|
bne 10b
|
|
strex r1, r2, [r3]
|
|
cmp r1, #0
|
|
bne 10b
|
|
dsb
|
|
#endif
|
|
|
|
mov r2, #TIMO
|
|
ldr r3, .Luart0
|
|
1: ldrb r1, [r3, #(COM_LSR*COM_MULT)]
|
|
tst r1, #LSR_TXRDY
|
|
bne 2f
|
|
subs r2, r2, #1
|
|
bne 1b
|
|
2:
|
|
strb r0, [r3, #COM_DATA]
|
|
|
|
mov r2, #TIMO
|
|
3: ldrb r1, [r3, #(COM_LSR*COM_MULT)]
|
|
tst r1, #LSR_TSRE
|
|
bne 4f
|
|
subs r2, r2, #1
|
|
bne 3b
|
|
4:
|
|
#ifdef MULTIPROCESSOR
|
|
ldr r3, .Lcomlock
|
|
mov r0, #0
|
|
str r0, [r3]
|
|
dsb
|
|
#endif
|
|
bx lr
|
|
|
|
.Luart0:
|
|
#ifdef CONADDR
|
|
.word CONADDR
|
|
#elif defined(CONSADDR)
|
|
.word CONSADDR
|
|
#endif
|
|
|
|
#ifdef MULTIPROCESSOR
|
|
.Lcomlock:
|
|
.word comlock
|
|
|
|
.pushsection .data
|
|
comlock:
|
|
.p2align 2
|
|
.word 0 @ not in bss
|
|
|
|
.popsection
|
|
#endif /* MULTIPROCESSOR */
|
|
#endif /* VERBOSE_INIT_ARM */
|
|
|
|
#ifdef CPU_CORTEXA9
|
|
a9_start:
|
|
mov r10, lr @ save lr
|
|
|
|
cpsid if, #PSR_SVC32_MODE
|
|
|
|
XPUTC(#64)
|
|
bl _C_LABEL(armv7_icache_inv_all) @ invalidate i-cache
|
|
|
|
/*
|
|
* Step 1a, invalidate the all cache tags in all ways on the SCU.
|
|
*/
|
|
XPUTC(#65)
|
|
mrc p15, 4, r3, c15, c0, 0 @ read cbar
|
|
ldr r0, [r3, #SCU_CFG] @ read scu config
|
|
and r0, r0, #7 @ get cpu max
|
|
add r0, r0, #2 @ adjust to cpu num
|
|
mov r1, #0xf @ select all ways
|
|
lsl r1, r1, r0 @ shift into place
|
|
str r1, [r3, #SCU_INV_ALL_REG] @ write scu invalidate all
|
|
dsb
|
|
isb
|
|
|
|
/*
|
|
* Step 1b, invalidate the data cache
|
|
*/
|
|
XPUTC(#66)
|
|
bl _C_LABEL(armv7_dcache_wbinv_all) @ writeback/invalidate d-cache
|
|
XPUTC(#67)
|
|
|
|
/*
|
|
* Step 2, disable the data cache
|
|
*/
|
|
mrc p15, 0, r2, c1, c0, 0 @ get system ctl register (save)
|
|
bic r1, r2, #CPU_CONTROL_DC_ENABLE @ clear data cache enable
|
|
mcr p15, 0, r1, c1, c0, 0 @ set system ctl register
|
|
isb
|
|
XPUTC(#49)
|
|
|
|
/*
|
|
* Step 3, enable the SCU (and set SMP mode)
|
|
*/
|
|
mrc p15, 4, r3, c15, c0, 0 @ read cbar
|
|
ldr r1, [r3, #SCU_CTL] @ read scu control
|
|
orr r1, r1, #SCU_CTL_SCU_ENA @ set scu enable flag
|
|
str r1, [r3, #SCU_CTL] @ write scu control
|
|
dsb
|
|
isb
|
|
XPUTC(#50)
|
|
|
|
/*
|
|
* Step 4a, enable the data cache
|
|
*/
|
|
orr r2, r2, #CPU_CONTROL_DC_ENABLE @ set data cache enable
|
|
mcr p15, 0, r2, c1, c0, 0 @ reenable caches
|
|
isb
|
|
XPUTC(#51)
|
|
|
|
#ifdef MULTIPROCESSOR
|
|
/*
|
|
* Step 4b, set ACTLR.SMP=1 (and ACTRL.FX=1)
|
|
*/
|
|
mrc p15, 0, r0, c1, c0, 1 @ read aux ctl
|
|
orr r0, r0, #CORTEXA9_AUXCTL_SMP @ enable SMP
|
|
mcr p15, 0, r0, c1, c0, 1 @ write aux ctl
|
|
isb
|
|
orr r0, r0, #CORTEXA9_AUXCTL_FW @ enable cache/tlb/coherency
|
|
mcr p15, 0, r0, c1, c0, 1 @ write aux ctl
|
|
isb
|
|
XPUTC(#52)
|
|
#endif
|
|
|
|
bx r10
|
|
ASEND(a9_start)
|
|
|
|
/*
|
|
* Secondary processors come here after exiting the SKU ROM.
|
|
*/
|
|
a9_mpstart:
|
|
#ifdef MULTIPROCESSOR
|
|
/*
|
|
* Step 1, invalidate the caches
|
|
*/
|
|
bl _C_LABEL(armv7_icache_inv_all) @ toss i-cache
|
|
bl _C_LABEL(armv7_dcache_inv_all) @ toss d-cache
|
|
|
|
/*
|
|
* Step 2, wait for the SCU to be enabled
|
|
*/
|
|
mrc p15, 4, r3, c15, c0, 0 @ read cbar
|
|
1: ldr r0, [r3, #SCU_CTL] @ read scu control
|
|
tst r0, #SCU_CTL_SCU_ENA @ enable bit set yet?
|
|
bne 1b @ try again
|
|
|
|
/*
|
|
* Step 3, set ACTLR.SMP=1 (and ACTRL.FX=1)
|
|
*/
|
|
mrc p15, 0, r0, c1, c0, 1 @ read aux ctl
|
|
orr r0, #CORTEXA9_AUXCTL_SMP @ enable SMP
|
|
mcr p15, 0, r0, c1, c0, 1 @ write aux ctl
|
|
mov r0, r0
|
|
orr r0, #CORTEXA9_AUXCTL_FW @ enable cache/tlb/coherency
|
|
mcr p15, 0, r0, c1, c0, 1 @ write aux ctl
|
|
mov r0, r0
|
|
|
|
/*
|
|
* We should be in SMP mode now.
|
|
*/
|
|
mrc p15, 0, r4, c0, c0, 5 @ get MPIDR
|
|
and r4, r4, #7 @ get our cpu numder
|
|
|
|
#if defined(VERBOSE_INIT_ARM)
|
|
add r0, r4, #48
|
|
bl xputc
|
|
#endif
|
|
|
|
ldr r0, .Lcpu_hatched @ now show we've hatched
|
|
mov r5, #1
|
|
lsl r5, r5, r4
|
|
mov r1, r5
|
|
bl _C_LABEL(atomic_or_32)
|
|
|
|
XPUTC(#97)
|
|
#endif
|
|
|
|
cpsid if, #PSR_SVC32_MODE @ make sure we are in SVC mode
|
|
|
|
/* Now we will wait for someone tell this cpu to start running */
|
|
#ifdef MULTIPROCESSOR
|
|
ldr r0, .Lcpu_mbox
|
|
#else
|
|
cmp r0, r0
|
|
#endif
|
|
2:
|
|
#ifdef MULTIPROCESSOR
|
|
dmb
|
|
ldr r2, [r0]
|
|
tst r2, r5
|
|
#endif
|
|
@wfeeq
|
|
beq 2b
|
|
|
|
#ifdef MULTIPROCESSOR
|
|
3: XPUTC(#98)
|
|
ldr r0, .Lcpu_marker
|
|
str pc, [r0]
|
|
|
|
ldr r0, .Lkernel_l1pt /* get address of l1pt pvaddr */
|
|
ldr r0, [r0, #PV_PA] /* Now get the phys addr */
|
|
bl cpu_init
|
|
|
|
ldr r0, .Lcpu_marker
|
|
str pc, [r0]
|
|
|
|
/* MMU, L1, are now on. */
|
|
|
|
ldr r0, .Lcpu_info /* get pointer to cpu_infos */
|
|
ldr r5, [r0, r4, lsl #2] /* load our cpu_info */
|
|
ldr r6, [r5, #CI_IDLELWP] /* get the idlelwp */
|
|
ldr r7, [r6, #L_PCB] /* now get its pcb */
|
|
ldr sp, [r7, #PCB_SP] /* finally, we can load our SP */
|
|
#ifdef TPIDRPRW_IS_CURCPU
|
|
mcr p15, 0, r5, c13, c0, 4 /* squirrel away curcpu() */
|
|
#elif defined(TPIDRPRW_IS_CURLWP)
|
|
mcr p15, 0, r6, c13, c0, 4 /* squirrel away curlwp() */
|
|
#else
|
|
#error either TPIDRPRW_IS_CURCPU or TPIDRPRW_IS_CURLWP must be defined
|
|
#endif
|
|
str r6, [r5, #CI_CURLWP] /* and note we are running on it */
|
|
|
|
ldr r0, .Lcpu_marker
|
|
str pc, [r0]
|
|
|
|
mov r0, r5 /* pass cpu_info */
|
|
mov r1, r4 /* pass cpu_id */
|
|
ldr r2, .Lbcm53xx_cpu_hatch /* pass md_cpu_hatch */
|
|
bl _C_LABEL(cpu_hatch)
|
|
b _C_LABEL(idle_loop)
|
|
ASEND(a9_mpstart)
|
|
/* NOT REACHED */
|
|
|
|
.Lkernel_l1pt:
|
|
.word _C_LABEL(kernel_l1pt)
|
|
.Lcpu_info:
|
|
.word _C_LABEL(cpu_info)
|
|
.Lcpu_max:
|
|
.word _C_LABEL(arm_cpu_max)
|
|
.Lcpu_hatched:
|
|
.word _C_LABEL(arm_cpu_hatched)
|
|
.Lcpu_mbox:
|
|
.word _C_LABEL(arm_cpu_mbox)
|
|
.Lcpu_marker:
|
|
.word _C_LABEL(arm_cpu_marker)
|
|
.Lbcm53xx_cpu_hatch:
|
|
.word _C_LABEL(bcm53xx_cpu_hatch)
|
|
#endif /* MULTIPROCESSOR */
|
|
#endif /* CPU_CORTEXA9 */
|