// Copyright 2016 The Fuchsia Authors // Copyright (c) 2014, Google Inc. All rights reserved // // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT /* MIT License Copyright (c) 2018 Sergey Matyukevich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * ChCore refers to both * https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md * and Google Zircon for implementing the boot helper functions. */ #include #include #define CURRENTEL_EL1 (0b01 << 2) #define CURRENTEL_EL2 (0b10 << 2) #define CPACR_EL1_FPEN (0b11 << 20) #define ID_AA64PFR0_EL1_GIC (0b1111 << 24) #define CNTHCTL_EL2_EL1PCEN (1 << 1) #define CNTHCTL_EL2_EL1PCTEN (1 << 0) #define CPTR_EL2_RES1 0x33ff #define HCR_EL2_RW (1 << 31) #define ICC_SRE_EL2_SRE (1 << 0) #define ICC_SRE_EL2_ENABLE (1 << 3) #define SCR_EL3_HCE (1 << 8) #define SCR_EL3_NS (1 << 0) #define SCR_EL3_RW (1 << 10) #define SPSR_ELX_DAIF (0b1111 << 6) #define SPSR_ELX_EL1H (0b0101) #define ICH_HCR_EL2 S3_4_C12_C11_0 #define ICC_SRE_EL2 S3_4_C12_C9_5 BEGIN_FUNC(arm64_elX_to_el1) mrs x9, CurrentEL // Check the current exception level. cmp x9, CURRENTEL_EL1 beq .Ltarget cmp x9, CURRENTEL_EL2 beq .Lin_el2 // Otherwise, we are in EL3. // Set EL2 to 64bit and enable the HVC instruction. mrs x9, scr_el3 mov x10, SCR_EL3_NS | SCR_EL3_HCE | SCR_EL3_RW orr x9, x9, x10 msr scr_el3, x9 // Set the return address and exception level. adr x9, .Ltarget msr elr_el3, x9 mov x9, SPSR_ELX_DAIF | SPSR_ELX_EL1H msr spsr_el3, x9 .Lin_el2: // Disable EL1 timer traps and the timer offset. mrs x9, cnthctl_el2 orr x9, x9, CNTHCTL_EL2_EL1PCEN | CNTHCTL_EL2_EL1PCTEN msr cnthctl_el2, x9 msr cntvoff_el2, xzr // Disable stage 2 translations. msr vttbr_el2, xzr // Disable EL2 coprocessor traps. mov x9, CPTR_EL2_RES1 msr cptr_el2, x9 // Disable EL1 FPU traps. mov x9, CPACR_EL1_FPEN msr cpacr_el1, x9 // Check whether the GIC system registers are supported. mrs x9, id_aa64pfr0_el1 and x9, x9, ID_AA64PFR0_EL1_GIC cbz x9, .Lno_gic_sr // Enable the GIC system registers in EL2, and allow their use in EL1. mrs x9, ICC_SRE_EL2 mov x10, ICC_SRE_EL2_ENABLE | ICC_SRE_EL2_SRE orr x9, x9, x10 msr ICC_SRE_EL2, x9 // Disable the GIC virtual CPU interface. msr ICH_HCR_EL2, xzr .Lno_gic_sr: // Set EL1 to 64bit. mov x9, HCR_EL2_RW msr hcr_el2, x9 // Set the return address and exception level. adr x9, .Ltarget msr elr_el2, x9 mov x9, SPSR_ELX_DAIF | SPSR_ELX_EL1H msr spsr_el2, x9 isb eret .Ltarget: ret END_FUNC(arm64_elX_to_el1) BEGIN_FUNC(invalidate_cache_all) mrs x0, clidr_el1 and w3, w0, #0x07000000 // get 2x level of coherence lsr w3, w3, #23 cbz w3, .Lfinished_inv_cache mov w10, #0 // w10 = 2x cache level mov w8, #1 // w8 = constant 1 .Lloop1_inv_cache: add w2, w10, w10, lsr #1 // calculate 3x cache level lsr w1, w0, w2 // extract 3 bit cache type for this level and w1, w1, #0x7 cmp w1, #2 b.lt .Lskip_inv_cache // no data or unified cache at this level msr csselr_el1, x10 // select this cache level isb // synchronize change to csselr mrs x1, ccsidr_el1 // w1 = ccsidr and w2, w1, #7 // w2 = log2(line len) - 4 add w2, w2, #4 // w2 = log2(line len) ubfx w4, w1, #3, #10 // w4 = max way number, right aligned clz w5, w4 // w5 = 32 - log2(ways), bit position of way in DC operand lsl w9, w4, w5 // w9 = max way number, aligned to position in DC operand lsl w12, w8, w5 // w12 = amount to decrement way number per iteration .Lloop2_inv_cache: ubfx w7, w1, #13, #15 // w7 = max set number, right aligned lsl w7, w7, w2 // w7 = max set number, aligned to position in DC operand lsl w13, w8, w2 // w13 = amount to decrement set number per iteration .Lloop3_inv_cache: orr w11, w10, w9 // w11 = combine way number and cache number orr w11, w11, w7 // and set number for DC operand dc isw, x11 // data cache op subs w7, w7, w13 // decrement set number b.ge .Lloop3_inv_cache subs w9, w9, w12 // decrement way number b.ge .Lloop2_inv_cache .Lskip_inv_cache: add w10, w10, #2 // increment 2x cache level cmp w3, w10 dsb sy // ensure completetion of previous cache maintainance instructions b.gt .Lloop1_inv_cache .Lfinished_inv_cache: // dump the instruction cache as well ic iallu isb ret END_FUNC(invalidate_cache_all) .extern boot_ttbr0_l0 .extern boot_ttbr1_l0 /* Device-nGnRE memory */ #define MMU_MAIR_ATTR1 (0x04 << (8 * 1)) /* Normal Memory, Outer Write-back non-transient Read/Write allocate, * Inner Write-back non-transient Read/Write allocate */ #define MMU_MAIR_ATTR2 (0xff << (8 * 2)) /* Normal Memory, Inner/Outer uncached, Write Combined */ #define MMU_MAIR_ATTR3 (0x44 << (8 * 3)) /* * Enable cached page table walks: * inner/outer (IRGN/ORGN): write-back + write-allocate */ #define MMU_TCR_TG1_4k (0 << 14) #define MMU_TCR_SH1_INNER_SH (3 << 28) #define MMU_TCR_ORGN1_WBA (1 << 26) #define MMU_TCR_IRGN1_WBA (1 << 24) #define MMU_TCR_T1SZ ((64 - 48) << 16) /* 48-bit */ #define MMU_TCR_FLAGS1 (MMU_TCR_TG1_4k | MMU_TCR_SH1_INNER_SH | \ MMU_TCR_ORGN1_WBA | MMU_TCR_IRGN1_WBA | MMU_TCR_T1SZ) #define MMU_TCR_TG0_4k (0 << 30) #define MMU_TCR_SH0_INNER_SH (3 << 12) #define MMU_TCR_ORGN0_WBA (1 << 10) #define MMU_TCR_IRGN0_WBA (1 << 8) #define MMU_TCR_T0SZ ((64 - 48) << 0) /* 48-bit */ #define MMU_TCR_FLAGS0 (MMU_TCR_TG0_4k | MMU_TCR_SH0_INNER_SH | \ MMU_TCR_ORGN0_WBA | MMU_TCR_IRGN0_WBA | MMU_TCR_T0SZ) #define MMU_TCR_IPS (0b101 << 32) /* 48-bit */ #define MMU_TCR_AS (1 << 36) BEGIN_FUNC(el1_mmu_activate) stp x29, x30, [sp, #-16]! mov x29, sp bl invalidate_cache_all /* Invalidate TLB */ tlbi vmalle1is isb dsb sy /* Initialize Memory Attribute Indirection Register */ ldr x8, =MMU_MAIR_ATTR1 | MMU_MAIR_ATTR2 | MMU_MAIR_ATTR3 msr mair_el1, x8 /* Initialize TCR_EL1 */ /* set cacheable attributes on translation walk */ /* (SMP extensions) non-shareable, inner write-back write-allocate */ ldr x8, =MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0 | MMU_TCR_IPS | MMU_TCR_AS msr tcr_el1, x8 isb /* Write ttbr with phys addr of the translation table */ adrp x8, boot_ttbr0_l0 msr ttbr0_el1, x8 adrp x8, boot_ttbr1_l0 msr ttbr1_el1, x8 isb mrs x8, sctlr_el1 /* Enable MMU */ orr x8, x8, #SCTLR_EL1_M /* Disable alignment checking */ bic x8, x8, #SCTLR_EL1_A bic x8, x8, #SCTLR_EL1_SA0 bic x8, x8, #SCTLR_EL1_SA orr x8, x8, #SCTLR_EL1_nAA /* Data accesses Cacheable */ orr x8, x8, #SCTLR_EL1_C /* Instruction access Cacheable */ orr x8, x8, #SCTLR_EL1_I msr sctlr_el1, x8 ldp x29, x30, [sp], #16 ret END_FUNC(el1_mmu_activate) /* These simple function is written by ChCorers */ BEGIN_FUNC(early_put32) str w1, [x0] ret END_FUNC(early_put32) BEGIN_FUNC(early_get32) ldr w0, [x0] ret END_FUNC(early_get32) BEGIN_FUNC(delay) subs x0, x0, #1 bne delay ret END_FUNC(delay)