kernel/head.S – __v7_ca7mp_setup:

  1. SMP 시스템에서 캐시 coherent가 disable되어 있으면 enable시킨다.
  2. d-cache를 모두 flush(invalidate + clean)한다.
  3. 현재 프로세스와 관련 있는 ERRATA(프로세스 에러 패치)를 적용한다.
  4. i-cache를 모두 invalidate한다.
  5. TLB cache를 모두 invalidate한다.
  6. TTBCR을 0으로 설정한다. (페이지테이블을 나누어 사용하지 않는다)
  7. TTBR1에 TTB_RGN_WBWA | TTB_S를 설정한다.
  8. PRRR에 =PRRR 값을 설정한다.
  9. NMRR에 =NMRR 값을 설정한다.

kernel_head.s분석11

__v7_ca7mp_setup:

/*
 *      __v7_setup
 *
 *      Initialise TLB, Caches, and MMU state ready to switch the MMU
 *      on.  Return in r0 the new CP15 C1 control register setting.
 *
 *      This should be able to cover all ARMv7 cores.
 *
 *      It is assumed that:
 *      - cache type register is implemented
 */
__v7_ca7mp_setup:
        mov     r10, #0
#ifdef CONFIG_SMP
        ALT_SMP(mrc     p15, 0, r0, c1, c0, 1)
        ALT_UP(mov      r0, #(1 << 6))          @ fake it for UP
        tst     r0, #(1 << 6)                   @ SMP/nAMP mode enabled?
        orreq   r0, r0, #(1 << 6)               @ Enable SMP/nAMP mode
        orreq   r0, r0, r10                     @ Enable CPU-specific SMP bits
        mcreq   p15, 0, r0, c1, c0, 1
#endif
        b       __v7_setup
  • ACTLR.SMP를 읽어 0으로 되어 있으면 1로 다시 바꾼다.
    • Enables coherent requests to the processor: 0=disable, 1=enable

 

__v7_setup:

__v7_setup:
        adr     r12, __v7_setup_stack           @ the local stack
        stmia   r12, {r0-r5, r7, r9, r11, lr}
        bl      v7_flush_dcache_louis
        ldmia   r12, {r0-r5, r7, r9, r11, lr}
  • adr     r12, __v7_setup_stack
    • r12=임시 스택용도로 사용할 공간 주소
  • stmia   r12, {r0-r5, r7, r9, r11, lr}
    • 레지스터들을 잠시 백업한다.
  • bl      v7_flush_dcache_louis
    • LoUIS 레벨까지의 d-cache를 flush한다.
  • 백업해 두었던 레지스터들을 복원하다.
        mrc     p15, 0, r0, c0, c0, 0           @ read main ID register
        and     r10, r0, #0xff000000            @ ARM?
        teq     r10, #0x41000000
        bne     3f
        and     r5, r0, #0x00f00000             @ variant
        and     r6, r0, #0x0000000f             @ revision
        orr     r6, r6, r5, lsr #20-4           @ combine variant and revision
        ubfx    r0, r0, #4, #12                 @ primary part number
  •  mrc     p15, 0, r0, c0, c0, 0
    • ERRATA 루틴들을 적용하기 위해 확인목적으로 read MIDR 한다.
    • MIDR(Main ID Register)
      • Implementer[31:24]: 0x41=ARM
      • Variant[23:20]: Major Revision Number
      • Architecture[19:16]: 0xf=ARMv7
      • Primary_Part_Number[15:4]: 0xc07=Cortex A7 MPCore
      • Revision[3:0]: Minor Revision Number
  • bne     3f
    • ARM이 아니면 3f로 jump
  • and     r5, r0, #0x00f00000
    • r5=MIDR.variant 부분만 추출
  • and     r6, r0, #0x0000000f
    • r6=MIDR.revision 부분만 추출
  • orr     r6, r6, r5, lsr #20-4
    • r5를 우측으로 16비트 쉬프트하여 r6와 합친다.
    • r6[7:4]=variant, r6[3:0]=revision
  • ubfx    r0, r0, #4, #12
    • r0=r0를 우측으로 4비트 쉬프트한 후 lsb 12비트만을 가져온다.
    • 결국 MIDR.Primary_Part_Number 부분만 추출한다.
    • rpi2: r0=0xc07
        /* Cortex-A8 Errata */
        ldr     r10, =0x00000c08                @ Cortex-A8 primary part number
        teq     r0, r10
        bne     2f
  • 다음은 Cortex-A8용 ERRATA이므로 Cortex-A8이 아니면 2f로 점프
#if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM)

        teq     r5, #0x00100000                 @ only present in r1p*
        mrceq   p15, 0, r10, c1, c0, 1          @ read aux control register
        orreq   r10, r10, #(1 << 6)             @ set IBE to 1
        mcreq   p15, 0, r10, c1, c0, 1          @ write aux control register
#endif
#ifdef CONFIG_ARM_ERRATA_458693
        teq     r6, #0x20                       @ only present in r2p0
        mrceq   p15, 0, r10, c1, c0, 1          @ read aux control register
        orreq   r10, r10, #(1 << 5)             @ set L1NEON to 1
        orreq   r10, r10, #(1 << 9)             @ set PLDNOP to 1
        mcreq   p15, 0, r10, c1, c0, 1          @ write aux control register
#endif
#ifdef CONFIG_ARM_ERRATA_460075
        teq     r6, #0x20                       @ only present in r2p0
        mrceq   p15, 1, r10, c9, c0, 2          @ read L2 cache aux ctrl register
        tsteq   r10, #1 << 22
        orreq   r10, r10, #(1 << 22)            @ set the Write Allocate disable bit
        mcreq   p15, 1, r10, c9, c0, 2          @ write the L2 cache aux ctrl register
#endif
        b       3f

 

        /* Cortex-A9 Errata */
2:      ldr     r10, =0x00000c09                @ Cortex-A9 primary part number
        teq     r0, r10
        bne     3f
  • 다음은 Cortex-A9용 ERRATA이므로 Cortex-A9이 아니면 3f로 점프
#ifdef CONFIG_ARM_ERRATA_742230
        cmp     r6, #0x22                       @ only present up to r2p2
        mrcle   p15, 0, r10, c15, c0, 1         @ read diagnostic register
        orrle   r10, r10, #1 << 4               @ set bit #4
        mcrle   p15, 0, r10, c15, c0, 1         @ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_742231
        teq     r6, #0x20                       @ present in r2p0
        teqne   r6, #0x21                       @ present in r2p1
        teqne   r6, #0x22                       @ present in r2p2
        mrceq   p15, 0, r10, c15, c0, 1         @ read diagnostic register
        orreq   r10, r10, #1 << 12              @ set bit #12
        orreq   r10, r10, #1 << 22              @ set bit #22
        mcreq   p15, 0, r10, c15, c0, 1         @ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_743622
        teq     r5, #0x00200000                 @ only present in r2p*
        mrceq   p15, 0, r10, c15, c0, 1         @ read diagnostic register
        orreq   r10, r10, #1 << 6               @ set bit #6
        mcreq   p15, 0, r10, c15, c0, 1         @ write diagnostic register
#endif
#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)
        ALT_SMP(cmp r6, #0x30)                  @ present prior to r3p0
        ALT_UP_B(1f)
        mrclt   p15, 0, r10, c15, c0, 1         @ read diagnostic register
        orrlt   r10, r10, #1 << 11              @ set bit #11
        mcrlt   p15, 0, r10, c15, c0, 1         @ write diagnostic register
1:
#endif

 

        /* Cortex-A15 Errata */
3:      ldr     r10, =0x00000c0f                @ Cortex-A15 primary part number
        teq     r0, r10
        bne     4f
  • 다음은 Cortex-A15용 ERRATA이므로 Cortex-A15가 아니면 4f로 점프
#ifdef CONFIG_ARM_ERRATA_773022
        cmp     r6, #0x4                        @ only present up to r0p4
        mrcle   p15, 0, r10, c1, c0, 1          @ read aux control register
        orrle   r10, r10, #1 << 1               @ disable loop buffer
        mcrle   p15, 0, r10, c1, c0, 1          @ write aux control register
#endif

 

4:      mov     r10, #0
        mcr     p15, 0, r10, c7, c5, 0          @ I+BTB cache invalidate
#ifdef CONFIG_MMU
        mcr     p15, 0, r10, c8, c7, 0          @ invalidate I + D TLBs
        v7_ttb_setup r10, r4, r8, r5            @ TTBCR, TTBRx setup
        ldr     r5, =PRRR                       @ PRRR
        ldr     r6, =NMRR                       @ NMRR
        mcr     p15, 0, r5, c10, c2, 0          @ write PRRR
        mcr     p15, 0, r6, c10, c2, 1          @ write NMRR
#endif
        dsb                                     @ Complete invalidations
  • mcr     p15, 0, r10, c7, c5, 0
    • invalidate all i-cache to PoU (ICIALLU)
  • mcr     p15, 0, r10, c8, c7, 0
    • invalidate TLB cache all (TLBIALL)
  • v7_ttb_setup r10, r4, r8, r5
    • arch/arm/mm/proc-v7-2level.S
    • .macro      v7_ttb_setup, zero, ttbr0, ttbr1, tmp
      • zero: TTBCR에서 사용할 0값이 담겨 있어야 한다.
      • ttbr0 |= TTB_RGN_WBWA|TTB_S -> 기록하지 않음.
      • ttbr1 |= TTB_RGN_WBWA|TTB_S -> 실제기록까지함.
      • tmp: 사용하지 않는다.
    • r10: 0
    • r4, r8: 페이지테이블 물리주소 |= TTB_RGN_WBWA|TTB_S
  • mcr     p15, 0, r5, c10, c2, 0
    • r5: 0xff0a_81a8 (PRRR)
  • mcr     p15, 0, r6, c10, c2, 1
    • r6: 0x40e0_40e0(NMRR)
#ifndef CONFIG_ARM_THUMBEE
        mrc     p15, 0, r0, c0, c1, 0           @ read ID_PFR0 for ThumbEE
        and     r0, r0, #(0xf << 12)            @ ThumbEE enabled field
        teq     r0, #(1 << 12)                  @ check if ThumbEE is present
        bne     1f
        mov     r5, #0
        mcr     p14, 6, r5, c1, c0, 0           @ Initialize TEEHBR to 0
        mrc     p14, 6, r0, c0, c0, 0           @ load TEECR
        orr     r0, r0, #1                      @ set the 1st bit in order to
        mcr     p14, 6, r0, c0, c0, 0           @ stop userspace TEEHBR access
1:
#endif
  • mrc     p15, 0, r0, c0, c1, 0
    • read ID_PFR0.ThumbEE[15..12]: 12번비트가 1이면 ThumbEE가 지원됨.
  • teq     r0, #(1 << 12)
    • ThumbEE 비트가 1인 경우 z flag가 1이 된다. (xor)
  • bne     1f
    • 0이 아니면(ThumbEE가 없으면) jump
        adr     r5, v7_crval
        ldmia   r5, {r5, r6}
 ARM_BE8(orr    r6, r6, #1 << 25)               @ big-endian page tables
#ifdef CONFIG_SWP_EMULATE
        orr     r5, r5, #(1 << 10)              @ set SW bit in "clear"
        bic     r6, r6, #(1 << 10)              @ clear it in "mmuset"
#endif
        mrc     p15, 0, r0, c1, c0, 0           @ read control register
        bic     r0, r0, r5                      @ clear bits them
        orr     r0, r0, r6                      @ set them
 THUMB( orr     r0, r0, #1 << 30        )       @ Thumb exceptions
        ret     lr                              @ return to head.S:__ret
        .space 256
ENDPROC(__v7_setup)
  • adr     r5, v7_crval
    • v7_crval는 arch/arm/mm/proc-v7-2level.S에 있음
  • ldmia   r5, {r5, r6}
    • r5=0x2120c302 (for bit clear)
    • r6=0x10c03c7d (for orr)
  • mrc     p15, 0, r0, c1, c0, 0
    • SCTLR을 r0에 읽어 들인다.
  • bic     r0, r0, r5
    • r5로 bit clear
  • orr     r0, r0, r6
    • r6를 더한다
  • ret     lr
    • lr=__enable_mmu: 의 물리 주소가 담겨 있음.

 

__v7_setup_stack:

        .align  2
__v7_setup_stack:
        .space  4 * 11                          @ 11 registers

 

 

v7_ttb_setup 매크로

        /*
         * Macro for setting up the TTBRx and TTBCR registers.
         * - \ttb0 and \ttb1 updated with the corresponding flags.
         */

        .macro  v7_ttb_setup, zero, ttbr0, ttbr1, tmp 
        mcr     p15, 0, \zero, c2, c0, 2        @ TTB control register
        ALT_SMP(orr     \ttbr0, \ttbr0, #TTB_FLAGS_SMP)
        ALT_UP(orr      \ttbr0, \ttbr0, #TTB_FLAGS_UP)
        ALT_SMP(orr     \ttbr1, \ttbr1, #TTB_FLAGS_SMP)
        ALT_UP(orr      \ttbr1, \ttbr1, #TTB_FLAGS_UP)
        mcr     p15, 0, \ttbr1, c2, c0, 1       @ load TTB1
        .endm
  • mcr     p15, 0, \zero, c2, c0, 2
    • TTBCR에 zero(0)를 기록한다.
  • ALT_SMP:
    • ttbr0 |= (TTB_RGN_WBWA|TTB_S)
    • ttbr1 |= (TTB_RGN_WBWA|TTB_S)
  • mcr     p15, 0, \ttbr1, c2, c0, 1
    • TTBR1에 ttbr1을 기록한다.
    • global 커널 페이지 테이블용으로 백업해두고 커널에 진입할 때 마다 ttbr0에 복사하여 사용

 

v7_crval:

arch/arm/mm/proc-v7-2level.S

        /*   AT 
         *  TFR   EV X F   I D LR    S
         * .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM
         * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced 
         *   01    0 110       0011 1100 .111 1101 < we want
         */
        .align  2
        .type   v7_crval, #object
v7_crval:
        crval   clear=0x2120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c
  • clear
    • AFE, VE, FI, Bit[15], RR, Bit[9], Bit[8], A
  • mmuset
    • TRE, Bit[23], U, V, I, Z, SW, Bit[6], CP15BEN, Bit[4], Bit[3], C, M
  • ucset
    • Bit[23], U, I, Z, SW, Bit[6], CP15BEN, Bit[4], Bit[3], C
  • SCTLR
    • Bit[31]: 0
    • TE[30]: Thumb Exception enable. 0=ARM state, 1=Thumb state
    • AFE[29]: Access Flag Enable. 0=full range, 1=simplified model
    • TRE[28]: TEX remap enable.
    • NMFI[27]: Non-maskable FIQ support. 0=SW can mask, 1=SW can not mask
    • Bit[26]: 0
    • EE[25]: Exception Endianness. 0=Little-endian, 1=Big-endian
    • VE[24]: Interrupt Vectors Enable: 0=use FIQ and IRQ vectors. 1=impl.
    • Bit[23]: 1
    • U[22]: Alignment support on page (ARMv7에서 1)
    • FI[21]: Fast Interrupts configuration enable. 0=All performance features enabled, 1=low interrupt latency. (some performance feature is disabled)
    • UWXN[20]: Unprivileged Write permission implies PL1 XN (for VE)
    • WXN[19]: Write permission implies XN (for VE)
    • Bit[20:19]: 0
    • Bit[18]: 1
    • HA[17]: Hardware Access flag enable.
    • Bit[16]: 1
    • Bit[15]: 0
    • RR[14]: Round Robin select. 0=normal(random), 1=Predictable strategy. (RR)
    • V[13]: Vectors bit. 0=0x0000_0000, 1=0xFFFF_0000
    • I[12]: Instruction Cache enable.
    • Z[11]: Branch Prediction enable.
    • SW[10]: SWP and SWPB enable
    • Bit[9:8]: 0
    • B[7]: Endian support on page (ARMv7에서 0)
    • Bit[6]: 1
    • CP15BEN[5]: CP15 barrier enable
    • Bit[4:3]: 1
    • C[2]: Cache enable
    • A[1]: Alignment check enable
    • M[0]: MMU enable

sctlr

 

crval 매크로

        .macro  crval, clear, mmuset, ucset
#ifdef CONFIG_MMU
        .word   \clear
        .word   \mmuset
#else
        .word   \clear
        .word   \ucset
#endif
        .endm

 

참고

댓글 남기기