diff options
author | John Rigby <john.rigby@linaro.org> | 2012-03-27 09:36:17 -0600 |
---|---|---|
committer | John Rigby <john.rigby@linaro.org> | 2012-03-27 09:36:17 -0600 |
commit | 891a674c57a0a1e4a2b871d5b6e874857e977ef5 (patch) | |
tree | 4cdc25fb8fe7352086da9a16cc1a9555a2d1f400 | |
parent | f0d8629d72fea2d76060d97c2f463e17c67ec844 (diff) |
Add linaro directory which contains the bootwrapper
Signed-off-by: John Rigby <john.rigby@linaro.org>
108 files changed, 17657 insertions, 0 deletions
diff --git a/linaro/arm-virt-bl/.gitignore b/linaro/arm-virt-bl/.gitignore new file mode 100644 index 0000000..c6a5595 --- /dev/null +++ b/linaro/arm-virt-bl/.gitignore @@ -0,0 +1,23 @@ +# git-ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ +*~ +.cproject +.project +*.o +*.a +*.axf +*.bin +*.d +*.map +*.s +*.spp +*.scf +*.zi +bl_syms.txt +bl_sec_syms.txt +bl.S +bl_sec.S diff --git a/linaro/arm-virt-bl/Release_Notes.txt b/linaro/arm-virt-bl/Release_Notes.txt new file mode 100644 index 0000000..3c48778 --- /dev/null +++ b/linaro/arm-virt-bl/Release_Notes.txt @@ -0,0 +1,253 @@ +Release notes +============= + +1. Preface + + a. Proprietary notice + + Copyright (c) 2012, ARM Limited + All rights reserved. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER + 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. + + b. License details + + Copyright (c) 2009-12, ARM Limited. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of ARM nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + c. Document confidentiality status + + Redistribution of source and compiled code is subject to the + license terms above. + + d. Product status + + ARM Virtualizer for Cortex-A15/Cortex-A7 Task Migration v2.2 + + e. Web address + + Not applicable. + + f. Feedback on the ARM Virtualizer software + + None at present. + + g. Feedback on this release note document + + None at present. + +2. Release details + + a. Product release status + + v2.2 + + b. ARM Virtualizer software release v2.2 + + This software release is a v2.2 snapshot of the ARM + Virtualizer software. + + The ARM Virtualizer software is example code that demonstrates + cluster context switching capability on a coherent dual + cluster system composed of a Cortex-A7 cluster and a + Cortex-A15 cluster. + + The intent behind this delivery is to allow + inspection of the software architecture and to + demonstrate existing functionality. + + It is possible to execute the ARM Virtualizer software on a + Real-Time System Model (RTSM_VE_Cortex_A15x1_A7x1 and + RTSM_VE_Cortex_A15x4_A7x4). + + This model may be obtained from ARM by separate arrangement. + + c. Deliverables + + This release contains the following file: + + 1. arm-virtualizer-v2_2-160212.tar.bz2 + + - Contains source code for a basic boot wrapper. + + This boot wrapper performs minimal system initialization + and boots the system with the Virtualizer code. It also + permits booting the system with an optional Linux kernel + image and an accompanying root filesystem [both NOT + supplied with this release]. + + - Contains source code for the ARM Virtualizer software. + + - Contains pertinent documentation covering the + release components, their installation and usage. + + d. Functionality included + + This release of the ARM Virtualizer software is capable of rapid + and robust cluster context switching on a coherent system + between a cluster of up to four Cortex-A7 processors and a + cluster of up to four Cortex-A15 processors. + + In addition, this release of the ARM Virtualizer software + permits payload software (bare-metal software or a Linux + operating system kernel) built for the Cortex-A15 processor + cluster to run un-modified on a Cortex-A7 processor cluster. + + This release does not support execution of software built for the + Cortex-A7 cluster on the Cortex-A15 cluster. + + e. New features + + Release v2.2 is a bug fix only release. + + f. Known issues + + 1. This release does not support execution of software + built for the Cortex-A7 cluster on the Cortex-A15 + cluster. + + 2. This release is intended to be built in a Linux development + environment. Environments other than Linux are not supported. + + 3. The cache level chosen through a write to the CSSELR on the + Cortex-A7 cluster is not migrated to the Cortex-A15 cluster during + a subsequent migration. + + 4. Differences in the characteristics of the I-Cache between the + Cortex-A7 and Cortex-A15 are not hidden through the use of + Virtualization extensions by the Virtualizer. + + g. Issues resolved since last release + + 1. Bug fixes + + v2.1: + + 1. vGIC HYP view interface handling code in (common/vgiclib.c) now + detects the number of implemented list registers from the vgic + type register instead of assuming that the maximum (64) will be + present. + + v2.1 to v2.2: + + 1. Issue an DCCISW and not a DCCSW when DCCSIW was trapped in + trap_cp15_mrc_mcr_handle (big-little/virtualisor/virt_handle.c). + + A DCCISW (Data Cache clean and invalidate by set/way) operation + was being implemented as a DCCSW (Data Cache clean by set/way) + operation by the Virtualizer. + + 2. Calculate l2_desc correctly in CreateL3PageTable + (big-little/common/pagetable_setup.c) for level equal 2. + + Correct index into Level-2 page table of the 2nd Stage + translations is being calculated when CreateL3PageTable() is + called to add a L3 page table for IPAs > 1GB. + + 3. Create second 4KB 2nd stage mapping for VGIC in + Create2ndStagePageTables + (big-little/common/pagetable_setup.c). + + Mapping added to 2nd stage translation tables to cover the 2nd + 4K memory map of the physical cpu interface of the vGIC (cpu + interface base + 0x1000). + + 4. Fix race condition during enabling CCI coherency in warm_reset + (big-little/secure_world/monmode_vectors.s). + + A race condition existed while enabling CCI coherency after a + warm reset in the Secure world code. This could have lead to a + case where cpus1-3 start restoring the saved context without + taking part in CCI based coherency for a brief period of time. + + h. Test cases and results + + In accordance with the delivery’s status as example code, testing is + sufficient to prove robustness of the basic implementation but does + not provide full coverage for all use cases. + + 1. This release has been tested for correct cluster switching + operation at ~12 million cycle switching intervals with + bare-metal and Linux kernel payloads. + + 2. This release has been tested using a select subset of an ARM + internal Linux based stress testing suite. + + i. Other information + + Not applicable. + +3. Documentation + + The docs subdirectory contains the following notes: + + 01-Usage.txt: General installation and usage instructions. + + 02-Code-layout.txt: Overview of the code layout. + + 03-Linux-kernel-build.txt: Instructions on obtaining and + building a Linux kernel image suitable for the virtualizer. + + 04-Cache-hit-rate-howto.txt: Description of the MTI trace + plugin infrastructure and ways to use the trace for + estimating snoop hit rates across cluster switches. + + 05-FAQ.txt: Placeholder for commonly asked questions with + answers. + + 06-Optional-rootfs-build.txt: Instructions for building and + using rootfilesystems with the virtualizer. + +4. Tools + + a. Tools + + 1. ARM Development Studio 5 - Version 5.8. + + 2. Real-Time System Model v7.0.1 (RTSM_VE_Cortex_A15x1_A7x1 + and RTSM_VE_Cortex_A15x4_A7x4). + + b. Operating systems + + 1. Ubuntu 10.10. + + 2. Red Hat Enterprise Linux WS release 4 (Nahant Update 4). + +5. Support + + ARM provides this software release purely as example software and + absolves itself of any support burden. ARM is open to receiving any + constructive feedback and at it's discretion, will endeavour to + incorporate any feedback in subsequent releases of this example + software. + diff --git a/linaro/arm-virt-bl/acsr/c_helpers.c b/linaro/arm-virt-bl/acsr/c_helpers.c new file mode 100644 index 0000000..a7df858 --- /dev/null +++ b/linaro/arm-virt-bl/acsr/c_helpers.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/** + * Lamport's Bakery algorithm for spinlock handling + * + * Note that the algorithm requires the stack and the bakery struct + * to be in Strongly-Ordered memory. + */ + +#include "appf_types.h" +#include "appf_internals.h" +#include "appf_helpers.h" + +/** + * Initialize a bakery - only required if the bakery_t is + * on the stack or heap, as static data is zeroed anyway. + */ +void initialize_spinlock(bakery_t * bakery) +{ + appf_memset(bakery, 0, sizeof(bakery_t)); +} + +/** + * Claim a bakery lock. Function does not return until + * lock has been obtained. + */ +void get_spinlock(unsigned cpuid, bakery_t * bakery) +{ + unsigned i, max = 0, my_full_number, his_full_number; + + /* Get a ticket */ + bakery->entering[cpuid] = TRUE; + for (i = 0; i < MAX_CPUS; ++i) { + if (bakery->number[i] > max) { + max = bakery->number[i]; + } + } + ++max; + bakery->number[cpuid] = max; + bakery->entering[cpuid] = FALSE; + + /* Wait for our turn */ + my_full_number = (max << 8) + cpuid; + for (i = 0; i < MAX_CPUS; ++i) { + while (bakery->entering[i]) ; /* Wait */ + do { + his_full_number = bakery->number[i]; + if (his_full_number) { + his_full_number = (his_full_number << 8) + i; + } + } + while (his_full_number && (his_full_number < my_full_number)); + } + dmb(); +} + +/** + * Release a bakery lock. + */ +void release_spinlock(unsigned cpuid, bakery_t * bakery) +{ + dmb(); + bakery->number[cpuid] = 0; +} diff --git a/linaro/arm-virt-bl/acsr/helpers.S b/linaro/arm-virt-bl/acsr/helpers.S new file mode 100644 index 0000000..944a903 --- /dev/null +++ b/linaro/arm-virt-bl/acsr/helpers.S @@ -0,0 +1,1065 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + EXPORT isb + EXPORT dsb + EXPORT dmb + EXPORT wfi + EXPORT endless_wfi + EXPORT wfe + EXPORT sev + EXPORT copy_words + EXPORT appf_memcpy + EXPORT appf_memset + EXPORT get_cpu_type + EXPORT va_to_pa + + EXPORT read_drar + EXPORT read_dsar + EXPORT read_cbar + EXPORT read_sctlr + EXPORT read_actlr + EXPORT read_prrr + EXPORT read_nmrr + EXPORT read_l2ctlr + EXPORT read_dacr + EXPORT read_ttbr0 + EXPORT read_cpacr + EXPORT read_scr + EXPORT read_cpsr + EXPORT read_midr + EXPORT read_mpidr + EXPORT read_cntpct + EXPORT read_cntfrq + EXPORT read_vmpidr + EXPORT read_vmidr + EXPORT read_vttbr + EXPORT read_httbr + EXPORT read_id_pfr0 + EXPORT read_id_pfr1 + EXPORT read_id_dfr0 + EXPORT read_id_afr0 + EXPORT read_id_mmfr0 + EXPORT read_id_mmfr1 + EXPORT read_id_mmfr2 + EXPORT read_id_mmfr3 + EXPORT read_id_isar0 + EXPORT read_id_isar1 + EXPORT read_id_isar2 + EXPORT read_id_isar3 + EXPORT read_id_isar4 + EXPORT read_id_isar5 + EXPORT read_cpuid + EXPORT read_aidr + EXPORT read_ctr + EXPORT read_tcmtr + EXPORT read_tlbtr + EXPORT read_clusterid + EXPORT read_l2ctlr + EXPORT read_hsctlr + EXPORT read_hdfar + EXPORT read_hpfar + EXPORT read_vtcr + EXPORT read_hcr + EXPORT read_hdcr + EXPORT read_hcptr + EXPORT read_hstr + EXPORT read_cnthctl + EXPORT read_cntkctl + EXPORT read_cntp_ctl + EXPORT read_cntp_tval + EXPORT read_cnthp_ctl + EXPORT read_cnthp_tval + EXPORT read_cnthp_cval + EXPORT read_ttbcr + EXPORT read_nsacr + EXPORT read_clidr + EXPORT read_csselr + EXPORT read_ccsidr + EXPORT read_nmrr + EXPORT read_prrr + EXPORT read_mvbar + EXPORT read_vbar + EXPORT read_hsr + EXPORT read_dfar + EXPORT read_ifar + EXPORT read_dfsr + EXPORT read_ifsr + EXPORT read_adfsr + EXPORT read_aifsr + EXPORT read_l2ectlr + EXPORT read_pmuserenr + EXPORT read_pmintenset + EXPORT read_pmintenclr + EXPORT read_pmovsset + EXPORT read_pmccntr + EXPORT read_pmxevtyper + EXPORT read_pmxevcntr + EXPORT read_pmcr + EXPORT read_pmcntenset + EXPORT read_pmcntenclr + EXPORT read_pmovsr + EXPORT read_pmswinc + EXPORT read_pmselr + EXPORT read_pmceid0 + EXPORT read_pmceid1 + + EXPORT write_l2ectlr + EXPORT write_pmuserenr + EXPORT write_pmintenset + EXPORT write_pmintenclr + EXPORT write_pmovsset + EXPORT write_pmccntr + EXPORT write_pmxevtyper + EXPORT write_pmxevcntr + EXPORT write_pmcr + EXPORT write_pmcntenset + EXPORT write_pmcntenclr + EXPORT write_pmovsr + EXPORT write_pmswinc + EXPORT write_pmselr + EXPORT write_pmceid0 + EXPORT write_pmceid1 + EXPORT write_dacr + EXPORT write_prrr + EXPORT write_nmrr + EXPORT write_ttbr0 + EXPORT write_cpacr + EXPORT write_nsacr + EXPORT write_scr + EXPORT write_mvbar + EXPORT write_vbar + EXPORT write_hvbar + EXPORT write_vmpidr + EXPORT write_vmidr + EXPORT write_csselr + EXPORT write_hcr + EXPORT write_hdcr + EXPORT write_hcptr + EXPORT write_hstr + EXPORT write_sctlr + EXPORT write_actlr + EXPORT write_osdlr + EXPORT write_ttbcr + EXPORT write_cntfrq + EXPORT write_cnthctl + EXPORT write_cntkctl + EXPORT write_cntp_ctl + EXPORT write_cntp_tval + EXPORT write_cnthp_ctl + EXPORT write_cnthp_tval + EXPORT write_cnthp_cval + EXPORT write_hsctlr + EXPORT write_httbr + EXPORT write_vttbr + EXPORT write_htcr + EXPORT write_vtcr + EXPORT write_hmair0 + EXPORT write_hmair1 + EXPORT write_dfar + EXPORT write_ifar + EXPORT write_dfsr + EXPORT write_ifsr + EXPORT write_adfsr + EXPORT write_aifsr + + +MIDR_CPU_MASK EQU 0xff00fff0 + + AREA |.text.ACSR|, CODE, ALIGN=5 + + +dmb FUNCTION + dmb + bx lr + ENDFUNC + +wfi FUNCTION + wfi + bx lr + ENDFUNC + + ; WFI forever, and attempt to prevent speculative accesses starting + ; FIQ and IRQ are assumed to be disabled +endless_wfi FUNCTION + b wfistart + + ALIGN 32 +wfistart + b bloop +loop + dsb + wfi +bloop + b loop + ENDFUNC + +wfe FUNCTION + wfe + bx lr + ENDFUNC + +sev FUNCTION + sev + bx lr + ENDFUNC + + ; This function takes three arguments + ; r0: Destination start address (must be word aligned) + ; r1: Source start address (must be word aligned) + ; r2: Number of words to copy + ; Return value is updated destination pointer (first unwritten word) +copy_words FUNCTION + cmp r2, #0 + beq %f1 +0 ldr r3, [r1], #4 + str r3, [r0], #4 + subs r2, r2, #1 + bne %b0 +1 bx lr + ENDFUNC + + +appf_memcpy FUNCTION + cmp r2, #0 + bxeq lr +0 ldrb r3, [r1], #1 + strb r3, [r0], #1 + subs r2, #1 + bne %b0 + bx lr + ENDFUNC + +appf_memset FUNCTION + cmp r2, #0 + bxeq lr +0 strb r1, [r0], #1 + subs r2, #1 + bne %b0 + bx lr + ENDFUNC + +read_cntfrq FUNCTION + mrc p15, 0, r0, c14, c0, 0 + bx lr + ENDFUNC + +write_cntfrq FUNCTION + mcr p15, 0, r0, c14, c0, 0 + bx lr + ENDFUNC + +read_cntpct FUNCTION + mrrc p15, 0, r0, r1, c14 + bx lr + ENDFUNC + +isb FUNCTION + isb + bx lr + ENDFUNC + +read_vmpidr FUNCTION + mrc p15, 4, r0, c0, c0, 5 + bx lr + ENDFUNC + +read_vmidr FUNCTION + mrc p15, 4, r0, c0, c0, 0 + bx lr + ENDFUNC + +read_id_pfr0 FUNCTION + mrc p15, 0, r0, c0, c1, 0 + bx lr + ENDFUNC + +read_id_pfr1 FUNCTION + mrc p15, 0, r0, c0, c1, 1 + bx lr + ENDFUNC + +read_id_dfr0 FUNCTION + mrc p15, 0, r0, c0, c1, 2 + bx lr + ENDFUNC + +read_id_afr0 FUNCTION + mrc p15, 0, r0, c0, c1, 3 + bx lr + ENDFUNC + +read_id_mmfr0 FUNCTION + mrc p15, 0, r0, c0, c1, 4 + bx lr + ENDFUNC + +read_id_mmfr1 FUNCTION + mrc p15, 0, r0, c0, c1, 5 + bx lr + ENDFUNC + +read_id_mmfr2 FUNCTION + mrc p15, 0, r0, c0, c1, 6 + bx lr + ENDFUNC + +read_id_mmfr3 FUNCTION + mrc p15, 0, r0, c0, c1, 7 + bx lr + ENDFUNC + +read_id_isar0 FUNCTION + mrc p15, 0, r0, c0, c2, 0 + bx lr + ENDFUNC + +read_id_isar1 FUNCTION + mrc p15, 0, r0, c0, c2, 1 + bx lr + ENDFUNC + +read_id_isar2 FUNCTION + mrc p15, 0, r0, c0, c2, 2 + bx lr + ENDFUNC + +read_id_isar3 FUNCTION + mrc p15, 0, r0, c0, c2, 3 + bx lr + ENDFUNC + +read_id_isar4 FUNCTION + mrc p15, 0, r0, c0, c2, 4 + bx lr + ENDFUNC + +read_id_isar5 FUNCTION + mrc p15, 0, r0, c0, c2, 5 + bx lr + ENDFUNC + +read_ctr FUNCTION + mrc p15, 0, r0, c0, c0, 1 + bx lr + ENDFUNC + +read_tcmtr FUNCTION + mrc p15, 0, r0, c0, c0, 2 + bx lr + ENDFUNC + +read_tlbtr FUNCTION + mrc p15, 0, r0, c0, c0, 3 + bx lr + ENDFUNC + +read_aidr FUNCTION + mrc p15, 1, r0, c0, c0, 7 + bx lr + ENDFUNC + +read_dacr FUNCTION + mrc p15, 0, r0, c3, c0, 0 + bx lr + ENDFUNC + +read_ttbr0 FUNCTION + mrc p15, 0, r0, c2, c0, 0 + bx lr + ENDFUNC + +write_dacr FUNCTION + mcr p15, 0, r0, c3, c0, 0 + isb + bx lr + ENDFUNC + +read_cpacr FUNCTION + mrc p15, 0, r0, c1, c0, 2 + bx lr + ENDFUNC + +write_cpacr FUNCTION + mcr p15, 0, r0, c1, c0, 2 + bx lr + ENDFUNC + +read_midr FUNCTION + mrc p15, 0, r0, c0, c0, 0; + bx lr + ENDFUNC + +read_mpidr FUNCTION + mrc p15, 0, r0, c0, c0, 5 + bx lr + ENDFUNC + +read_scr FUNCTION + mrc p15, 0, r0, c1, c1, 0 + bx lr + ENDFUNC + +write_scr FUNCTION + mcr p15, 0, r0, c1, c1, 0 + dsb + isb + bx lr + ENDFUNC + +write_nsacr FUNCTION + mcr p15, 0, r0, c1, c1, 2 + dsb + isb + bx lr + ENDFUNC + +read_cpsr FUNCTION + mrs r0, CPSR + bx lr + ENDFUNC + +write_mvbar FUNCTION + mcr p15, 0, r0, c12, c0, 1 + bx lr + ENDFUNC + +write_vbar FUNCTION + mcr p15, 0, r0, c12, c0, 0 + bx lr + ENDFUNC + +write_hvbar FUNCTION + mcr p15, 4, r0, c12, c0, 0 + bx lr + ENDFUNC + +read_mvbar FUNCTION + mrc p15, 0, r0, c12, c0, 1 + bx lr + ENDFUNC + +read_vbar FUNCTION + mrc p15, 0, r0, c12, c0, 0 + bx lr + ENDFUNC + +read_cpuid FUNCTION + mrc p15, 0, r0, c0, c0, 5 + ands r0, r0, #0xf + bx lr + ENDFUNC + +read_clusterid FUNCTION + mrc p15, 0, r0, c0, c0, 5 + lsr r0, r0, #0x8 + ands r0, r0, #0xf + bx lr + ENDFUNC + +write_ttbr0 FUNCTION + mcr p15, 0, r0, c2, c0, 0 + mcr p15, 0, r0, c7, c5, 6 + mcr p15, 0, r0, c8, c7, 0 + dsb + isb + bx lr + ENDFUNC + +read_ttbcr FUNCTION + mrc p15, 0, r0, c2, c0, 2 + bx lr + ENDFUNC + +write_ttbcr FUNCTION + mcr p15, 0, r0, c2, c0, 2 + bx lr + ENDFUNC + +write_vmpidr FUNCTION + mcr p15, 4, r0, c0, c0, 5 + isb + bx lr + ENDFUNC + +write_vmidr FUNCTION + mcr p15, 4, r0, c0, c0, 0 + isb + bx lr + ENDFUNC + +read_vtcr FUNCTION + mrc p15, 4, r0, c2, c1, 2 + bx lr + ENDFUNC + +read_hcr FUNCTION + mrc p15, 4, r0, c1, c1, 0 + bx lr + ENDFUNC + +read_hdcr FUNCTION + mrc p15, 4, r0, c1, c1, 1 + bx lr + ENDFUNC + +read_hcptr FUNCTION + mrc p15, 4, r0, c1, c1, 2 + bx lr + ENDFUNC + +read_hstr FUNCTION + mrc p15, 4, r0, c1, c1, 3 + bx lr + ENDFUNC + +read_httbr FUNCTION + mrrc p15, 4, r0, r1, c2 + bx lr + ENDFUNC + +read_vttbr FUNCTION + mrrc p15, 6, r0, r1, c2 + bx lr + ENDFUNC + +write_hcr FUNCTION + mcr p15, 4, r0, c1, c1, 0 + dsb + isb + bx lr + ENDFUNC + +write_hdcr FUNCTION + mcr p15, 4, r0, c1, c1, 1 + bx lr + ENDFUNC + +write_hcptr FUNCTION + mcr p15, 4, r0, c1, c1, 2 + bx lr + ENDFUNC + +write_hstr FUNCTION + mcr p15, 4, r0, c1, c1, 3 + bx lr + ENDFUNC + +write_httbr FUNCTION + mcrr p15, 4, r0, r1, c2 + mcr p15, 0, r0, c7, c5, 6 + mcr p15, 0, r0, c8, c7, 0 + dsb + isb + bx lr + ENDFUNC + +write_vttbr FUNCTION + mcrr p15, 6, r0, r1, c2 + mcr p15, 0, r0, c7, c5, 6 + mcr p15, 0, r0, c8, c7, 0 + dsb + isb + bx lr + ENDFUNC + +write_htcr FUNCTION + mcr p15, 4, r0, c2, c0, 2 + bx lr + ENDFUNC + +write_vtcr FUNCTION + mcr p15, 4, r0, c2, c1, 2 + bx lr + ENDFUNC + +write_hmair0 FUNCTION + mcr p15, 4, r0, c10, c2, 0 + bx lr + ENDFUNC + +write_hmair1 FUNCTION + mcr p15, 4, r0, c10, c2, 1 + bx lr + ENDFUNC + +read_nsacr FUNCTION + mrc p15, 0, r0, c1, c1, 2 + bx lr + ENDFUNC + +read_l2ctlr FUNCTION + mrc p15, 1, r0, c9, c0, 2 + bx lr + ENDFUNC + +read_l2ectlr FUNCTION + mrc p15, 1, r0, c9, c0, 3 + bx lr + ENDFUNC + +read_pmuserenr FUNCTION + mrc p15, 0, r0, c9, c14, 0 + bx lr + ENDFUNC + +read_pmintenset FUNCTION + mrc p15, 0, r0, c9, c14, 1 + bx lr + ENDFUNC + +read_pmintenclr FUNCTION + mrc p15, 0, r0, c9, c14, 2 + bx lr + ENDFUNC + +read_pmovsset FUNCTION + mrc p15, 0, r0, c9, c14, 3 + bx lr + ENDFUNC + +read_pmccntr FUNCTION + mrc p15, 0, r0, c9, c13, 0 + bx lr + ENDFUNC + +read_pmxevtyper FUNCTION + mrc p15, 0, r0, c9, c13, 1 + bx lr + ENDFUNC + +read_pmxevcntr FUNCTION + mrc p15, 0, r0, c9, c13, 2 + bx lr + ENDFUNC + +read_pmcr FUNCTION + mrc p15, 0, r0, c9, c12, 0 + bx lr + ENDFUNC + +read_pmcntenset FUNCTION + mrc p15, 0, r0, c9, c12, 1 + bx lr + ENDFUNC + +read_pmcntenclr FUNCTION + mrc p15, 0, r0, c9, c12, 2 + bx lr + ENDFUNC + +read_pmovsr FUNCTION + mrc p15, 0, r0, c9, c12, 3 + bx lr + ENDFUNC + +read_pmswinc FUNCTION + mrc p15, 0, r0, c9, c12, 4 + bx lr + ENDFUNC + +read_pmselr FUNCTION + mrc p15, 0, r0, c9, c12, 5 + bx lr + ENDFUNC + +read_pmceid0 FUNCTION + mrc p15, 0, r0, c9, c12, 6 + bx lr + ENDFUNC + +read_pmceid1 FUNCTION + mrc p15, 0, r0, c9, c12, 7 + bx lr + ENDFUNC + +write_l2ectlr FUNCTION + mcr p15, 1, r0, c9, c0, 3 + bx lr + ENDFUNC + +write_pmuserenr FUNCTION + mcr p15, 0, r0, c9, c14, 0 + bx lr + ENDFUNC + +write_pmintenset FUNCTION + mcr p15, 0, r0, c9, c14, 1 + bx lr + ENDFUNC + +write_pmintenclr FUNCTION + mcr p15, 0, r0, c9, c14, 2 + bx lr + ENDFUNC + +write_pmovsset FUNCTION + mcr p15, 0, r0, c9, c14, 3 + bx lr + ENDFUNC + +write_pmccntr FUNCTION + mcr p15, 0, r0, c9, c13, 0 + bx lr + ENDFUNC + +write_pmxevtyper FUNCTION + mcr p15, 0, r0, c9, c13, 1 + bx lr + ENDFUNC + +write_pmxevcntr FUNCTION + mcr p15, 0, r0, c9, c13, 2 + bx lr + ENDFUNC + +write_pmcr FUNCTION + mcr p15, 0, r0, c9, c12, 0 + bx lr + ENDFUNC + +write_pmcntenset FUNCTION + mcr p15, 0, r0, c9, c12, 1 + bx lr + ENDFUNC + +write_pmcntenclr FUNCTION + mcr p15, 0, r0, c9, c12, 2 + bx lr + ENDFUNC + +write_pmovsr FUNCTION + mcr p15, 0, r0, c9, c12, 3 + bx lr + ENDFUNC + +write_pmswinc FUNCTION + mcr p15, 0, r0, c9, c12, 4 + bx lr + ENDFUNC + +write_pmselr FUNCTION + mcr p15, 0, r0, c9, c12, 5 + bx lr + ENDFUNC + +write_pmceid0 FUNCTION + mcr p15, 0, r0, c9, c12, 6 + bx lr + ENDFUNC + +write_pmceid1 FUNCTION + mcr p15, 0, r0, c9, c12, 7 + bx lr + ENDFUNC + +read_sctlr FUNCTION + mrc p15, 0, r0, c1, c0, 0 + bx lr + ENDFUNC + +write_sctlr FUNCTION + mcr p15, 0, r0, c1, c0, 0 + dsb + isb + bx lr + ENDFUNC + +read_hsctlr FUNCTION + mrc p15, 4, r0, c1, c0, 0 + bx lr + ENDFUNC + +read_hdfar FUNCTION + mrc p15, 4, r0, c6, c0, 0 + bx lr + ENDFUNC + +read_hpfar FUNCTION + mrc p15, 4, r0, c6, c0, 4 + bx lr + ENDFUNC + +read_hsr FUNCTION + mrc p15, 4, r0, c5, c2, 0 + bx lr + ENDFUNC + +write_hsctlr FUNCTION + mcr p15, 4, r0, c1, c0, 0 + dsb + isb + bx lr + ENDFUNC + +read_cnthctl FUNCTION + mrc p15, 4, r0, c14, c1, 0 + bx lr + ENDFUNC + +read_cntkctl FUNCTION + mrc p15, 0, r0, c14, c1, 0 + bx lr + ENDFUNC + +read_cnthp_cval FUNCTION + mrrc p15, 6, r0, r1, c14 + bx lr + ENDFUNC + +read_cnthp_tval FUNCTION + mrc p15, 4, r0, c14, c2, 0 + bx lr + ENDFUNC + +read_cntp_tval FUNCTION + mrc p15, 0, r0, c14, c2, 0 + bx lr + ENDFUNC + +read_cntp_ctl FUNCTION + mrc p15, 0, r0, c14, c2, 1 + bx lr + ENDFUNC + +read_cnthp_ctl FUNCTION + mrc p15, 4, r0, c14, c2, 1 + bx lr + ENDFUNC + +write_cnthctl FUNCTION + mcr p15, 4, r0, c14, c1, 0 + bx lr + ENDFUNC + +write_cntkctl FUNCTION + mcr p15, 0, r0, c14, c1, 0 + bx lr + ENDFUNC + +write_cntp_tval FUNCTION + mcr p15, 0, r0, c14, c2, 0 + isb + bx lr + ENDFUNC + +write_cntp_ctl FUNCTION + mcr p15, 0, r0, c14, c2, 1 + dsb + isb + bx lr + ENDFUNC + +write_cnthp_cval FUNCTION + mcrr p15, 6, r0, r1, c14 + dsb + isb + bx lr + ENDFUNC + +write_cnthp_tval FUNCTION + mcr p15, 4, r0, c14, c2, 0 + dsb + isb + bx lr + ENDFUNC + +write_cnthp_ctl FUNCTION + mcr p15, 4, r0, c14, c2, 1 + dsb + isb + bx lr + ENDFUNC + +read_clidr FUNCTION + mrc p15, 1, r0, c0, c0, 1 ; read clidr + bx lr + ENDFUNC + +read_ccsidr FUNCTION + mrc p15, 1, r0, c0, c0, 0 ; read ccsidr + bx lr + ENDFUNC + +read_csselr FUNCTION + mrc p15, 2, r0, c0, c0, 0 ; read csselr + bx lr + ENDFUNC + +write_csselr FUNCTION + mcr p15, 2, r0, c0, c0, 0 ; read csselr + dsb + isb + bx lr + ENDFUNC + +read_actlr FUNCTION + mrc p15, 0, r0, c1, c0, 1 + bx lr + ENDFUNC + +write_actlr FUNCTION + mcr p15, 0, r0, c1, c0, 1 + dsb + isb + bx lr + ENDFUNC + +read_prrr FUNCTION + mrc p15, 0, r0, c10, c2, 0 + bx lr + ENDFUNC + +read_nmrr FUNCTION + mrc p15, 0, r0, c10, c2, 1 + bx lr + ENDFUNC + +write_prrr FUNCTION + mcr p15, 0, r0, c10, c2, 0 + dsb + isb + bx lr + ENDFUNC + +write_nmrr FUNCTION + mcr p15, 0, r0, c10, c2, 1 + dsb + isb + bx lr + ENDFUNC + +read_dfar FUNCTION + mrc p15, 0, r0, c6, c0, 0 + bx lr + ENDFUNC + +read_ifar FUNCTION + mrc p15, 0, r0, c6, c0, 2 + bx lr + ENDFUNC + +read_dfsr FUNCTION + mrc p15, 0, r0, c5, c0, 0 + bx lr + ENDFUNC + +read_ifsr FUNCTION + mrc p15, 0, r0, c5, c0, 1 + bx lr + ENDFUNC + +read_adfsr FUNCTION + mrc p15, 0, r0, c5, c1, 0 + bx lr + ENDFUNC + +read_aifsr FUNCTION + mrc p15, 0, r0, c5, c1, 1 + bx lr + ENDFUNC + +write_dfar FUNCTION + mcr p15, 0, r0, c6, c0, 0 + dsb + isb + bx lr + ENDFUNC + +write_ifar FUNCTION + mcr p15, 0, r0, c6, c0, 2 + dsb + isb + bx lr + ENDFUNC + +write_dfsr FUNCTION + mcr p15, 0, r0, c5, c0, 0 + dsb + isb + bx lr + ENDFUNC + +write_ifsr FUNCTION + mcr p15, 0, r0, c5, c0, 1 + dsb + isb + bx lr + ENDFUNC + +write_adfsr FUNCTION + mcr p15, 0, r0, c5, c1, 0 + dsb + isb + bx lr + ENDFUNC + +write_aifsr FUNCTION + mcr p15, 0, r0, c5, c1, 1 + dsb + isb + bx lr + ENDFUNC + +read_cbar FUNCTION + mrc p15, 4, r0, c15, c0, 0 ; Read Configuration Base Address Register + bx lr + ENDFUNC + +read_drar FUNCTION + mrc p14, 0, r0, c1, c0, 0 ; Read Debug ROM Address Register + bx lr + ENDFUNC + +read_dsar FUNCTION + mrc p14, 0, r0, c2, c0, 0 ; Read Debug Self Address Offset Register + bx lr + ENDFUNC + +write_osdlr FUNCTION + mcr p14, 0, r0, c1, c3, 4 ; Write OS Double Lock Register + bx lr + ENDFUNC + +get_cpu_type FUNCTION + mrc p15, 0, r0, c0, c0, 0; read MIDR + ldr r1, =MIDR_CPU_MASK + ands r0, r1 + bx lr + ENDFUNC + +dsb FUNCTION + dsb + bx lr + ENDFUNC + +va_to_pa FUNCTION ; Note: assumes conversion will be successful! + mov r1, r0 + mcr p15, 0, r0, c7, c8, 1 ; Priv Write Current World VA-PA + mrc p15, 0, r0, c7, c4, 0 ; Get PA + bfc r0, #0, #12 ; We want top bits of translated addr + bfc r1, #12, #20 ; plus bottom bits of input addr + orr r0, r0, r1 + bx lr + ENDFUNC + + END diff --git a/linaro/arm-virt-bl/acsr/helpers.h b/linaro/arm-virt-bl/acsr/helpers.h new file mode 100644 index 0000000..a4d461e --- /dev/null +++ b/linaro/arm-virt-bl/acsr/helpers.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/* + * V7 functions + */ +extern void save_control_registers(unsigned *pointer, int is_secure); +extern void save_mmu(unsigned *pointer); +extern void save_mpu(unsigned *pointer); +extern void save_performance_monitors(unsigned *pointer); +extern void save_banked_registers(unsigned *pointer); +extern void save_cp15(unsigned *pointer); +extern void save_vfp(unsigned *pointer); +extern void save_generic_timer(unsigned *pointer, int is_hyp); +extern void save_v7_debug(unsigned *pointer); +extern void save_fault_status(unsigned *pointer); + +extern void restore_control_registers(unsigned *pointer, int is_secure); +extern void restore_mmu(unsigned *pointer); +extern void restore_mpu(unsigned *pointer); +extern void restore_performance_monitors(unsigned *pointer); +extern void restore_banked_registers(unsigned *pointer); +extern void restore_cp15(unsigned *pointer); +extern void restore_vfp(unsigned *pointer); +extern void restore_generic_timer(unsigned *pointer, int is_hyp); +extern void restore_v7_debug(unsigned *pointer); +extern void restore_fault_status(unsigned *pointer); + +extern unsigned va_to_pa(unsigned virtual_address); +extern unsigned get_cpu_type(void); + +extern unsigned read_mpidr(void); +extern unsigned read_sctlr(void); +extern unsigned read_actlr(void); +extern unsigned read_prrr(void); +extern unsigned read_nmrr(void); +extern unsigned read_l2ctlr(void); +extern unsigned read_mvbar(void); +extern unsigned read_cbar(void); +extern unsigned read_drar(void); +extern unsigned read_dsar(void); +extern unsigned read_teehbr(void); +extern unsigned read_l2ectlr(void); +extern unsigned read_pmuserenr(void); +extern unsigned read_pmintenset(void); +extern unsigned read_pmintenclr(void); +extern unsigned read_pmovsset(void); +extern unsigned read_pmccntr(void); +extern unsigned read_pmxevtyper(void); +extern unsigned read_pmxevcntr(void); +extern unsigned read_pmcr(void); +extern unsigned read_pmcntenset(void); +extern unsigned read_pmcntenclr(void); +extern unsigned read_pmovsr(void); +extern unsigned read_pmswinc(void); +extern unsigned read_pmselr(void); +extern unsigned read_pmceid0(void); +extern unsigned read_pmceid1(void); +extern unsigned read_dfar(void); +extern unsigned read_ifar(void); +extern unsigned read_dfsr(void); +extern unsigned read_ifsr(void); +extern unsigned read_adfsr(void); +extern unsigned read_aifsr(void); +extern unsigned read_cntfrq(void); +extern unsigned read_hsctlr(void); +extern unsigned read_hsr(void); +extern unsigned read_dacr(void); +extern unsigned read_ttbr0(void); +extern unsigned read_cpacr(void); +extern unsigned read_scr(void); +extern unsigned read_cpsr(void); +extern unsigned read_midr(void); +extern unsigned read_vmpidr(void); +extern unsigned read_vmidr(void); +extern unsigned read_id_pfr0(void); +extern unsigned read_id_pfr1(void); +extern unsigned read_id_dfr0(void); +extern unsigned read_id_afr0(void); +extern unsigned read_id_mmfr0(void); +extern unsigned read_id_mmfr1(void); +extern unsigned read_id_mmfr2(void); +extern unsigned read_id_mmfr3(void); +extern unsigned read_id_isar0(void); +extern unsigned read_id_isar1(void); +extern unsigned read_id_isar2(void); +extern unsigned read_id_isar3(void); +extern unsigned read_id_isar4(void); +extern unsigned read_id_isar5(void); +extern unsigned read_aidr(void); +extern unsigned read_vbar(void); +extern unsigned read_ctr(void); +extern unsigned read_tcmtr(void); +extern unsigned read_tlbtr(void); +extern unsigned read_hcr(void); +extern unsigned read_hdcr(void); +extern unsigned read_hcptr(void); +extern unsigned read_hstr(void); +extern unsigned read_vtcr(void); +extern unsigned read_hdfar(void); +extern unsigned read_hpfar(void); +extern unsigned read_cpsr(void); +extern unsigned read_cpuid(void); +extern unsigned read_clusterid(void); +extern unsigned read_clidr(void); +extern unsigned read_ccsidr(void); +extern unsigned read_csselr(void); +extern unsigned read_nsacr(void); +extern unsigned read_ttbr0(void); +extern unsigned read_ttbcr(void); +extern unsigned read_cnthctl(void); +extern unsigned long read_cnthp_cval(void); +extern unsigned read_cnthp_tval(void); +extern unsigned read_cnthp_ctl(void); +extern unsigned read_cntp_ctl(void); +extern unsigned read_cntp_tval(void); +extern unsigned long long read_httbr(void); +extern unsigned long long read_vttbr(void); +extern unsigned long long read_cntpct(void); + +extern void dsb(void); +extern void dmb(void); +extern void wfi(void); +extern void endless_wfi(void); +extern void wfe(void); +extern void sev(void); +extern void isb(void); + +extern void write_osdlr(unsigned value); +extern void write_sctlr(unsigned value); +extern void write_actlr(unsigned value); +extern void write_nsacr(unsigned); +extern void write_ttbr0(unsigned); +extern void write_ttbcr(unsigned); +extern void write_cntfrq(unsigned); +extern void write_cnthctl(unsigned); +extern void write_cnthp_cval(unsigned, unsigned); +extern void write_cnthp_tval(unsigned); +extern void write_cnthp_ctl(unsigned); +extern void write_cntp_ctl(unsigned); +extern void write_cntp_tval(unsigned); +extern void write_csselr(unsigned); +extern void write_hcr(unsigned); +extern void write_hdcr(unsigned); +extern void write_hcptr(unsigned); +extern void write_hstr(unsigned); +extern void write_hsctlr(unsigned); +extern void write_httbr(unsigned long long); +extern void write_vttbr(unsigned long long); +extern void write_htcr(unsigned); +extern void write_vtcr(unsigned); +extern void write_hmair0(unsigned); +extern void write_hmair1(unsigned); +extern void write_vmpidr(unsigned); +extern void write_vmidr(unsigned); +extern void write_dacr(unsigned); +extern void write_ttbr0(unsigned); +extern void write_cpacr(unsigned); +extern void write_nsacr(unsigned); +extern void write_scr(unsigned); +extern void write_mvbar(unsigned); +extern void write_hvbar(unsigned); +extern void write_vbar(unsigned); +extern void write_prrr(unsigned); +extern void write_nmrr(unsigned); +extern void write_dfar(unsigned); +extern void write_ifar(unsigned); +extern void write_dfsr(unsigned); +extern void write_ifsr(unsigned); +extern void write_adfsr(unsigned); +extern void write_aifsr(unsigned); +extern void write_l2ectlr(unsigned); +extern void write_pmuserenr(unsigned); +extern void write_pmintenset(unsigned); +extern void write_pmintenclr(unsigned); +extern void write_pmovsset(unsigned); +extern void write_pmccntr(unsigned); +extern void write_pmxevtyper(unsigned); +extern void write_pmxevcntr(unsigned); +extern void write_pmcr(unsigned); +extern void write_pmcntenset(unsigned); +extern void write_pmcntenclr(unsigned); +extern void write_pmovsr(unsigned); +extern void write_pmswinc(unsigned); +extern void write_pmselr(unsigned); +extern void write_pmceid0(unsigned); +extern void write_pmceid1(unsigned); +extern void write_osdlr(unsigned value); + +extern unsigned *copy_words(volatile unsigned *destination, + volatile unsigned *source, unsigned num_words); +extern void appf_memcpy(void *dst, const void *src, unsigned length); +extern void appf_memset(void *dst, unsigned value, unsigned length); + +extern void initialize_spinlock(bakery_t * bakery); +extern void get_spinlock(unsigned cpuid, bakery_t * bakery); +extern void release_spinlock(unsigned cpuid, bakery_t * bakery); + +/* + * GCC Compatibility + */ +#ifndef __ARMCC_VERSION +#define __nop() __asm__ __volatile__( "nop\n" ) +#endif diff --git a/linaro/arm-virt-bl/acsr/v7.S b/linaro/arm-virt-bl/acsr/v7.S new file mode 100644 index 0000000..873d1e3 --- /dev/null +++ b/linaro/arm-virt-bl/acsr/v7.S @@ -0,0 +1,656 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + +/* + * gas does not handle all vmsr/vmrs forms correctly, so use the obsolete + * fmrx/rmxr mnemonics instead (these are strictly not correct though, and + * are not accepted by armasm). + */ +#if !BUILD_RVCT +#define vmrs fmrx +#define vmsr fmxr +#endif + + EXPORT save_performance_monitors + EXPORT restore_performance_monitors + + EXPORT save_banked_registers + EXPORT restore_banked_registers + + EXPORT save_cp15 + EXPORT restore_cp15 + + EXPORT save_control_registers + EXPORT restore_control_registers + + EXPORT save_mmu + EXPORT restore_mmu + + EXPORT save_mpu + EXPORT restore_mpu + + EXPORT save_vfp + EXPORT restore_vfp + + EXPORT save_generic_timer + EXPORT restore_generic_timer + + EXPORT save_fault_status + EXPORT restore_fault_status + + AREA |.text.APPF|, CODE + +; Aliases for mode encodings - do not change +MODE_USR EQU 0x10 +MODE_FIQ EQU 0x11 +MODE_IRQ EQU 0x12 +MODE_SVC EQU 0x13 +MODE_MON EQU 0x16 ; A-profile (Security Extensions) only +MODE_ABT EQU 0x17 +MODE_UND EQU 0x1B +MODE_SYS EQU 0x1F +MODE_HYP EQU 0x1A + +TTBCR_EAE EQU (1<<31) ; Are we using LPAE? + +PFR0_THUMB_EE_SUPPORT EQU (1<<12) + + +save_performance_monitors FUNCTION + + push {r4, r8, r9, r10} + + ; Ignore: + ; Count Enable Clear Register + ; Software Increment Register + ; Interrupt Enable Clear Register + + mrc p15,0,r8,c9,c12,0 ; PMon: Control Register + bic r1,r8,#1 + mcr p15,0,r1,c9,c12,0 ; disable counter updates from here + isb ; 0b0 => PMCR<0> + mrc p15,0,r9,c9,c12,3 ; PMon: Overflow Flag Status Reg + mrc p15,0,r10,c9,c12,5 ; PMon: Event Counter Selection Reg + stm r0!, {r8-r10} + ubfx r9,r8,#11,#5 ; extract # of event counters, N + tst r9, r9 + beq %f1 + +0 subs r9,r9,#1 ; decrement N + mcr p15,0,r9,c9,c12,5 ; PMon: select CounterN + isb + mrc p15,0,r3,c9,c13,1 ; PMon: save Event Type register + mrc p15,0,r4,c9,c13,2 ; PMon: save Event Counter register + stm r0!, {r3,r4} + bne %b0 + +1 mrc p15,0,r1,c9,c13,0 ; PMon: Cycle Count Register + mrc p15,0,r2,c9,c14,0 ; PMon: User Enable Register + mrc p15,0,r3,c9,c14,1 ; PMon: Interrupt Enable Set Reg + mrc p15,0,r4,c9,c12,1 ; PMon: Count Enable Set Register + stm r0!, {r1-r4} + + pop {r4, r8, r9, r10} + bx lr + ENDFUNC + +restore_performance_monitors FUNCTION + + push {r4-r5, r8-r10, lr} + ; NOTE: all counters disabled by PMCR<0> == 0 on reset + + ; Restore performance counters + ldm r0!,{r8-r10} ; recover first block of PMon context + ; (PMCR, PMOVSR, PMSELR) + mov r1, #0 ; generate register of all 0's + mvn r2, #0 ; generate register of all 1's + mcr p15,0,r2,c9,c14,2 ; disable all counter related interrupts + mcr p15,0,r2,c9,c12,3 ; clear all overflow flags + isb + + ubfx r12,r8,#11,#5 ; extract # of event counters, N (0-31) + tst r12, r12 + beq %f20 + mov r3, r12 ; for N >0, generate a 2nd copy of N + mov r4, #1 + lsl r4, r4, r3 + sub r4, r4, #1 ; set bits<N-1:0> to all 1's + +0 subs r3,r3,#1 ; decrement N + mcr p15,0,r3,c9,c12,5 ; select Event CounterN + isb + mrc p15,0,r5,c9,c13,1 ; read Event Type register + bfc r5,#0,#8 + mcr p15,0,r5,c9,c13,1 ; set Event Type to 0x0 + mcr p15,0,r2,c9,c13,2 ; set Event Counter to all 1's + isb + bne %b0 + + mov r3, #1 + bic r5, r9, #1<<31 + mcr p15,0,r5,c9,c12,1 ; enable Event Counters + ; (PMOVSR bits set) + mcr p15,0,r3,c9,c12,0 ; set the PMCR global enable bit + isb + mcr p15,0,r9,c9,c12,4 ; set event count overflow bits + isb + mcr p15,0,r4,c9,c12,2 ; disable Event Counters + + ; restore the event counters +10 subs r12,r12,#1 ; decrement N + mcr p15,0,r12,c9,c12,5 ; select Event CounterN + isb + ldm r0!,{r3-r4} + mcr p15,0,r3,c9,c13,1 ; restore Event Type + mcr p15,0,r4,c9,c13,2 ; restore Event Counter + isb + bne %b10 + +20 tst r9, #0x80000000 ; check for cycle count overflow flag + beq %f40 + mcr p15,0,r2,c9,c13,0 ; set Cycle Counter to all 1's + isb + mov r3, #0x80000000 + mcr p15,0,r3,c9,c12,1 ; enable the Cycle Counter + isb + +30 mrc p15,0,r4,c9,c12,3 ; check cycle count overflow now set + movs r4,r4 ; test bit<31> + bpl %b30 + mcr p15,0,r3,c9,c12,2 ; disable the Cycle Counter + +40 mcr p15,0,r1,c9,c12,0 ; clear the PMCR global enable bit + isb + + ; restore the remaining PMon registers + ldm r0!,{r1-r4} + mcr p15,0,r1,c9,c13,0 ; restore Cycle Count Register + mcr p15,0,r2,c9,c14,0 ; restore User Enable Register + mcr p15,0,r3,c9,c14,1 ; restore Interrupt Enable Set Reg + mcr p15,0,r4,c9,c12,1 ; restore Count Enable Set Register + mcr p15,0,r10,c9,c12,5 ; restore Event Counter Selection + isb + mcr p15,0,r8,c9,c12,0 ; restore the PM Control Register + isb + + pop {r4-r5, r8-r10, pc} + ENDFUNC + + +save_banked_registers FUNCTION + mrs r2, CPSR ; save current mode + and r3, r2, #0x1f ; If we are in HYP mode then use the virt. + cmp r3, #MODE_HYP ; instructions to save the banked registers + beq save_in_hyp ; without changing the mode + + cps #MODE_SYS ; switch to System mode + str sp,[r0], #4 ; save the User SP + str lr,[r0], #4 ; save the User LR + cps #MODE_ABT ; switch to Abort mode + str sp,[r0], #4 ; save the current SP + mrs r3,SPSR + stm r0!,{r3,lr} ; save the current SPSR, LR + cps #MODE_UND ; switch to Undefined mode + str sp,[r0], #4 ; save the current SP + mrs r3,SPSR + stm r0!,{r3,lr} ; save the current SPSR, LR + cps #MODE_IRQ ; switch to IRQ mode + str sp,[r0], #4 ; save the current SP + mrs r3,SPSR + stm r0!,{r3,lr} ; save the current SPSR, LR + cps #MODE_FIQ ; switch to FIQ mode + str SP,[r0], #4 ; save the current SP + mrs r3,SPSR + stm r0!,{r8-r12,lr} ; save the current SPSR,r8-r12,LR + msr CPSR_cxsf, r2 ; switch back to original mode + bx lr + +save_in_hyp + mrs r1, SP_usr + stm r0!, {r1} + + mrs r1, SP_und + mrs r2, SPSR_und + mrs r3, LR_und + stm r0!, {r1-r3} + + mrs r1, SP_abt + mrs r2, SPSR_abt + mrs r3, LR_abt + stm r0!, {r1-r3} + + mrs r1, SP_svc + mrs r2, SPSR_svc + mrs r3, LR_svc + stm r0!, {r1-r3} + + mrs r1, SP_irq + mrs r2, SPSR_irq + mrs r3, LR_irq + stm r0!, {r1-r3} + + mrs r1, SP_fiq + mrs r2, SPSR_fiq + mrs r3, LR_fiq + stm r0!, {r1-r3} + mrs r1, r8_fiq + mrs r2, r9_fiq + mrs r3, r10_fiq + stm r0!, {r1-r3} + mrs r1, r11_fiq + mrs r2, r12_fiq + stm r0!, {r1-r2} + bx lr + + ENDFUNC + +restore_banked_registers FUNCTION + mrs r2, CPSR ; save current mode + and r3, r2, #0x1f ; If we are in HYP mode then use the virt. + cmp r3, #MODE_HYP ; instructions to restore the banked registers + beq rest_in_hyp ; without changing the mode + + cps #MODE_SYS ; switch to System mode + ldr sp,[r0],#4 ; restore the User SP + ldr lr,[r0],#4 ; restore the User LR + cps #MODE_ABT ; switch to Abort mode + ldr sp,[r0],#4 ; restore the current SP + ldm r0!,{r3,lr} ; restore the current LR + msr SPSR_fsxc,r3 ; restore the current SPSR + cps #MODE_UND ; switch to Undefined mode + ldr sp,[r0],#4 ; restore the current SP + ldm r0!,{r3,lr} ; restore the current LR + msr SPSR_fsxc,r3 ; restore the current SPSR + cps #MODE_IRQ ; switch to IRQ mode + ldr sp,[r0],#4 ; restore the current SP + ldm r0!,{r3,lr} ; restore the current LR + msr SPSR_fsxc,r3 ; restore the current SPSR + cps #MODE_FIQ ; switch to FIQ mode + ldr sp,[r0],#4 ; restore the current SP + ldm r0!,{r8-r12,lr} ; restore the current r8-r12,LR + msr SPSR_fsxc,r4 ; restore the current SPSR + msr CPSR_cxsf, r2 ; switch back to original mode +0 bx lr + +rest_in_hyp + ldm r0!, {r1} + msr SP_usr, r1 + + ldm r0!, {r1-r3} + msr SP_und, r1 + msr SPSR_und, r2 + msr LR_und, r3 + + ldm r0!, {r1-r3} + msr SP_abt, r1 + msr SPSR_abt, r2 + msr LR_abt, r3 + + ldm r0!, {r1-r3} + msr SP_svc, r1 + msr SPSR_svc, r2 + msr LR_svc, r3 + + ldm r0!, {r1-r3} + msr SP_irq, r1 + msr SPSR_irq, r2 + msr LR_irq, r3 + + ldm r0!, {r1-r3} + msr SP_fiq, r1 + msr SPSR_fiq, r2 + msr LR_fiq, r3 + + ldm r0!, {r1-r3} + msr r8_fiq, r1 + msr r9_fiq, r2 + msr r10_fiq, r3 + + ldm r0!, {r1-r2} + msr r11_fiq, r1 + msr r12_fiq, r2 + + bx lr + ENDFUNC + + +save_cp15 FUNCTION + ; CSSELR Cache Size Selection Register + mrc p15,2,r3,c0,c0,0 + str r3,[r0], #4 + + ; IMPLEMENTATION DEFINED - proprietary features: + ; (CP15 register 15, TCM support, lockdown support, etc.) + + ; NOTE: IMP DEF registers might have save and restore order that relate + ; to other CP15 registers or logical grouping requirements and can + ; therefore occur at any point in this sequence. + bx lr + ENDFUNC + +restore_cp15 FUNCTION + ; CSSELR – Cache Size Selection Register + ldr r3,[r0], #4 + mcr p15,2,r3,c0,c0,0 + + bx lr + ENDFUNC + + ; Function called with two arguments: + ; r0 contains address to store control registers + ; r1 is non-zero if we are Secure +save_control_registers FUNCTION + cmp r1, #0 ; Are we Secure? + mrc p15,0,r2,c1,c0,1 ; ACTLR - Auxiliary Control Register + mrc p15,0,r3,c1,c0,0 ; SCTLR - System Control Register + mrc p15,0,r12,c1,c0,2 ; CPACR - Coprocessor Access Control Register + stm r0!, {r2-r3, r12} + + mrcne p15,0,r1,c12,c0,1 ; MVBAR - Monitor Vector Base Address Register + mrcne p15,0,r2,c1,c1,0 ; Secure Configuration Register + mrcne p15,0,r3,c1,c1,1 ; Secure Debug Enable Register + mrcne p15,0,r12,c1,c1,2 ; Non-Secure Access Control Register + stmne r0!, {r1-r3,r12} + + mrc p15,0,r1,c13,c0,1 ; CONTEXTIDR + mrc p15,0,r2,c13,c0,2 ; TPIDRURW + mrc p15,0,r3,c13,c0,3 ; TPIDRURO + mrc p15,0,r12,c13,c0,4 ; TPIDRPRW + stm r0!, {r1-r3,r12} + + ; The next two registers are only present if ThumbEE is implemented + mrc p15, 0, r1, c0, c1, 0 ; Read ID_PFR0 + tst r1, #PFR0_THUMB_EE_SUPPORT + mrcne p14,6,r1,c0,c0,0 ; TEECR + mrcne p14,6,r2,c1,c0,0 ; TEEHBR + stmne r0!, {r1, r2} + + mrc p14,7,r1,c1,c0,0 ; JOSCR + mrc p14,7,r2,c2,c0,0 ; JMCR + stm r0!, {r1, r2} + bx lr + ENDFUNC + + + ; Function called with two arguments: + ; r0 contains address to read control registers + ; r1 is non-zero if we are Secure +restore_control_registers FUNCTION + cmp r1, #0 ; Are we Secure? + ldm r0!, {r2-r3, r12} + mcr p15,0,r2,c1,c0,1 ; ACTLR - Auxiliary Control Register + mcr p15,0,r3,c1,c0,0 ; SCTLR - System Control Register + mcr p15,0,r12,c1,c0,2 ; CPACR - Coprocessor Access Control Register + + ldmne r0!, {r1-r3,r12} + mcrne p15,0,r1,c12,c0,1 ; MVBAR - Monitor Vector Base Address Register + mcrne p15,0,r2,c1,c1,0 ; Secure Configuration Register + mcrne p15,0,r3,c1,c1,1 ; Secure Debug Enable Register + mcrne p15,0,r12,c1,c1,2 ; Non-Secure Access Control Register + + ldm r0!, {r1-r3,r12} + mcr p15,0,r1,c13,c0,1 ; CONTEXTIDR + mcr p15,0,r2,c13,c0,2 ; TPIDRURW + mcr p15,0,r3,c13,c0,3 ; TPIDRURO + mcr p15,0,r12,c13,c0,4 ; TPIDRPRW + + ; The next two registers are only present if ThumbEE is implemented + mrc p15, 0, r1, c0, c1, 0 ; Read ID_PFR0 + tst r1, #PFR0_THUMB_EE_SUPPORT + ldmne r0!, {r1,r2} + mcrne p14,6,r1,c0,c0,0 ; TEECR + mcrne p14,6,r2,c1,c0,0 ; TEEHBR + + ldm r0!, {r1, r2} + mcr p14,7,r1,c1,c0,0 ; JOSCR + mcr p14,7,r2,c2,c0,0 ; JMCR + isb + bx lr + ENDFUNC + +save_mmu FUNCTION + push {r4, r5, r6, r7} + ; ASSUMPTION: no useful fault address / fault status information + + mrc p15,0,r4,c12,c0,0 ; VBAR + mrc p15,0,r5,c2,c0,2 ; TTBCR + + tst r5, #TTBCR_EAE ; Are we using LPAE? + + ; save 32 or 64 bit TTBRs + mrceq p15,0,r6,c2,c0,0 ; 32 bit TTBR0 + mrceq p15,0,r7,c2,c0,1 ; 32 bit TTBR1 + mrrcne p15,0,r6,r7,c2 ; 64 bit TTBR0 + stm r0!, {r4-r7} + mrrcne p15,1,r6,r7,c2 ; 64 bit TTBR1 + stmne r0!, {r6-r7} + + mrc p15,0,r4,c3,c0,0 ; DACR + mrc p15,0,r5,c7,c4,0 ; PAR + mrc p15,0,r6,c10,c2,0 ; PRRR + mrc p15,0,r7,c10,c2,1 ; NMRR + stm r0!, {r4-r7} + + pop {r4, r5, r6, r7} + bx lr + ENDFUNC + + +restore_mmu FUNCTION + + push {r4, r5, r6, r7} + ldm r0!, {r4-r7} + mcr p15,0,r4,c12,c0,0 ; VBAR + mcr p15,0,r5,c2,c0,2 ; TTBCR + + tst r5, #TTBCR_EAE ; Are we using LPAE? + + ; restore 32 or 64 bit TTBRs + mcreq p15,0,r6,c2,c0,0 ; 32 bit TTBR0 + mcreq p15,0,r7,c2,c0,1 ; 32 bit TTBR1 + mcrrne p15,0,r6,r7,c2 ; 64-bit TTBR0 + ldmne r0!, {r6-r7} + mcrrne p15,1,r6,r7,c2 ; 64-bit TTBR1 + + ldm r0!, {r4-r7} + mcr p15,0,r4,c3,c0,0 ; DACR + mcr p15,0,r5,c7,c4,0 ; PAR + mcr p15,0,r6,c10,c2,0 ; PRRR + mcr p15,0,r7,c10,c2,1 ; NMRR + + pop {r4, r5, r6, r7} + bx lr + ENDFUNC + + +save_mpu FUNCTION + mrc p15, 0, r1, c0, c0, 4 ; Read MPUIR + and r1, r1, #0xff00 + lsr r1, r1, #8 ; Extract number of MPU regions + + ; Loop over the number of regions +10 cmp r1, #0 + beq %f20 + sub r1, r1, #1 + mcr p15, 0, r1, c6, c2, 0 ; Write RGNR + mrc p15, 0, r2, c6, c1, 0 ; Read MPU Region Base Address Register + mrc p15, 0, r3, c6, c1, 2 ; Read Data MPU Region Size and Enable Register + mrc p15, 0, r12, c6, c1, 4 ; Read Region access control Register + stm r0!, {r2, r3, r12} + b %b10 + +20 bx lr + ENDFUNC + + +restore_mpu FUNCTION + mrc p15, 0, r1, c0, c0, 4 ; Read MPUIR + and r1, r1, #0xff00 + lsr r1, r1, #8 ; Extract number of MPU regions + + ; Loop over the number of regions +10 cmp r1, #0 + beq %f20 + ldm r0!, {r2, r3, r12} + sub r1, r1, #1 + mcr p15, 0, r1, c6, c2, 0 ; Write RGNR + mcr p15, 0, r2, c6, c1, 0 ; Write MPU Region Base Address Register + mcr p15, 0, r3, c6, c1, 2 ; Write Data MPU Region Size and Enable Register + mcr p15, 0, r12, c6, c1, 4 ; Write Region access control Register + b %b10 + +20 bx lr + ENDFUNC + + +save_vfp FUNCTION + ; FPU state save/restore. + ; FPSID,MVFR0 and MVFR1 don't get serialized/saved (Read Only). + mrc p15,0,r3,c1,c0,2 ; CPACR allows CP10 and CP11 access + ORR r2,r3,#0xF00000 + mcr p15,0,r2,c1,c0,2 + isb + mrc p15,0,r2,c1,c0,2 + and r2,r2,#0xF00000 + cmp r2,#0xF00000 + beq %f0 + movs r2, #0 + b %f2 + +0 ; Save configuration registers and enable. + vmrs r12,FPEXC + str r12,[r0],#4 ; Save the FPEXC + ; Enable FPU access to save/restore the other registers. + ldr r2,=0x40000000 + vmsr FPEXC,r2 + vmrs r2,FPSCR + str r2,[r0],#4 ; Save the FPSCR + ; Store the VFP-D16 registers. + vstm r0!, {D0-D15} + ; Check for Advanced SIMD/VFP-D32 support + vmrs r2,MVFR0 + and r2,r2,#0xF ; extract the A_SIMD bitfield + cmp r2, #0x2 + blt %f1 + ; Store the Advanced SIMD/VFP-D32 additional registers. + vstm r0!, {D16-D31} + + ; IMPLEMENTATION DEFINED: save any subarchitecture defined state + ; NOTE: Don't change the order of the FPEXC and CPACR restores +1 + vmsr FPEXC,r12 ; Restore the original En bit of FPU. +2 + mcr p15,0,r3,c1,c0,2 ; Restore the original CPACR value. + bx lr + ENDFUNC + + +restore_vfp FUNCTION + ; FPU state save/restore. Obviously FPSID,MVFR0 and MVFR1 don't get + ; serialized (RO). + ; Modify CPACR to allow CP10 and CP11 access + mrc p15,0,r1,c1,c0,2 + ORR r2,r1,#0x00F00000 + mcr p15,0,r2,c1,c0,2 + ; Enable FPU access to save/restore the rest of registers. + ldr r2,=0x40000000 + vmsr FPEXC, r2 + ; Recover FPEXC and FPSCR. These will be restored later. + ldm r0!,{r3,r12} + ; Restore the VFP-D16 registers. + vldm r0!, {D0-D15} + ; Check for Advanced SIMD/VFP-D32 support + vmrs r2, MVFR0 + and r2,r2,#0xF ; extract the A_SIMD bitfield + cmp r2, #0x2 + blt %f0 + + ; Store the Advanced SIMD/VFP-D32 additional registers. + vldm r0!, {D16-D31} + + ; IMPLEMENTATION DEFINED: restore any subarchitecture defined state + +0 ; Restore configuration registers and enable. + ; Restore FPSCR _before_ FPEXC since FPEXC could disable FPU + ; and make setting FPSCR unpredictable. + vmsr FPSCR,r12 + vmsr FPEXC,r3 ; Restore FPEXC after FPSCR + ; Restore CPACR + mcr p15,0,r1,c1,c0,2 + bx lr + ENDFUNC + + + ; If r1 is 0, we assume that the OS is not using the Virtualization extensions, + ; and that the warm boot code will set up CNTHCTL correctly. If r1 is non-zero + ; then CNTHCTL is saved and restored + ; CNTP_CVAL will be preserved as it is in the always-on domain. + +save_generic_timer FUNCTION + mrc p15,0,r2,c14,c2,1 ; read CNTP_CTL + mrc p15,0,r3,c14,c2,0 ; read CNTP_TVAL + mrc p15,0,r12,c14,c1,0 ; read CNTKCTL + stm r0!, {r2, r3, r12} + cmp r1, #0 + mrcne p15,4,r1,c14,c1,0 ; read CNTHCTL + strne r1, [r0], #4 + bx lr + ENDFUNC + +restore_generic_timer FUNCTION + ldm r0!, {r2, r3, r12} + mcr p15,0,r3,c14,c2,0 ; write CNTP_TVAL + mcr p15,0,r12,c14,c1,0 ; write CNTKCTL + mcr p15,0,r2,c14,c2,1 ; write CNTP_CTL + cmp r1, #0 + ldrne r1, [r0], #4 + mcrne p15,4,r1,c14,c1,0 ; write CNTHCTL + bx lr + ENDFUNC + + +save_fault_status FUNCTION + mrc p15,0,r1,c6,c0,0 ; read DFAR + mrc p15,0,r2,c6,c0,2 ; read IFAR + mrc p15,0,r3,c5,c0,0 ; read DFSR + mrc p15,0,r12,c5,c0,1 ; read IFSR + stm r0!, {r1,r2,r3,r12} + mrc p15,0,r1,c5,c1,0 ; read ADFSR + mrc p15,0,r2,c5,c1,1 ; read AIFSR + stm r0!, {r1,r2} + bx lr + ENDFUNC + +restore_fault_status FUNCTION + ldm r0!, {r1,r2,r3,r12} + mcr p15,0,r1,c6,c0,0 ; write DFAR + mcr p15,0,r2,c6,c0,2 ; write IFAR + mcr p15,0,r3,c5,c0,0 ; write DFSR + mcr p15,0,r12,c5,c0,1 ; write IFSR + ldm r0!, {r1,r2} + mcr p15,0,r1,c5,c1,0 ; write ADFSR + mcr p15,0,r2,c5,c1,1 ; write AIFSR + bx lr + ENDFUNC + + + END diff --git a/linaro/arm-virt-bl/acsr/v7_c.c b/linaro/arm-virt-bl/acsr/v7_c.c new file mode 100644 index 0000000..c802bfc --- /dev/null +++ b/linaro/arm-virt-bl/acsr/v7_c.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/* + * The code to save and restore debug context uses the memory-mapped interface. + * The registers that are saved are enough to support a self-hosted debugger, + * but a different approach should be taken with an external debugger (cp14). + */ + +#include "appf_types.h" +#include "appf_internals.h" +#include "appf_helpers.h" + +#define DIDR_VERSION_SHIFT 16 +#define DIDR_VERSION_MASK 0xF +#define DIDR_VERSION_7_1 5 +#define DIDR_BP_SHIFT 24 +#define DIDR_BP_MASK 0xF +#define DIDR_WP_SHIFT 28 +#define DIDR_WP_MASK 0xF +#define CLAIMCLR_CLEAR_ALL 0xff + +#define DRAR_VALID_MASK 0x00000003 +#define DSAR_VALID_MASK 0x00000003 +#define DRAR_ADDRESS_MASK 0xFFFFF000 +#define DSAR_ADDRESS_MASK 0xFFFFF000 +#define OSLSR_OSLM_MASK 0x00000009 +#define OSLAR_UNLOCKED 0x00000000 +#define OSLAR_LOCKED 0xC5ACCE55 +#define LAR_UNLOCKED 0xC5ACCE55 +#define LAR_LOCKED 0x00000000 +#define OSDLR_UNLOCKED 0x00000000 +#define OSDLR_LOCKED 0x00000001 + +typedef volatile struct { /* Registers Save? */ + appf_u32 const didr; /* 0 Read only */ + appf_u32 dscr_i; /* 1 ignore - use dscr_e instead */ + appf_u32 const dummy1[3]; /* 2-4 ignore */ + appf_u32 dtrrx_dtrtx_i; /* 5 ignore */ + appf_u32 wfar; /* 6 ignore - transient information */ + appf_u32 vcr; /* 7 Save */ + appf_u32 const dummy2; /* 8 ignore */ + appf_u32 ecr; /* 9 ignore */ + appf_u32 dsccr; /* 10 ignore */ + appf_u32 dsmcr; /* 11 ignore */ + appf_u32 const dummy3[20]; /* 12-31 ignore */ + appf_u32 dtrrx_e; /* 32 ignore */ + appf_u32 itr_pcsr; /* 33 ignore */ + appf_u32 dscr_e; /* 34 Save */ + appf_u32 dtrtx_e; /* 35 ignore */ + appf_u32 drcr; /* 36 ignore */ + appf_u32 eacr; /* 37 Save - V7.1 only */ + appf_u32 const dummy4[2]; /* 38-39 ignore */ + appf_u32 pcsr; /* 40 ignore */ + appf_u32 cidsr; /* 41 ignore */ + appf_u32 vidsr; /* 42 ignore */ + appf_u32 const dummy5[21]; /* 43-63 ignore */ + appf_u32 bvr[16]; /* 64-79 Save */ + appf_u32 bcr[16]; /* 80-95 Save */ + appf_u32 wvr[16]; /* 96-111 Save */ + appf_u32 wcr[16]; /* 112-127 Save */ + appf_u32 const dummy6[16]; /* 128-143 ignore */ + appf_u32 bxvr[16]; /* 144-159 Save if have Virtualization extensions */ + appf_u32 const dummy7[32]; /* 160-191 ignore */ + appf_u32 oslar; /* 192 If oslsr[0] is 1, unlock before save/restore */ + appf_u32 const oslsr; /* 193 ignore */ + appf_u32 ossrr; /* 194 ignore */ + appf_u32 const dummy8; /* 195 ignore */ + appf_u32 prcr; /* 196 ignore */ + appf_u32 prsr; /* 197 clear SPD on restore */ + appf_u32 const dummy9[762]; /* 198-959 ignore */ + appf_u32 itctrl; /* 960 ignore */ + appf_u32 const dummy10[39]; /* 961-999 ignore */ + appf_u32 claimset; /* 1000 Restore claim bits to here */ + appf_u32 claimclr; /* 1001 Save claim bits from here */ + appf_u32 const dummy11[2]; /* 1002-1003 ignore */ + appf_u32 lar; /* 1004 Unlock before restore */ + appf_u32 const lsr; /* 1005 ignore */ + appf_u32 const authstatus; /* 1006 Read only */ + appf_u32 const dummy12; /* 1007 ignore */ + appf_u32 const devid2; /* 1008 Read only */ + appf_u32 const devid1; /* 1009 Read only */ + appf_u32 const devid; /* 1010 Read only */ + appf_u32 const devtype; /* 1011 Read only */ + appf_u32 const pid[8]; /* 1012-1019 Read only */ + appf_u32 const cid[4]; /* 1020-1023 Read only */ +} debug_registers_t; + +typedef struct { + appf_u32 vcr; + appf_u32 dscr_e; + appf_u32 eacr; + appf_u32 bvr[16]; + appf_u32 bcr[16]; + appf_u32 wvr[16]; + appf_u32 wcr[16]; + appf_u32 bxvr[16]; + appf_u32 claim; +} debug_context_t; /* total size 86 * 4 = 344 bytes */ + +debug_registers_t *read_debug_address(void) +{ + unsigned drar, dsar; + + drar = read_drar(); + dsar = read_dsar(); + + if (!(drar & DRAR_VALID_MASK) + || !(dsar & DSAR_VALID_MASK)) { + return 0; /* No memory-mapped debug on this processor */ + } + + return (debug_registers_t *) ((drar & DRAR_ADDRESS_MASK) + + (dsar & DSAR_ADDRESS_MASK)); +} + +/* + * We assume that before save (and after restore): + * - OSLAR is NOT locked, or the debugger would not work properly + * - LAR is locked, because the ARM ARM says it must be + * - OSDLR is NOT locked, or the debugger would not work properly + */ + +void save_v7_debug(appf_u32 * context) +{ + debug_registers_t *dbg = (void *)read_debug_address(); + debug_context_t *ctx = (void *)context; + unsigned v71, num_bps, num_wps, i; + appf_u32 didr; + + if (!dbg) { + return; + } + + didr = dbg->didr; + /* + * Work out what version of debug we have + */ + v71 = + (((didr >> DIDR_VERSION_SHIFT) & DIDR_VERSION_MASK) == + DIDR_VERSION_7_1); + + /* + * Save all context to memory + */ + ctx->vcr = dbg->vcr; + ctx->dscr_e = dbg->dscr_e; + ctx->claim = dbg->claimclr; + + if (v71) { + ctx->eacr = dbg->eacr; + } + + num_bps = 1 + ((didr >> DIDR_BP_SHIFT) & DIDR_BP_MASK); + for (i = 0; i < num_bps; ++i) { + ctx->bvr[i] = dbg->bvr[i]; + ctx->bcr[i] = dbg->bcr[i]; +#ifdef VIRTUALIZATION + ctx->bxvr[i] = dbg->bxvr[i]; /* TODO: don't save the ones that don't exist */ +#endif + } + + num_wps = 1 + ((didr >> DIDR_WP_SHIFT) & DIDR_WP_MASK); + for (i = 0; i < num_wps; ++i) { + ctx->wvr[i] = dbg->wvr[i]; + ctx->wcr[i] = dbg->wcr[i]; + } + + /* + * If Debug V7.1, we must set osdlr (by cp14 interface) before power down. + * Once we have done this, debug becomes inaccessible. + */ + if (v71) { + write_osdlr(OSDLR_LOCKED); + } +} + +void restore_v7_debug(appf_u32 * context) +{ + debug_registers_t *dbg = (void *)read_debug_address(); + debug_context_t *ctx = (void *)context; + unsigned v71, num_bps, num_wps, i; + appf_u32 didr; + + if (!dbg) { + return; + } + + didr = dbg->didr; + /* + * Work out what version of debug we have + */ + v71 = + (((didr >> DIDR_VERSION_SHIFT) & DIDR_VERSION_MASK) == + DIDR_VERSION_7_1); + + /* Enable write access to registers */ + dbg->lar = LAR_UNLOCKED; + /* + * If Debug V7.1, we must unset osdlr (by cp14 interface) before restoring. + * (If the CPU has not actually power-cycled, osdlr may not be reset). + */ + if (v71) { + write_osdlr(OSDLR_UNLOCKED); + } + + /* + * Restore all context from memory + */ + dbg->vcr = ctx->vcr; + dbg->claimclr = CLAIMCLR_CLEAR_ALL; + dbg->claimset = ctx->claim; + + if (v71) { + dbg->eacr = ctx->eacr; + } + + num_bps = 1 + ((didr >> DIDR_BP_SHIFT) & DIDR_BP_MASK); + for (i = 0; i < num_bps; ++i) { + dbg->bvr[i] = ctx->bvr[i]; + dbg->bcr[i] = ctx->bcr[i]; +#ifdef VIRTUALIZATION + dbg->bxvr[i] = ctx->bxvr[i]; /* TODO: don't restore the ones that don't exist */ +#endif + } + + num_wps = 1 + ((didr >> DIDR_WP_SHIFT) & DIDR_WP_MASK); + for (i = 0; i < num_wps; ++i) { + dbg->wvr[i] = ctx->wvr[i]; + dbg->wcr[i] = ctx->wcr[i]; + } + + /* Clear PRSR.SPD by reading PRSR */ + if (!v71) { + (dbg->prsr); + } + + /* Re-enable debug */ + dbg->dscr_e = ctx->dscr_e; + + /* Disable write access to registers */ + dbg->lar = LAR_LOCKED; +} diff --git a/linaro/arm-virt-bl/big-little/Makefile b/linaro/arm-virt-bl/big-little/Makefile new file mode 100755 index 0000000..2d3346d --- /dev/null +++ b/linaro/arm-virt-bl/big-little/Makefile @@ -0,0 +1,287 @@ +# +# Copyright (c) 2012, ARM Limited. All rights reserved. +# +# Redistribution and use in source and binary forms, with +# or without modification, are permitted provided that the +# following conditions are met: +# +# Redistributions of source code must retain the above +# copyright notice, this list of conditions and the +# following disclaimer. +# +# 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. +# +# Neither the name of ARM nor the names of its +# contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# + +# Decrease the verbosity of the make script +# can be made verbose by passing V=1 at the make command line +ifdef V + KBUILD_VERBOSE = $(V) +else + KBUILD_VERBOSE = 0 +endif + +ifeq "$(KBUILD_VERBOSE)" "0" + Q=@ +else + Q= +endif + +BUILD_RVCT?=FALSE +ifneq ($(BUILD_RVCT),TRUE) +CROSS_COMPILE?=arm-linux-gnueabi- +endif + +HIBASE?=0x8ff +DEBUG=TRUE + +############################################################################################################### +# Shared/External Virtual GIC defines +SVGIC_OBJS += sh_vgic.o +############################################################################################################### +# Switcher defines +SWITCHER ?= TRUE +ASYNC ?= TRUE +HYP_TIMERS ?= TRUE +RAND_ASYNC ?= FALSE +HOST_CLUSTER ?= 1 +FLUSH_OB_L2 ?= TRUE +FLUSH_L2_FIX ?= FALSE +TUBE ?= FALSE +FM_BETA ?= TRUE + +# Global tool configuration +ifeq ($(BUILD_RVCT),TRUE) +CC = $(CROSS_COMPILE)armcc +AS = $(CROSS_COMPILE)armasm +LD = $(CROSS_COMPILE)armlink +OBJCOPY = objcopy () { $(CROSS_COMPILE)fromelf --bin $1 --output $2; } && objcopy +CFLAGS += $(CFLAGS_RVCT) +ASFLAGS += $(ASFLAGS_RVCT) +APP = cat +else +CC = $(CROSS_COMPILE)gcc +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +OBJCOPY = objcopy () { $(CROSS_COMPILE)objcopy -Obinary $1 $2; } && objcopy +CFLAGS += $(CFLAGS_GNU) +ASFLAGS += $(ASFLAGS_GNU) +APP = ../scripts/armasm2gas.pl +endif +CPP = $(CC) -E + +ifeq ($(BUILD_RVCT),TRUE) +CPPFLAGS += --md +else +CPPFLAGS += -MD +endif + +# Global include path: +CPPFLAGS += -Iinclude -I. + +# Global defines +CPPFLAGS += -DHIBASE=$(HIBASE) + +# Global CPPFLAGS: +ifeq ($(BUILD_RVCT),TRUE) +CPPFLAGS += -DBUILD_RVCT +endif +CPPFLAGS += -DHOST_CLUSTER=$(HOST_CLUSTER) +ifeq ($(FM_BETA),TRUE) +CPPFLAGS += -DFM_BETA +endif +ifeq ($(SWITCHER),TRUE) +CPPFLAGS += -DSWITCHER +endif +ifeq ($(FLUSH_OB_L2),TRUE) +CPPFLAGS += -DFLUSH_OB_L2 +endif +ifeq ($(TUBE),TRUE) +CPPFLAGS += -DTUBE +endif +ifeq ($(FLUSH_L2_FIX),TRUE) +CPPFLAGS += -DFLUSH_L2_FIX +endif +ifeq ($(ASYNC),TRUE) +CPPFLAGS += -DASYNC_SWITCH +endif +ifeq ($(RAND_ASYNC),TRUE) +CPPFLAGS += -DRAND_ASYNC +endif +ifeq ($(HYP_TIMERS),TRUE) +CPPFLAGS += -DUSE_HYP_TIMERS +endif + +# Tool-specific global flags: +ASFLAGS_RVCT = --apcs /inter --cpu=Eagle --keep +ASFLAGS_GNU = -mcpu=cortex-a15 -mfpu=vfpv3 + +CFLAGS_RVCT = --cpu=Eagle --fpu=none +CFLAGS_GNU = -march=armv7-a -marm -ffreestanding + +# Global debug flags: +ifdef DEBUG +CFLAGS += -g -O0 +ASFLAGS += -g +else +CFLAGS += -O2 +endif + +ifeq ($(SWITCHER), TRUE) +ifeq ($(ASYNC), FALSE) +HYP_TIMERS = FALSE +endif + +vpath %.c switcher switcher/trigger switcher/context common/ lib/ secure_world/ ../acsr +vpath %.S switcher switcher/trigger switcher/context common/ lib/ secure_world/ ../acsr + +SWITCHER_OBJS = ns_context.o hyp_setup.o pagetable_setup.o virt_helpers.o sync_switchover.o \ + vgiclib.o vgic_handle.o uart.o v7.o gic.o handle_switchover.o tube.o \ + virt_events.o bakery.o vgic_setup.o async_switchover.o hyp_vectors.o helpers.o + +SECURE_ENTRY_POINT = monmode_vector_table + +OBJS-bl_sec.axf += secure_context_sec.o monmode_vectors.o flat_pagetable.o virt_helpers.o virt_events.o \ + secure_resets_sec.o bakery.o tube.o helpers.o + +SECURE_CPPFLAGS = $(CPPFLAGS) -Isecure_world -I../acsr + +ifeq ($(BUILD_RVCT),TRUE) +LDFLAGS-bl_sec.axf = --verbose --map --symbols --noremove --datacompressor=off \ + --entry $(SECURE_ENTRY_POINT) --scatter $(SECURE_MAPFILE) \ + --symdefs=bl_sec_symdef.o +else +LDFLAGS-bl_sec.axf = -n --print-map -e $(SECURE_ENTRY_POINT) -T $(SECURE_MAPFILE) +endif + +endif # SWITCHER + +############################################################################################################### +# Virtualisor defines +CMOP_DEBUG ?= FALSE + +ifeq ($(CMOP_DEBUG),TRUE) +CPPFLAGS += -DCMOP_DEBUG +endif + +vpath %.c virtualisor virtualisor/cpus/a15 virtualisor/cpus/a7 + +VIRTUALISOR_OBJS += virt_handle.o virt_setup.o virt_context.o cache_geom.o mem_trap.o vgic_trap_handler.o \ + a7.o a15.o + +############################################################################################################### + + +OBJS-bl.axf += cci.o + +VIRTUALISOR_CPPFLAGS = -Ivirtualisor/include -Ivirtualisor/cpus/a7/include \ + -Ivirtualisor/cpus/a15/include -I../acsr + +OBJS-bl.axf += $(SWITCHER_OBJS) $(VIRTUALISOR_OBJS) $(SVGIC_OBJS) + +ENTRY_POINT = bl_setup + +MAPFILE = bl.scf +SECURE_MAPFILE = bl-sec.scf +LISTFILE-bl.axf = bl.map +LISTFILE-bl_sec.axf = bl_sec.map + +ifeq ($(BUILD_RVCT),TRUE) +LDFLAGS-bl.axf = --verbose --map --symbols --noremove --datacompressor=off --entry $(ENTRY_POINT) --scatter $(MAPFILE) --symdefs=bl_symdef.o +else +LDFLAGS-bl.axf = -n --print-map -e $(ENTRY_POINT) -T $(MAPFILE) + +# Extra library objects to replace ARM C library functionality: +OBJS-bl.axf += idiv0.o ldiv0.o raise.o unwind-personality.o \ + printf.o vsnprintf.o puts.o string.o +OBJS-bl.axf += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +OBJS-bl_sec.axf += string.o +endif + +ifeq ($(FM_BETA), FALSE) +all: bl.axf bl_sec.axf wboot.bin +else +all: bl.axf bl_sec.axf +endif + +-include *.d + +clean: + @echo " CLEAN" + $(Q)rm -rf *.zi + $(Q)rm -rf *.dump + $(Q)rm -rf *.bin + $(Q)rm -f *.axf + $(Q)rm -f *.o + $(Q)rm -f *.ar + $(Q)rm -f *.map + $(Q)rm -f *.scf + $(Q)rm -f *.s *.spp *.d + $(Q)rm -f $(LISTFILE-bl.axf) + $(Q)rm -f $(LISTFILE-bl_sec.axf) + +dump: + @echo " OBJDUMP" + fromelf --text -c bl.axf > bl.dump + fromelf --text -c bl_sec.axf > bl_sec.dump + +# Since we potentially need an extra preprocessing step, cancel the normal +# built-in rule for .S files: +%.o: %.S + +%.s: %.S + @echo " APP $<" + $(Q)$(CPP) $(CPPFLAGS) -o $@pp $< + $(Q)$(APP) <$@pp >$@ + +%.o: %.s + @echo " AS $<" + $(Q)$(AS) $(ASFLAGS) $< -o $@ + +%.o: %.c + @echo " CC $<" + $(Q)$(CC) $(CPPFLAGS) $(VIRTUALISOR_CPPFLAGS) $(CFLAGS) -c $< -o $@ + +%.scf: %.scf.S + @echo " SCF $<" + $(Q)$(CPP) $(CPPFLAGS) $< | grep -v ^# >$@ + +ifeq ($(FM_BETA), FALSE) +wboot.axf: ve_reset_handler.o + @echo " LD $@" + $(Q)$(LD) --ro-base=0x0 $< -o $@ > $(LISTFILE) +else +OBJS-bl_sec.axf += ve_reset_handler.o +# Override default rule for %.bin with a no-op: +.PHONY: wboot.bin +wboot.bin: ; +endif + +bl.axf: $(OBJS-bl.axf) $(MAPFILE) +bl_sec.axf: $(OBJS-bl_sec.axf) $(SECURE_MAPFILE) + +%.axf: + @echo " LD $@" + $(Q)$(LD) $(LDFLAGS-$@) $(OBJS-$@) -o $@ > $(LISTFILE-$@) + +bl.ar: $(OBJS) + @echo " AR $@" + $(Q)$(AR) -r $@ $(OBJS) + +%.bin: %.axf + @echo " OBJCOPY $@" + $(Q)$(OBJCOPY) $< $@ + +%_sec.o: %.c + @echo " CC[SEC] $<" + $(Q)$(CC) $(SECURE_CPPFLAGS) $(SECURE_CFLAGS) -c $< -o $@ + +bl_sec.ar: $(SECURE_OBJS) + $(Q)$(AR) -r $@ $(SECURE_OBJS) diff --git a/linaro/arm-virt-bl/big-little/bl-sec.scf.S b/linaro/arm-virt-bl/big-little/bl-sec.scf.S new file mode 100644 index 0000000..63c1222 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/bl-sec.scf.S @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "scf-macros.h" + +#ifdef BUILD_RVCT + +#ifdef FM_BETA +JUMP_LOAD 0x0 0x100 +{ + JUMP_EXEC 0x0 0x100 + { + ve_reset_handler.o (+RO, +RW, +ZI) + } +} +#endif + +LOAD_REGION1 PASTE(HIBASE,00000) NOCOMPRESS ALIGN 4096 65536 +{ + BL_SEC_DV_PAGE +0x0 ALIGN 4096 4096 + { + *(.data.BL_SEC_DV_PAGE) + } + + SEC_CODE PASTE(HIBASE,01000) FIXED + { + *(+RO) + } + + SEC_DATA +0x0 + { + *(+ZI,+RW) + } +} + +#else /* ! BUILD_RVCT */ + +PHDRS { + JUMP_LOAD PT_LOAD; + BL_SEC_DV_PAGE PT_LOAD; + TEXT PT_LOAD; + DATA PT_LOAD; +} + +SECTIONS { + + BL_SEC_DV_PAGE PASTE(HIBASE,00000) : { /* ALIGN (4096) */ + __BL_SEC_DV_PAGE_base = .; + *(.data.BL_SEC_DV_PAGE) + __BL_SEC_DV_PAGE_end = .; + } :BL_SEC_DV_PAGE + +#ifdef FM_BETA + JUMP_LOAD 0 : { + ve_reset_handler.o(.text .text.*) + } :JUMP_LOAD +#endif + + SEC_CODE PASTE(HIBASE,01000) : { + *(.text) *(.text.*) + *(.rodata) *(.doaata.*) + } :TEXT + + SEC_DATA : { + *(.data) *(.data.*) + *(.bss) *(.bss.*) + } :DATA +} + +#endif /* ! BUILD_RVCT */ diff --git a/linaro/arm-virt-bl/big-little/bl.scf.S b/linaro/arm-virt-bl/big-little/bl.scf.S new file mode 100644 index 0000000..aa74eff --- /dev/null +++ b/linaro/arm-virt-bl/big-little/bl.scf.S @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "scf-macros.h" + +#ifdef BUILD_RVCT + +LOAD_REGION1 PASTE(HIBASE,0D000) NOCOMPRESS ALIGN 4096 65536 +{ + BL_DV_PAGE +0x0 ALIGN 4096 4096 + { + *(.data.BL_DV_PAGE) + } + BL_CODE PASTE(HIBASE,0E000) FIXED + { + *(+RO) + } + BL_DATA +0x0 + { + *(+ZI,+RW) + } +} + +#else /* ! BUILD_RVCT */ + +PHDRS { + BL_DV_PAGE PT_LOAD; + TEXT PT_LOAD; + DATA PT_LOAD; +} + +SECTIONS { + BL_DV_PAGE PASTE(HIBASE,0D000) : { /* ALIGN(4096) */ + __BL_DV_PAGE_base = .; + *(.data.BL_DV_PAGE) + __BL_DV_PAGE_end = .; + } :BL_DV_PAGE + + BL_CODE PASTE(HIBASE,0E000) : { + *(.text) *(.text.*) + *(.rodata) *(.rodata.*) + } :TEXT + + S2_TRAP_SECTION : { + __s2_trap_section_base = .; + *(.data.s2_trap_section) + __s2_trap_section_end = .; + } :DATA + + VIRT_DESC_SECTION : { + __virt_desc_section_base = .; + *(.data.virt_desc_section) + __virt_desc_section_end = .; + } :DATA + + BL_DATA : { + *(.data) *(.data.*) + *(.bss) *(.bss.*) + } :DATA +} + +#endif /* ! BUILD_RVCT */ diff --git a/linaro/arm-virt-bl/big-little/common/cci.c b/linaro/arm-virt-bl/big-little/common/cci.c new file mode 100644 index 0000000..3c47e19 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/common/cci.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "misc.h" +#include "virt_helpers.h" +#include "hyp_types.h" + +void enable_cci_snoops(unsigned cluster_id) +{ + /* Turn off CCI snoops & DVM Messages */ + if (cluster_id) + write32(A7_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x3); + else + write32(A15_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x3); + + dsb(); + + /* Wait for the dust to settle down */ + while (read32(CCI_BASE + STATUS_REG) & 0x1) ; + + return; +} + +void disable_cci_snoops(unsigned cluster_id) +{ + /* Turn off CCI snoops & DVM messages */ + if (cluster_id) + write32(A7_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x0); + else + write32(A15_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x0); + + dsb(); + + /* Wait for the dust to settle down */ + while (read32(CCI_BASE + STATUS_REG) & 0x1) ; + + return; +} diff --git a/linaro/arm-virt-bl/big-little/common/hyp_setup.c b/linaro/arm-virt-bl/big-little/common/hyp_setup.c new file mode 100644 index 0000000..59a0a4a --- /dev/null +++ b/linaro/arm-virt-bl/big-little/common/hyp_setup.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "context.h" +#include "misc.h" +#include "events.h" +#include "virt_helpers.h" +#include "virtualisor.h" +#include "bl.h" + +#ifndef ASYNC_SWITCH +#define ASYNC_SWITCH 0 +#endif + +extern unsigned vectors; +extern system_context switcher_context; +extern void SetupVirtExtPageTables(unsigned, unsigned); +extern void Enable2ndStagePageTables(void); +extern void monmode_setup(void); +extern void config_uart(void); +extern void SetupVGIC(unsigned); +extern void enable_trigger(unsigned); +extern void restore_context(unsigned); + +unsigned host_cluster = HOST_CLUSTER; +unsigned switcher = SWITCHER; +vm_state guestos_state[MAX_CPUIFS]; +unsigned guestos_state_size = sizeof(vm_state); + +/* + * To make events work across a non-coherent interconnect, events + * are allocated in an SO or DV page. + */ +unsigned event[NUM_CPUS][MAX_EVENTS] __attribute__ ((section("BL_DV_PAGE"))); + +/* + * C function to perform the remaining initialisation + * once the MMU has been enabled after a cold reset + */ +void bl_rest_init(void) +{ + unsigned first_cpu = find_first_cpu(); + unsigned cpu_id = read_cpuid(); + unsigned cluster_id = read_clusterid(); + unsigned warm_reset = 0; + + /* HYP mode initialisation performed after every reset */ + write_hvbar((unsigned)&vectors); + Enable2ndStagePageTables(); + + /* Initialise a per cpu UART */ + config_uart(); + + if (switcher) { + /* + * Ask the secure world to initialise its context. + * Not required when "always on" + */ + smc(SMC_SEC_INIT, 0); + + /* + * Since we are using the shared vgic, we need to map + * the cpuids to the cpu interfaces as there is no + * longer a 1:1 mapping + */ + map_cpuif(cluster_id, cpu_id); + + if (ASYNC_SWITCH && first_cpu == cpu_id) + enable_trigger(read_cntfrq()); + } else { + + /* + * Only one cpu should enable the CCI while the other + * cpus wait. + */ + if (first_cpu == cpu_id && cluster_id == host_cluster) { + write32(A7_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x3); + write32(A15_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x3); + dsb(); + } + + /* Wait for the dust to settle down */ + while (read32(CCI_BASE + STATUS_REG) & 0x1) ; + } + + /* Initialise the Virtual GIC and the Virtualizer */ + SetupVGIC(warm_reset); + SetupVirtualisor(first_cpu); + + return; +} diff --git a/linaro/arm-virt-bl/big-little/common/hyp_vectors.S b/linaro/arm-virt-bl/big-little/common/hyp_vectors.S new file mode 100755 index 0000000..ba5dd2d --- /dev/null +++ b/linaro/arm-virt-bl/big-little/common/hyp_vectors.S @@ -0,0 +1,399 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + AREA |.text.HypVectors|, CODE, READONLY, ALIGN=5 + + PRESERVE8 + + IMPORT handle_interrupt + IMPORT HandleVirtualisor + IMPORT guestos_state + IMPORT guestos_state_size + IMPORT get_sp + IMPORT output_string + IMPORT virt_dead + IMPORT SetupVirtExtPageTables + IMPORT Enable2ndStagePageTables + IMPORT restore_context + IMPORT read_hsctlr + IMPORT write_hsctlr + IMPORT write_hmair0 + IMPORT write_httbr + IMPORT write_htcr + IMPORT bl_rest_init + IMPORT hyp_l1_pagetable + +#if !ASYNC_SWITCH + IMPORT is_hvc + IMPORT HandleHVC +#endif + + EXPORT vectors + EXPORT iabt_entry + EXPORT dabt_entry + EXPORT undef_entry + EXPORT svc_hyp_entry + EXPORT fiq_entry + EXPORT bl_setup + EXPORT hyp_warm_reset_handler + + + MACRO + hyp_entry $reg + SUB $reg, $reg, #72 + + ; --------------------------------------------------- + ; Save all GP registers + ; Save User mode LR which the HYP mode will use now. + ; Save HYP mode ELR & SPSR in case we are re-entrant + ; Pass saved context as argument to next bit of code + ; --------------------------------------------------- + STMIA $reg, {r0-r12} + MRS r0, ELR_hyp + MRS r1, SPSR + MRS r2, LR_usr + ADD r3, $reg, #60 + STMIA r3, {r0-r2} + MEND + + MACRO + hyp_exit $reg + ADD r3, $reg, #60 + LDMIA r3, {r0-r2} + MSR ELR_hyp, r0 + MSR SPSR_cxsf, r1 + MSR LR_usr, r2 + + ; ---------------------------------------------------- + ; We do need to clear the BTAC though since it is + ; virtually-addressed with no regard for the NS bit + ; ---------------------------------------------------- + MCR p15, 0, r0, c7, c5, 6 ; invalidate BTAC + + LDMIA $reg, {r0-r12} + ADD $reg, $reg, #72 + ERET + MEND + +#if 0 +dabort_string + DCB " Virtualisor-DAB!\n", 0 +undef_string + DCB " Virtualisor-UND!\n", 0 +pabort_string + DCB " Virtualisor-PAB!\n", 0 +swi_string + DCB " Virtualisor-SWI!\n", 0 +irq_string + DCB " Virtualisor-IRQ!\n", 0 +fiq_string + DCB " Virtualisor-FIQ!\n", 0 +unused_string + DCB " Virtualisor-UNU!\n", 0 + + ALIGN +#endif + + ; ---------------------------------------------------- + ; Defines for enabling HYP mode MMU + ; ---------------------------------------------------- + +ENABLE EQU 0x1 +DISABLE EQU 0x0 + + ; ---------------------------------------------------- + ; HMAIR attributes relevant to us + ; ---------------------------------------------------- +HMAIR_INNER_WB_RWA_MEM EQU 0x0f +HMAIR_OUTER_WB_RWA_MEM EQU 0xf0 +HMAIR_DEVICE_MEM EQU 0x04 +HMAIR_SO_MEM EQU 0x00 + +IDX0 EQU (HMAIR_DEVICE_MEM << 0) +IDX1 EQU ((HMAIR_INNER_WB_RWA_MEM :OR: HMAIR_OUTER_WB_RWA_MEM) << 8) +IDX2 EQU (HMAIR_SO_MEM << 16) + + ; ---------------------------------------------------- + ; HSCTLR defines + ; ---------------------------------------------------- +ICACHE EQU (ENABLE << 12) +ALIGN EQU (ENABLE << 1) +DCACHE EQU (ENABLE << 2) +MMU EQU (ENABLE << 0) + + ; ---------------------------------------------------- + ; HTCR defines + ; ---------------------------------------------------- +CR_C_WBWA EQU 0x1 +CR_OUTER_SH EQU 0x2 +CR_INNER_SH EQU 0x3 +CR_ADDR_SPC_4GB EQU 0x0 + +EAE EQU (ENABLE << 31) +T0SZ EQU (CR_ADDR_SPC_4GB << 0) +IRGN0 EQU (CR_C_WBWA << 8) +ORGN0 EQU (CR_C_WBWA << 10) +SH0 EQU (CR_INNER_SH << 12) + +vectors + B bl_setup ; reset + B undef_entry ; undef + B svc_hyp_entry ; swi + B iabt_entry ; pabt + B dabt_entry ; dabt + B hvc_entry ; HVC + B irq_entry ; irq + B fiq_entry ; fiq + +bl_setup FUNCTION + ; ---------------------------------------------------- + ; This function is called after a reset. 'r0-r3' can + ; be corrupted after a cold reset. + ; Its also assumed that we are taking part in coherency + ; already (entered in secure world) + ; ---------------------------------------------------- + + ; ---------------------------------------------------- + ; Enable Caches + ; ---------------------------------------------------- + mrc p15, 4, r0, c1, c0, 0 + orr r0, #ICACHE + orr r0, #ALIGN + orr r0, #DCACHE + mcr p15, 4, r0, c1, c0, 0 + isb + + msr elr_hyp, lr + + ; ---------------------------------------------------- + ; Give yourself a stack without enabling the MMU so + ; that the pagetables can be created in C code. + ; ---------------------------------------------------- + + ; ---------------------------------------------------- + ; Allocate the HYP stack first up to do greater things + ; ---------------------------------------------------- + ldr r0, =guestos_state + ldr r1, =guestos_state_size + ldr r1, [r1] + bl get_sp + mov sp, r0 + + ; ---------------------------------------------------- + ; Create the 2nd stage and HYP mode page tables + ; ---------------------------------------------------- + bl SetupVirtExtPageTables + + ; ---------------------------------------------------- + ; Enable the HYP mode MMU before doing anything further + ; ---------------------------------------------------- + ldr r0, =hyp_l1_pagetable + MOV r1, #0 + mcrr p15, 4, r0, r1, c2 + ldr r0, =(IDX2 :OR: IDX1 :OR: IDX0) + mcr p15, 4, r0, c10, c2, 0 + ldr r0, =(EAE :OR: SH0 :OR: ORGN0 :OR: IRGN0 :OR: T0SZ) + mcr p15, 4, r0, c2, c0, 2 + mrc p15, 4, r0, c1, c0, 0 + orr r0, #MMU + mcr p15, 4, r0, c1, c0, 0 + dsb + isb + + ; ---------------------------------------------------- + ; Initialise the remaining bits now that the MMU is on + ; ---------------------------------------------------- + hyp_entry sp + bl bl_rest_init + hyp_exit sp + + ENDFUNC + +#if 0 +common_abt + PUSH {lr} + + BL hexword ; print r0 + + MRC p15, 0, r0, c5, c0, 0 ; DFSR + BL hexword + + MRC p15, 0, r0, c6, c0, 0 ; DFAR + BL hexword + + MRC p15, 4, r0, c5, c2, 0 ; HSR + BL hexword + + MRC p15, 4, r0, c6, c0, 0 ; HDFAR + BL hexword + + MRC p15, 4, r0, c6, c0, 2 ; HIFAR + BL hexword + + MRC p15, 4, r0, c6, c0, 4 ; HPFAR + BL hexword + + POP {lr} + BX lr + +dabt_entry + MOV r0, lr ; save lr, just in case it's interesting +#if 0 + BL common_abt +#endif + LDR r0, =dabort_string + BL output_string + B dead + +iabt_entry + MOV r0, lr ; save lr, just in case it's interesting +#if 0 + BL common_abt +#endif + LDR r0, =pabort_string + BL output_string + B dead + +undef_entry + MOV r0, lr ; save lr, just in case it's interesting +#if 0 + BL common_abt +#endif + LDR r0, =undef_string + BL output_string + B dead + +dead + B dead +#endif + +dabt_entry + B dabt_entry + +iabt_entry + B iabt_entry + +undef_entry + B undef_entry + +irq_entry + hyp_entry sp + ; ---------------------------------------------------- + ; Pass SP as arg if we intend to initiate a switchover + ; ---------------------------------------------------- + MOV r0, sp + BL handle_interrupt + hyp_exit sp + +svc_hyp_entry + B svc_hyp_entry + +fiq_entry + B fiq_entry + +hvc_entry + hyp_entry sp + + ; ---------------------------------------------------- + ; Check if we have an HVC call. The Switcher handles + ; it first. If its unable to, its passed to the + ; Virtualisor. It should be possible to cascade an HVC + ; across the two, but not for the time being. + ; ---------------------------------------------------- +#if !ASYNC_SWITCH + BL is_hvc + CMP r0, #0 + BEQ next + MOV r0, sp + BL HandleHVC + TST r0, #1 + BNE out +#endif +next + MOV r0, sp + BL HandleVirtualisor +out + hyp_exit sp + +hyp_warm_reset_handler FUNCTION + ; ---------------------------------------------------- + ; Enable Caches + ; ---------------------------------------------------- + mrc p15, 4, r0, c1, c0, 0 + orr r0, #ICACHE + orr r0, #ALIGN + orr r0, #DCACHE + mcr p15, 4, r0, c1, c0, 0 + isb + + ; ---------------------------------------------------- + ; Enable the HYP mode MMU before doing anything further + ; ---------------------------------------------------- + ldr r0, =hyp_l1_pagetable + MOV r1, #0 + mcrr p15, 4, r0, r1, c2 + ldr r0, =(IDX2 :OR: IDX1 :OR: IDX0) + mcr p15, 4, r0, c10, c2, 0 + ldr r0, =(EAE :OR: SH0 :OR: ORGN0 :OR: IRGN0 :OR: T0SZ) + mcr p15, 4, r0, c2, c0, 2 + mrc p15, 4, r0, c1, c0, 0 + orr r0, #MMU + mcr p15, 4, r0, c1, c0, 0 + dsb + isb + + ; ---------------------------------------------------- + ; Initialise the remaining bits now that the MMU is on + ; ---------------------------------------------------- + + ; ---------------------------------------------------- + ; Allocate the HYP stack first up to do greater things + ; ---------------------------------------------------- + ldr r0, =guestos_state + ldr r1, =guestos_state_size + ldr r1, [r1] + bl get_sp + mov sp, r0 + + ; ---------------------------------------------------- + ; Initialise the HVBAR + ; ---------------------------------------------------- + adr r0, vectors + mcr p15, 4, r0, c12, c0, 0 + + ; ---------------------------------------------------- + ; Initialise the 2nd stage translations for NS PL0/1 + ; ---------------------------------------------------- + bl Enable2ndStagePageTables + + ; ---------------------------------------------------- + ; Restore the context now. CPU0 is the first cpu + ; ---------------------------------------------------- + hyp_entry sp + mov r0, #0 + bl restore_context + hyp_exit sp + + ENDFUNC + + END + diff --git a/linaro/arm-virt-bl/big-little/common/pagetable_setup.c b/linaro/arm-virt-bl/big-little/common/pagetable_setup.c new file mode 100755 index 0000000..c7466dc --- /dev/null +++ b/linaro/arm-virt-bl/big-little/common/pagetable_setup.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/* ---------------------------------------------------------------------------- + * i n c l u d e s + * --------------------------------------------------------------------------*/ +#include "hyp_types.h" +#include "hyp_vmmap.h" +#include "misc.h" +#include "events.h" +#include "virt_helpers.h" + +#ifndef SWITCHER +#define SWITCHER 0 +#endif + +typedef struct { + unsigned va; + unsigned pa; + unsigned long long attrs; + unsigned long long *pt_addr; +} four_kb_pt_desc; + +/* ---------------------------------------------------------------------------- + * d e f i n e s + * --------------------------------------------------------------------------*/ +#define LEVEL1 0x1 +#define LEVEL2 0x2 + +#define HYP_PA_START 0x00000000 /* Flat mapping */ +#define HYP_PA_END 0xFFFFFFFF +#define HYP_VA_START HYP_PA_START +#define HYP_VA_END HYP_PA_END + +/* + * First level pagetables to cover 512GB. + * Only first 4GB used + */ +unsigned long long hyp_l1_pagetable[512] __attribute__ ((aligned(4096))); + +/* + * Second level pagetables to cover each GB. + * Arranged contiguously for ease + */ +unsigned long long hyp_l2_pagetable[4][512] __attribute__ ((aligned(16384))); + +/* + * Allocate one Level 3 page table which will + * create a 4K SO ordered page. + */ +unsigned long long hyp_l3_so_pt[512] __attribute__ ((aligned(4096))); + +/* + * Allocate space for 4 contiguous level 2 page + * tables which will cover the 32 bit address + * space. Align it to the 16K boundary. + */ +unsigned long long stage2_l2_pagetable[4][512] __attribute__ ((aligned(16384))); + +/* + * Allocate one Level 3 page table which will + * route guestOS physical cpu interface accesses + * to the virtual cpu interface. Align it to the + * 4K boundary. + */ +unsigned long long stage2_l3_cpuif_pt[512] __attribute__ ((aligned(4096))); + +/* + * Allocate one Level 3 page table which will + * create a 4K SO ordered page. + */ +unsigned long long stage2_l3_so_pt[512] __attribute__ ((aligned(4096))); + +#define ENABLE 0x1 +#define DISABLE 0x0 + +/* HMAIR attributes relevant to us */ +#define HMAIR_INNER_WB_RWA_MEM 0x0f +#define HMAIR_OUTER_WB_RWA_MEM 0xf0 +#define HMAIR_DEVICE_MEM 0x04 +#define HMAIR_SO_MEM 0x00 + +#define IDX0(x) ((x) << 0) +#define IDX1(x) ((x) << 8) +#define IDX2(x) ((x) << 16) + +/* Memory attributes index for HMAIR0 */ +#define HMAIR0_DEVICE_MEM_ATTR_IDX (0x0 << 2) +#define HMAIR0_NORMAL_MEM_ATTR_IDX (0x1 << 2) +#define HMAIR0_SO_MEM_ATTR_IDX (0x2 << 2) + +#define NS_BIT (1 << 5) + +/* Access permissions */ +#define AP(x) ((x) << 6) +/* HAP permissions */ +#define HAP_RO 0x1 +#define HAP_RW 0x3 +/* Simplified Access permissions */ +#define KERN_RO 0x2 +#define KERN_RW 0x0 + +/* HTCR/VTCR fields */ +#define EAE(x) ((unsigned) x << 31) +#define T0SZ(x) (x << 0) +#define IRGN0(x) (x << 8) +#define ORGN0(x) (x << 10) +#define SH0(x) (x << 12) + +#define CR_C_WBWA 0x1 +#define CR_OUTER_SH 0x2 +#define CR_INNER_SH 0x3 +#define CR_ADDR_SPC_4GB 0x0 + +/* HSCTLR fields */ +#define MMU(x) (x << 0) +#define ALIGNMENT(x) (x << 1) +#define DCACHE(x) (x << 2) +#define ICACHE(x) (x << 12) + +/* + * BUG: + * Dcache clean by MVA ops added to ensure that main memory is updated prior to + * the first page table walk upon entry into NS world. This is potentially an AEM + * bug as the descriptors should be picked from the cache itself since the VTCR + * marks PTWs as cacheable. + * It would be better to collect the writes and then perform the clean rather then + * picking them up individually. + */ +/* + * Map the physical cpu interface to the virtual + * cpu interface for OS use. + */ +static void CreateL3PageTable(four_kb_pt_desc * l3_mapping, unsigned level, + unsigned long long *base_pt_addr) +{ + unsigned one_gb_index = l3_mapping->pa >> 30; + unsigned two_mb_index = l3_mapping->pa >> 21; + unsigned four_kb_index = 0; + unsigned pa_4k_index = 0; + unsigned long long l1_desc = 0; + unsigned long long *l2_desc = 0; + unsigned long long old_attrs = 0; + unsigned long long *l1_pt_addr = 0; + unsigned long long *l2_pt_addr = 0; + unsigned long long *l3_pt_addr = l3_mapping->pt_addr; + + /* + * Indices calculated above are relative to the GB or MB they + * belong to rather than an offset of 0x0. e.g. for the 2mb index + * index = (address >> 21) - (<number of 2MBs in 1GB> x <this GB index>) + */ + + /* Calculate the level 2 page table descriptor */ + if (level == 1) { + l1_pt_addr = base_pt_addr; + l1_desc = l1_pt_addr[one_gb_index]; + l2_pt_addr = + (unsigned long long + *)((unsigned)((&l1_desc)[0] & 0xfffff000UL)); + l2_desc = &l2_pt_addr[two_mb_index - (512 * one_gb_index)]; + } else { + l2_pt_addr = &base_pt_addr[one_gb_index << 9]; + l2_desc = &l2_pt_addr[two_mb_index - (512 * one_gb_index)]; + } + + /* Preserve the old attributes */ + old_attrs = *l2_desc & 0xfff0000000000fffULL; + /* Replace block mapping with table mapping */ + *l2_desc = + (unsigned long long)(unsigned long)l3_pt_addr | TABLE_MAPPING; + + /* Create a flat mapping for all 4k descriptors to begin with */ + for (four_kb_index = 0; four_kb_index < 512; four_kb_index++) { + l3_pt_addr[four_kb_index] = + (((two_mb_index << 9) + + four_kb_index) << 12) | old_attrs | VALID_MAPPING; + } + pa_4k_index = ((l3_mapping->pa << 11) >> 11) >> 12; + + /* + * Replace the existing descriptor with new mapping and attributes + */ + l3_pt_addr[pa_4k_index] = + l3_mapping->va | l3_mapping->attrs | VALID_MAPPING; + + return; +} + +/* + * Add an 4KB mapping to an existing L3 page table. + */ +static void Add4KMapping(four_kb_pt_desc * l3_mapping) +{ + unsigned pa_4k_index = ((l3_mapping->pa << 11) >> 11) >> 12; + unsigned long long *l3_pt_addr = l3_mapping->pt_addr; + + /* + * Replace the existing descriptor with new mapping and attributes + */ + l3_pt_addr[pa_4k_index] = + l3_mapping->va | l3_mapping->attrs | VALID_MAPPING; + + return; +} + +void CreateHypModePageTables(void) +{ + unsigned num_l1_descs = 0, num_l2_descs = 0; + unsigned l1_index, l2_index; + unsigned long long l2_attrs = 0; + four_kb_pt_desc l3_desc; + + /* Create the pagetables */ + num_l1_descs = ((HYP_PA_END - HYP_PA_START) >> 30) + 1; + num_l2_descs = ((HYP_PA_END - HYP_PA_START) >> 21) + 1; + + /* Only the first 4GB are valid translations */ + for (l1_index = 0; l1_index < num_l1_descs; l1_index++) { + hyp_l1_pagetable[l1_index] = + (unsigned long long)(unsigned long) + &hyp_l2_pagetable[l1_index][0] | TABLE_MAPPING; + for (l2_index = 0; l2_index < num_l2_descs / num_l1_descs; + l2_index++) { + + if ((l2_index + (l1_index << 9)) < 32) { + /* 0-64M(Secure ROM/NOR Flash):Block mapping with RO access, Inner shareable, Inner/Outer WBWA */ + l2_attrs = + BLOCK_MAPPING | HMAIR0_NORMAL_MEM_ATTR_IDX | + NS_BIT | SHAREABILITY(0x3) | ACCESS_FLAG | + AP(KERN_RO); + ((unsigned *)&l2_attrs)[1] |= XN; + } else if ((l2_index + (l1_index << 9)) < 64) + /* 64-128M(Secure RAM) : Block mapping with RW access, Inner shareable, Inner/Outer WBWA */ + l2_attrs = + BLOCK_MAPPING | HMAIR0_NORMAL_MEM_ATTR_IDX | + NS_BIT | SHAREABILITY(0x3) | ACCESS_FLAG | + AP(KERN_RW); + else if ((l2_index + (l1_index << 9)) < 1024) { + /* 128-2048M (Peripherals) : Block mapping of Device memory */ + l2_attrs = + BLOCK_MAPPING | HMAIR0_DEVICE_MEM_ATTR_IDX | + NS_BIT | SHAREABILITY(0x3) | ACCESS_FLAG | + AP(KERN_RW); + ((unsigned *)&l2_attrs)[1] |= XN; + } else + /* 2-4GB (RAM) : Block mapping with RW access, Inner shareable, Inner/Outer WBWA */ + l2_attrs = + BLOCK_MAPPING | HMAIR0_NORMAL_MEM_ATTR_IDX | + NS_BIT | SHAREABILITY(0x3) | ACCESS_FLAG | + AP(KERN_RW); + + hyp_l2_pagetable[l1_index][l2_index] = + ((l2_index + (l1_index << 9)) << 21) | l2_attrs; + } + } + + /* + * Create a mapping for a device page to be used + * for Locks, Events & anything that is shared when both + * the clusters are executing at the same time. + */ + l3_desc.va = (unsigned)BL_DV_PAGE_base; + l3_desc.pa = (unsigned)BL_DV_PAGE_base; + l3_desc.attrs = + ACCESS_FLAG | HMAIR0_DEVICE_MEM_ATTR_IDX | SHAREABILITY(0x3) | + AP(KERN_RW); + l3_desc.pt_addr = hyp_l3_so_pt; + CreateL3PageTable(&l3_desc, LEVEL1, + (unsigned long long *)hyp_l1_pagetable); + + return; +} + +void EnableHypModePageTables(void) +{ + /* Update the HTTBR */ + write_httbr((unsigned long long)(unsigned long)hyp_l1_pagetable); + + /* + * Setup the HMAIR0 register. + * [7:0] = Device memory + * [15:8] = Normal memory, Inner and outer cacheable, WBWA + */ + write_hmair0(IDX2(HMAIR_SO_MEM) | + IDX1(HMAIR_INNER_WB_RWA_MEM | HMAIR_OUTER_WB_RWA_MEM) | + IDX0(HMAIR_DEVICE_MEM)); + + /* + * Set the HTCR. + * Pagetables are Normal memory, Inner/Outer shareable, Inner/Outer WBWA + */ + write_htcr(EAE(ENABLE) | SH0(CR_INNER_SH) | ORGN0(CR_C_WBWA) | + IRGN0(CR_C_WBWA) | T0SZ(CR_ADDR_SPC_4GB)); + + /* Enable the Hyp MMU */ + write_hsctlr(ICACHE(ENABLE) | DCACHE(ENABLE) | ALIGNMENT(ENABLE) | + MMU(ENABLE)); + + return; +} + +void Create2ndStagePageTables(void) +{ + unsigned two_mb_index = 0; + unsigned one_gb_index = 0; + unsigned long long level2_desc = 0; + four_kb_pt_desc l3_desc = { 0 }; + + /* + * Create the flat mapped 2nd stage page tables. + * This should be done only once. The remaining + * cpus can share the mappings and wait while + * this is being done. + */ + for (one_gb_index = 0; one_gb_index < 4; one_gb_index++) + for (two_mb_index = 0; two_mb_index < 512; two_mb_index++) { + + if ((two_mb_index + (one_gb_index << 9)) < 32) + /* 0-64M (Secure ROM/NOR Flash) : Block mapping with RO access, Inner shareable, Inner/Outer WBWA */ + level2_desc = + ACCESS_FLAG | SHAREABILITY(0x3) | AP(HAP_RO) + | MEM_ATTR(0xf) | BLOCK_MAPPING; + else if ((two_mb_index + (one_gb_index << 9)) < 64) + /* 64-128M (Secure RAM) : Block mapping with RW access, Inner shareable, Inner/Outer WBWA */ + level2_desc = + ACCESS_FLAG | SHAREABILITY(0x3) | AP(HAP_RW) + | MEM_ATTR(0xf) | BLOCK_MAPPING; + else if ((two_mb_index + (one_gb_index << 9)) < 1024) + /* 128-2048M (Peripherals) : Block mapping of Device memory */ + level2_desc = + ACCESS_FLAG | SHAREABILITY(0x3) | AP(HAP_RW) + | MEM_ATTR(0x1) | BLOCK_MAPPING; + else + /* 2-4GB (RAM) : Block mapping with RW access, Inner shareable, Inner/Outer WBWA */ + level2_desc = + ACCESS_FLAG | SHAREABILITY(0x3) | AP(HAP_RW) + | MEM_ATTR(0xf) | BLOCK_MAPPING; + + stage2_l2_pagetable[one_gb_index][two_mb_index] = + (two_mb_index + + (512 * one_gb_index) << 21) | level2_desc; + + } + + /* First 4KB Mapping PCPUIF to the VCPUIF for the payload software */ + l3_desc.va = VGIC_VM_PHY_BASE; + l3_desc.pa = GIC_IC_PHY_BASE; + l3_desc.attrs = + ACCESS_FLAG | SHAREABILITY(0x3) | ACCESS_PERM(0x3) | MEM_ATTR(0x1); + l3_desc.pt_addr = stage2_l3_cpuif_pt; + CreateL3PageTable(&l3_desc, LEVEL2, + (unsigned long long *)stage2_l2_pagetable); + + /* Second 4KB Mapping PCPUIF to the VCPUIF for the payload software */ + l3_desc.va = VGIC_VM_PHY_BASE + 0x1000; + l3_desc.pa = GIC_IC_PHY_BASE + 0x1000; + l3_desc.attrs = + ACCESS_FLAG | SHAREABILITY(0x3) | ACCESS_PERM(0x3) | MEM_ATTR(0x1); + l3_desc.pt_addr = stage2_l3_cpuif_pt; + Add4KMapping(&l3_desc); + + /* + * Create a mapping for a device page to be used + * for Locks, Events & anything that is shared when both + * the clusters are executing at the same time. + */ + l3_desc.va = (unsigned)BL_DV_PAGE_base; + l3_desc.pa = (unsigned)BL_DV_PAGE_base; + l3_desc.attrs = + ACCESS_FLAG | SHAREABILITY(0x3) | ACCESS_PERM(0x3) | MEM_ATTR(0x1); + l3_desc.pt_addr = stage2_l3_so_pt; + CreateL3PageTable(&l3_desc, LEVEL2, + (unsigned long long *)stage2_l2_pagetable); + + return; +} + +void Enable2ndStagePageTables(void) +{ + /* + * Set the VTCR to: + * Normal memory outer shareable, Device memory shareable + * Outer and Inner WBWA + * Start at level 2 + * Size of addressed region is 4GB (16k worth of page tables) + */ + write_vtcr(SH0(CR_INNER_SH) | ORGN0(CR_C_WBWA) | IRGN0(CR_C_WBWA)); + + /* Address is already aligned to 16k or 2*14 */ + write_vttbr((unsigned long long)(unsigned long)stage2_l2_pagetable); + + write_hcr(read_hcr() | HCR_VM); + + /* + * TODO: We do not need a synchronization barrier here as we + * are not yet executing out of NS PL0 & PL1 and there will be + * a barrier at some point before that. + */ + return; +} + +void SetupVirtExtPageTables(void) +{ + unsigned cpu_id = read_cpuid(); + unsigned first_cpu = find_first_cpu(); + unsigned cluster_id = read_clusterid(); + unsigned abs_cpuid = 0; + + if (!SWITCHER) + abs_cpuid = abs_cpuid(cpu_id, cluster_id); + + /* + * First cpu creates the pagetables after + * a cold reset. Reused by all cpus across + * warm resets. + */ + if (SWITCHER) { + + /* + * While switching its possible that the host cluster + * is brought out of reset first. Hence, the first + * cpu of whichever cluster reaches here does the + * pagetable setup + */ + if (cpu_id == first_cpu) { + CreateHypModePageTables(); + Create2ndStagePageTables(); + set_events(VIRT_PGT_DONE); + } + + wait_for_event(VIRT_PGT_DONE, cpu_id); + reset_event(VIRT_PGT_DONE, cpu_id); + + } else { + + /* + * Any cluster can do the initialisation as long as + * only one of them does it. + */ + if (cpu_id == first_cpu && cluster_id == HOST_CLUSTER) { + CreateHypModePageTables(); + Create2ndStagePageTables(); + set_events(VIRT_PGT_DONE); + } + + wait_for_event(VIRT_PGT_DONE, abs_cpuid); + reset_event(VIRT_PGT_DONE, abs_cpuid); + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/common/vgic_handle.c b/linaro/arm-virt-bl/big-little/common/vgic_handle.c new file mode 100644 index 0000000..b750fe3 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/common/vgic_handle.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "int_master.h" +#include "gic_registers.h" +#include "virt_helpers.h" +#include "misc.h" +#include "events.h" +#include "vgiclib.h" + +extern vm_context *trigger_entry(vm_context *, unsigned); +extern unsigned get_cpuinfo(unsigned); +extern unsigned check_switchover_ipi(unsigned, unsigned); +extern void keep_trigger_alive(void); +extern unsigned check_trigger(unsigned, unsigned); + +/* + * Flag to make the interrupt handling code aware that + * each interrupt needs to be checked for it being a + * signal to switch to the other cluster + */ +#ifndef ASYNC_SWITCH +#define ASYNC_SWITCH 0 +#endif + +void gic_send_ipi(unsigned cpu_mask, unsigned ipi_num) +{ + write32(GIC_ID_PHY_BASE + GICD_SW, + ((cpu_mask & 0xff) << 16) | (ipi_num & 0xf)); +} + +void gic_enable_int(unsigned num) +{ + unsigned int regbase; + + regbase = GIC_ID_PHY_BASE + GICD_ENABLESET + ((num >> 5) << 2); + write32(regbase, 1 << (num & 0x1F)); +} + +void gic_disable_int(unsigned num) +{ + unsigned int regbase; + + regbase = GIC_ID_PHY_BASE + GICD_ENABLECLEAR + ((num >> 5) << 2); + write32(regbase, 1 << (num & 0x1F)); +} + +void gic_deactivate_int(unsigned num) +{ + write32(GIC_IC_PHY_BASE + GICC_DEACTIVATE, num); +} + +void gic_eoi_int(unsigned num) +{ + write32(GIC_IC_PHY_BASE + GICC_EOI, num); +} + +unsigned gic_ack_int(void) +{ + return read32(GIC_IC_PHY_BASE + GICC_INTACK); +} + +unsigned gic_int_num(void) +{ + unsigned intcount = 0; + + intcount = read32(GIC_ID_PHY_BASE + GICD_CTR); + intcount = ((intcount & 0x1F) + 1) * 32; + + return intcount; +} + +/* + * handle_interrupt() will be called when an interrupt arrives + */ +vm_context *handle_interrupt(vm_context * context) +{ + unsigned int status, i, src_cpu = 0; + unsigned cpuid = read_cpuid(); + unsigned cluster_id = read_clusterid(); + unsigned list_desc = 0; + unsigned int_pri = 0; + unsigned cpu_if = get_cpuif(cluster_id, cpuid); + vm_context *ret_ctx = context; + unsigned do_switch = 0, first_cpu = find_first_cpu(); + + /* + * Get the interrupt # + */ + status = gic_ack_int(); + i = status & 0x3FF; + + /* + * Stop if there are no more interrupts + */ + if (i == 1023) { + printf("Spurious interrupt %d \n", i); + return ret_ctx; + } + + if (ASYNC_SWITCH && cpuid == first_cpu) + keep_trigger_alive(); + + /* + * Special case IPIs, since we need the source CPU ID + */ + if (i < 16) { + src_cpu = (status >> 10) & INTACK_CPUID_MASK; + + /* Check whether we have been requested to switchover */ + do_switch = check_switchover_ipi(cpu_if, i); + + /* + * SGI Ack actually returns the source cpu interface + * which needs to be mapped to the apt cpuid. + */ + src_cpu = get_cpuinfo(src_cpu) & 0xf; + + /* + * IPI handling: + * If Split EOI is not enabled, then writing to the EOI + * register drops the priority and deactivates the IPI + * together. Otherwise, we need to do it seperately. + * Note that in either case, the OS cannot deactivate the + * IPI as writing to the virtual EOI register will not + * bring about a state change in the physical distributor + * state machine. + */ + gic_eoi_int(status); + if (read32(GIC_IC_PHY_BASE + GICC_CTL) & 0x200) + gic_deactivate_int(status); + + if (do_switch) { + /* + * switch_cluster() takes the first_cpu as its arg. Since + * all the cores are expected to power down, its reasonable + * to assume cpu0 is the first cpu and will take care of + * saving all the global context. + */ + switch_cluster(first_cpu); + return ret_ctx; + } + } + + /* + * Check if this interrupt is meant to trigger to switch to the + * other cluster. If so, then we do not forward the interrupt + * to the payload software. + */ + if (ASYNC_SWITCH && check_trigger(i, status)) + return ret_ctx; + + /* + * TODO: Further optimizations can be done later when there are + * more interrupts apart from timer & uart. + */ + /* + * vGIC 11.0 onwards split EOI functionality has to be used for + * all interrupts. EOIing the interrupt from the VCPUIF will only + * deactivate the interrupt (clear the active bit) and not clear + * the active priority at the PCPUIF. + * Do this only for non SGIs as their priority has already been + * dropped. + */ + if (i >= 16) + write32(GIC_IC_PHY_BASE + GICC_PRIODROP, i); + + /* + * Priority reg = (interrupt no. / 4) x 4 bytes. + * Priority index = interrupt no. % 4 x 8 bits (8 bits for each priority value) + * Prioriity value = Priority reg >> Priority index + */ + int_pri = + read32(GIC_ID_PHY_BASE + GICD_PRI + + ((i >> 2) << 2)) >> ((i & 0x3) << 3); + + /* + * Signal interrupts as secure to the VCPUIF since the OS will write to the EnableS + * bit of the VCPUIF through the 2nd stage translations. + * TODO: Priority is being read as a 8 bit value from the distributor registers + * and passed as a 5 bit value. Need to check if this will cause problems. + */ + if (i < 16) + list_desc = + STATE(PENDING) | (int_pri >> 3) << 23 | src_cpu << 10 | i; + else + list_desc = + HW_IRQ | STATE(PENDING) | (int_pri >> 3) << 23 | i << 10 | + i; + + enqueue_interrupt(list_desc, cpuid); + + return ret_ctx; +} diff --git a/linaro/arm-virt-bl/big-little/common/vgic_setup.c b/linaro/arm-virt-bl/big-little/common/vgic_setup.c new file mode 100644 index 0000000..15625cf --- /dev/null +++ b/linaro/arm-virt-bl/big-little/common/vgic_setup.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "int_master.h" +#include "gic_registers.h" +#include "virt_helpers.h" +#include "misc.h" +#include "events.h" +#include "vgiclib.h" + +/* + * The Big-little spftware needs to bother itself with + * bareminimal vGIC configuration. + * + * 1. Distributor. Security bits should be taken care of + * by the boot firmaware after a cold reset. Big-little + * code should initialise private interrupts as secure + * after a warm reset. + * + * 2. Physical Cpu interface. Initialised by us after + * both warm and cold reset. + * + * 3. Virtual CPU interface (HYP view). Initialised by us + * after cold reset & restored after warm reset. + * + * 4. Virtual CPU interface (CPU view). Initialised by + * the payload software after cold reset and restored by + * us after a warm reset. + */ +static void gic_cpuinit() +{ + /* Disable the PCPUIF before configuring it. */ + write32(GIC_IC_PHY_BASE + GICC_CTL, 0x0); + write32(GIC_IC_PHY_BASE + GICC_BP, 0x0); + write32(GIC_IC_PHY_BASE + GICC_PRIMASK, 0xFF); + /* Enable split EOI & Non-secure PCPUIF */ + write32(GIC_IC_PHY_BASE + GICC_CTL, 0x201); +} + +void SetupVGIC(unsigned warm_reset) +{ + /* + * Initialise the HYP view Virtual CPU interface after + * a cold reset + */ + if (!warm_reset) + vgic_init(); + + /* Initialise the Physical cpu interface */ + gic_cpuinit(); + + /* + * Enable Virtual exceptions + */ + write_hcr(read_hcr() | HCR_AMO | HCR_IMO | HCR_FMO); + + /* + * TODO: Barriers not needed here as there will surely + * be others further down the line before virtual + * exceptions are used. + */ + return; +} diff --git a/linaro/arm-virt-bl/big-little/common/vgiclib.c b/linaro/arm-virt-bl/big-little/common/vgiclib.c new file mode 100644 index 0000000..2a27088 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/common/vgiclib.c @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "vgiclib.h" +#include "misc.h" +#include "virt_helpers.h" +#include "int_master.h" + +/* + * Manage overflowints somehow.. static pool with recycling allocators. + */ + +#define MAXOVERFLOWINTS 200 + +static struct overflowint *freeoverflows[NUM_CPUS]; +static struct overflowint theoverflowints[NUM_CPUS][MAXOVERFLOWINTS]; +static struct gic_cpuif cpuifs[NUM_CPUS]; +static unsigned hv_lr_count[NUM_CPUS] = { 0 }; + +void dump_vgic_state() +{ + unsigned int i; + + printf("VGIC state:\n"); + printf(" Control : 0x%x \n", read32(VGIC_HV_PHY_BASE + GICH_CTL)); + printf(" ActivePri: 0x%x \n", read32(VGIC_HV_PHY_BASE + GICH_APR0)); + for (i = 0; i < 4; i++) { + printf(" List : 0x%x \n", + read32(VGIC_HV_PHY_BASE + GICH_LR_BASE + (i * 4))); + } +} + +static struct overflowint *get_overflowint(unsigned cpuid) +{ + struct overflowint *p = freeoverflows[cpuid]; + + if (!p) { + printf("Panic: Out of overflow interrupt slots.\n"); + printf("Recompile with larger MAXOVERFLOWINTS.\n"); + panic(); + } + + freeoverflows[cpuid] = p->next; + + return p; +} + +static void free_overflowint(struct overflowint *p, unsigned cpuid) +{ + p->next = freeoverflows[cpuid]; + freeoverflows[cpuid] = p; +} + +void vgic_init(void) +{ + unsigned int i; + unsigned cpuid = read_cpuid(); + + freeoverflows[cpuid] = 0x0; + + for (i = 0; i < MAXOVERFLOWINTS; i++) { + free_overflowint(&(theoverflowints[cpuid][i]), cpuid); + } + + /* + * Find the number of List registers + * TODO: Will not work if individual cpus can have different number + * of list registers across clusters. Needs to be detected for each + * access then. + */ + hv_lr_count[cpuid] = (read32(VGIC_HV_PHY_BASE + GICH_VTR) & 0x3f) + 1; + + /* Enable virtual interrupts & if required, maintenance interrupts */ + write32(VGIC_HV_PHY_BASE + GICH_CTL, VGICH_HCR_EN); + + return; +} + +/* + * Abstracted entry accessor functions. Work for live or saved state + */ +static void set_vgic_entry(unsigned int descr, unsigned int slot) +{ + write32(VGIC_HV_PHY_BASE + GICH_LR_BASE + (slot * 4), descr); +} + +static unsigned int get_vgic_entry(unsigned int slot) +{ + return read32(VGIC_HV_PHY_BASE + GICH_LR_BASE + (slot * 4)); +} + +/* + * Abstracted status accessor functions, as above + */ +static void set_vgic_status(unsigned int status) +{ + write32(VGIC_HV_PHY_BASE + GICH_CTL, status); +} + +static unsigned int get_vgic_status(void) +{ + return read32(VGIC_HV_PHY_BASE + GICH_CTL); +} + +/* + * Add an entry to the queue, the queue is kept in descending priority + * * (that is to say, ascending numerical priority) order. + * * + * * Static function to assist with this, only called if the int is going in the queue. + */ +static void set_vgic_queue_entry(struct gic_cpuif *cpuif, unsigned int descr) +{ + unsigned int pri = (descr >> 20) & 0xFF; + struct overflowint **oflowh, *oflowp; + unsigned cpuid = read_cpuid(); + + /* + * If we are queuing something and there is currently no queue, set the interrupt bit + */ + if (!(cpuif->overflow)) + set_vgic_status(get_vgic_status() | 0x2); + + /* + * Determine insertion point, might be the end of the list + */ + for (oflowh = &(cpuif->overflow); *oflowh; oflowh = &((*oflowh)->next)) + if ((*oflowh)->priority > pri) + break; + + oflowp = get_overflowint(cpuid); + oflowp->priority = pri; + oflowp->value = descr; + oflowp->next = *oflowh; + *oflowh = oflowp; +} + +/* + * The vGIC spec implements 64 list registers across two 32-bit status + * registers. Since all of the list registers may not be implemented, + * this function returns the maximum index we need to bother about. + */ +static inline unsigned elrsr_max_index(unsigned cpuid) +{ + return (hv_lr_count[cpuid] - 1) >> 5; +} + +/* + * In a HYP view list register status register both active and unimplemented + * interrupts are represented by a 0 bit. This function returns a 32-bit value + * where each set bit represents an active list register. Its basically the + * inverse of what the elrsr returns while taking into account unimplemented + * interrupts. + */ +static unsigned get_elrsr_active_bits(unsigned index, unsigned cpuid, + unsigned max_index) +{ + unsigned elrsr = + ~(read32(VGIC_HV_PHY_BASE + GICH_ELRSR0 + (index << 2))); + + if (index == max_index) { + /* + * Get the remainder, shift 1 times remainder and subtract 1 + * from it to form the mask. + */ + elrsr &= (1 << (hv_lr_count[cpuid] - (32 * max_index))) - 1; + } else if (index > max_index) { + /* + * There can never be active virqs when the list registers + * do not exist. + */ + elrsr = 0; + } + + return elrsr; +} + +void vgic_savestate(unsigned int cpu) +{ + struct gic_cpuif *cpuif = &(cpuifs[cpu]); + unsigned int i, ctr = 0, cur_elrsr = 0; + unsigned max_index = elrsr_max_index(cpu); + + for (ctr = 0; ctr <= max_index; ctr++) { + /* Negate read value so that set bit corresponds to a !inactive register */ + cur_elrsr = get_elrsr_active_bits(ctr, cpu, max_index); + cpuif->elrsr[ctr] = cur_elrsr; + + for (i = bitindex(cur_elrsr); ((int)i) >= 0; + i = bitindex(cur_elrsr)) { + unsigned list_reg = + read32(VGIC_HV_PHY_BASE + GICH_LR_BASE + + ((1 << 7) * ctr) + (i << 2)); + unsigned int_id = (list_reg >> 10) & 0x3ff; + + /* Clear the saved bit index */ + cur_elrsr &= ~(1 << i); + + /* + * Invalidate the pending/active virtual interrupt. Since its a shared vGIC + * this irq will persist till the next switch and hence create a duplicate. + */ + write32(VGIC_HV_PHY_BASE + GICH_LR_BASE + + ((1 << 7) * ctr) + (i << 2), + list_reg & ~(0x3 << 28)); + + /* + * While saving queued IPI context, ensure that the requesting cpu + * interface is mapped to it counterpart on the inbound cluster + */ + if (int_id < 16) { + unsigned ob_cpuid = int_id & 0x7; + unsigned ob_clusterid = read_clusterid(); + unsigned ib_cpuif = 0; + + ib_cpuif = get_cpuif(!ob_clusterid, ob_cpuid); + /* Clear the cpu interface bits and place inbound cpu interface instead */ + list_reg = + (list_reg & ~(0x7 << 10)) | (ib_cpuif << + 10); + } else if (int_id < 32) { + /* + * Pending Private peripheral interrupts will be recreated from scratch + * so no need to save them. + */ + cpuif->elrsr[ctr] &= ~(1 << i); + continue; + } + + cpuif->ints[i] = list_reg; + + } + } + + cpuif->status = read32(VGIC_HV_PHY_BASE + GICH_CTL); + cpuif->activepris = read32(VGIC_HV_PHY_BASE + GICH_APR0); + + write32(VGIC_HV_PHY_BASE + GICH_CTL, 0); /* SMP */ + + return; +} + +void vgic_loadstate(unsigned int cpu) +{ + struct gic_cpuif *cpuif = &(cpuifs[cpu]); + unsigned int i, ctr = 0, cur_elrsr = 0; + unsigned max_index = elrsr_max_index(cpu); + + for (ctr = 0; ctr <= max_index; ctr++) { + cur_elrsr = cpuif->elrsr[ctr]; + + for (i = bitindex(cur_elrsr); ((int)i) >= 0; + i = bitindex(cur_elrsr)) { + write32(VGIC_HV_PHY_BASE + GICH_LR_BASE + + ((1 << 7) * ctr) + (i << 2), cpuif->ints[i]); + + /* Clear the restored bit index */ + cur_elrsr &= ~(1 << i); + } + } + + write32(VGIC_HV_PHY_BASE + GICH_CTL, cpuif->status); + write32(VGIC_HV_PHY_BASE + GICH_APR0, cpuif->activepris); + + return; +} + +/* + * vgic_refresh: Generic "maintenance" routine for the VGIC + * * + * * This is called: + * * - On maintenance interrupt. We get maintenance interrupts for + * * two reasons: + * * o Non-zero EOI skid. This routine deals with the skid and sets + * * the field to 0, quenching the interrupt source. + * * o "Nearly empty" interrupt bit set, and nearly empty condition + * * exists. This interrupt source is quenched by filling the + * * slots (and clearing the interrupt bit if the queue is now empty) + * * - When a new interrupt arrives and the cached "free slot" value + * * indicates that there are no free slots. We expect to scavenge some + * * slots from interrupts which have been completed by the VM. + * * + * * This routine is O(n) in the number of skidded EOI's + O(m) in the number + * * of interrupt slots provided - since this is constant for an + * * implementation it's really O(1). + * * + * * If this VGIC instance is currently live on a CPU it is only legal to + * * execute this routine on that CPU. + */ +void vgic_refresh(unsigned int cpu) +{ + struct gic_cpuif *cpuif = &(cpuifs[cpu]); + unsigned int i, value, status, newstatus; + struct overflowint **oflowh, *oflowp; + + /* + * Grab a copy of the status. + */ + status = get_vgic_status(); + + /* + * "newstatus" is the value to be written back if needed. Whatever + * * happens, we will clear the slipped EOI count by the time we are done + */ + newstatus = status & 0x07FFFFFF; + + /* + * See if there are any "slipped" EOIs + */ + i = (status >> 27) & 0x1F; + + if (i) { + /* + * If there are, let's deal with them. + * * + * * We will walk through the list of queued interrupts, deactivating the + * * ACTIVE ones as needed until we either have no more slipped EOI's to + * * do or run out of queued interrupts. If we run out of queued + * * interrupts first, that's UNPREDICTABLE behaviour (and the fault of + * * the VM). In this case we will just ignore the surplus EOIs. + * * + * * After EOI'ing, we delete the entry if it was just ACTIVE or set it + * * to PENDING if it was PENDING+ACTIVE. + * * + * * Use a handle to point to the list entries to avoid the need for + * * special cases in the loop. + */ + oflowh = &(cpuif->overflow); + + while (i && *oflowh) { + value = (*oflowh)->value; + if (value & VGIC_ENTRY_ACTIVE) { + /* + * It's ACTIVE (or PENDING+ACTIVE) + */ + i--; + + if (value & VGIC_ENTRY_HW) { + /* + * HW bit set, so we need to pass on an EOI. This doesn't ever happen + * * for IPIs, so just pass on the 10-bit "Hardware ID" + */ + gic_deactivate_int((value >> 10) & + 0x3FF); + } + + if (value & VGIC_ENTRY_PENDING) { + /* + * It was PENDING+ACTIVE, clear the ACTIVE bit and move on + */ + (*oflowh)->value &= ~VGIC_ENTRY_ACTIVE; + } else { + /* + * It was only ACTIVE, so we need to delete it.. + */ + oflowp = *oflowh; + oflowh = &(oflowp->next); + free_overflowint(oflowp, cpu); + } + } else { + /* + * It wasn't ACTIVE :( Try the next one. + */ + oflowh = &((*oflowh)->next); + } + } + } + + /* + * Now populate any spare slots with entries from the list (if any). Also fix up the free slot bitmap + */ + for (i = 0; i < hv_lr_count[cpu]; i++) { + value = get_vgic_entry(i); + + if (value & 0x30000000) { + /* + * This entry already contains a valid interrupt, skip + */ + continue; + } + + /* + * Not a valid interrupt + */ + oflowp = cpuif->overflow; + if (oflowp) { + /* + * If there's a queue, move the top entry out of the queue and into + * * this slot.. + */ + cpuif->overflow = oflowp->next; + + set_vgic_entry(oflowp->value, i); + free_overflowint(oflowp, cpu); + } else { + /* + * .. otherwise mark it as available. + */ + cpuif->freelist |= (1 << i); + } + } + + /* + * If we now don't have any overflow, clear the status bit + */ + if (!(cpuif->overflow)) { + newstatus &= ~0x2; + } + + /* + * Refresh status if needed + */ + if (newstatus != status) { + set_vgic_status(newstatus); + } +} + +/* + * Adds the interrupt specified to the active list of the CPU specified. + * Expected to cope with the state being live on that CPU, or not. + * + * It's only valid to call this on the CPU which the corresponding VCPUIF is live on. + * + * This is O(n) in the number of queued interrupts on the CPUIF in question. + */ +void enqueue_interrupt(unsigned int descr, unsigned int cpu) +{ + unsigned int slot; + struct gic_cpuif *cpuif; + + cpuif = &(cpuifs[cpu]); + + /* + * If there are no free slots, trigger a maintenance + */ + if (!(cpuif->freelist)) { + vgic_refresh(cpu); + } + + if (cpuif->freelist) { + /* + * There is a free slot, use it. + */ + slot = cpuif->freelist; /* Take the free list.. */ + slot &= (-slot); /* .. extract one set bit .. */ + cpuif->freelist &= (~slot); /* .. clear that bit from free list .. */ + slot = bitindex(slot); /* .. and convert to number. */ + + set_vgic_entry(descr, slot); + } else { + /* + * There are no free slots, we are either queuing this one or swapping another out + */ + unsigned int pri = (descr >> 20) & 0xFF; + unsigned int minpri = 0; + unsigned int minslot = 0; + unsigned int i, j; + + if (cpuif->overflow && cpuif->overflow->priority <= pri) { + /* + * There are already queued interrupts with the same or higher priority, just queue this one + */ + set_vgic_queue_entry(cpuif, descr); + return; + } + + /* + * Otherwise find the lowest priority entry.. + */ + for (i = 0; i < hv_lr_count[cpu]; i++) { + j = (get_vgic_entry(i) >> 20) & 0xFF; /* Get the priority for the current thing in this slot */ + if (i == 0 || (j > minpri)) { + minpri = j; + minslot = i; + } + } + + if (minpri > pri) { + /* + * If it's lower priority than this new one we kick it out + */ + set_vgic_queue_entry(cpuif, get_vgic_entry(minslot)); + set_vgic_entry(descr, minslot); + } else { + /* + * Otherwise just queue the new one + */ + set_vgic_queue_entry(cpuif, descr); + } + } +} diff --git a/linaro/arm-virt-bl/big-little/include/arm.h b/linaro/arm-virt-bl/big-little/include/arm.h new file mode 100644 index 0000000..4f33cb5 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/arm.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef ARM_H +#define ARM_H + +/* + * File for ARM Architecture specific defines and constants + */ +#define CP15CTL_M 0x1 +#define CP15CTL_A 0x2 +#define CP15CTL_C 0x4 +#define CP15CTL_W 0x8 +/* + * 4:6 SBO + */ +#define CP15CTL_B 0x80 +#define CP15CTL_S 0x100 +#define CP15CTL_R 0x200 +#define CP15CTL_F 0x400 +#define CP15CTL_Z 0x800 +#define CP15CTL_I 0x1000 +#define CP15CTL_V 0x2000 +#define CP15CTL_RR 0x4000 +#define CP15CTL_L4 0x8000 + +#define FSR_XTABT_L1 0x0C +#define FSR_XTABT_L2 0x0E + +#define FSR_SECTRANS 0x05 +#define FSR_PAGETRANS 0x07 + +/* + * These macros extract the page/section numbers from an address + */ +#define pagenum(x) (((x) >> 12) & 0xFF) +#define secnum(x) ((x) >> 21) /* i$$NEW$$ */ +//#define secnum(x) ((x) >> 20) /* orig */ + +#define MODE_USR 0x10 +#define MODE_FIQ 0x11 +#define MODE_IRQ 0x12 +#define MODE_SVC 0x13 +#define MODE_ABT 0x17 +#define MODE_UND 0x1D +#define MODE_SYS 0x1F +#define MODE_MON 0x16 + +#define getmode(x) ((x) & 0x1F) + +#endif diff --git a/linaro/arm-virt-bl/big-little/include/bakery.h b/linaro/arm-virt-bl/big-little/include/bakery.h new file mode 100644 index 0000000..261acf3 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/bakery.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ +#ifndef _BAKERY_H_ +#define _BAKERY_H_ + +#define MAX_CPUS 4 + +/* + * Bakery structure - declare/allocate one of these for each lock. + * A pointer to this struct is passed to the lock/unlock functions. + */ +typedef struct { + volatile char entering[MAX_CPUS]; + volatile unsigned number[MAX_CPUS]; +} bakery_t; + +/* + * Initialize a bakery - only required if the bakery_t is + * on the stack or heap, as static data is zeroed anyway. + */ +extern void init_bakery_spinlock(bakery_t * bakery); + +/* + * Claim a bakery lock. Function does not return until + * lock has been obtained. + */ +extern void get_bakery_spinlock(unsigned cpuid, bakery_t * bakery); + +/* + * Release a bakery lock. + */ +extern void release_bakery_spinlock(unsigned cpuid, bakery_t * bakery); + +#endif /* _BAKERY_H_ */ diff --git a/linaro/arm-virt-bl/big-little/include/bl.h b/linaro/arm-virt-bl/big-little/include/bl.h new file mode 100644 index 0000000..94e2fb0 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/bl.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __BL_H__ +#define __BL_H__ + +#include "misc.h" + +typedef struct vm_c { + unsigned gp_regs[15]; + unsigned elr_hyp; + unsigned spsr; + unsigned usr_lr; +} vm_context; + +/* + * VM context structure: To hold execution context of the preceding + * mode upon entry into the HYP mode synchronously/asynchronously. + */ +typedef struct vm_s { + unsigned stack[STACK_SIZE]; + vm_context context; +} vm_state; + +extern vm_state guestos_state[MAX_CPUIFS]; +extern void bl_setup(void); +extern void hyp_warm_reset_handler(void); +#endif /* __BL_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/context.h b/linaro/arm-virt-bl/big-little/include/context.h new file mode 100644 index 0000000..11a737c --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/context.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __CONTEXT_H__ +#define __CONTEXT_H__ + +#include "misc.h" + +typedef struct ns_gic_cpu_context { + unsigned int gic_cpu_if_regs[32]; /* GIC context local to the CPU */ + unsigned int gic_dist_if_pvt_regs[32]; /* GIC SGI/PPI context local to the CPU */ +} gic_cpu_context; + +typedef struct fault_regs { + unsigned dfar; + unsigned ifar; + unsigned ifsr; + unsigned dfsr; + unsigned adfsr; + unsigned aifsr; +} cp15_fault_regs; + +typedef struct ns_banked_cp15_context { + unsigned int cp15_misc_regs[2]; /* cp15 miscellaneous registers */ + unsigned int cp15_ctrl_regs[20]; /* cp15 control registers */ + unsigned int cp15_mmu_regs[16]; /* cp15 mmu registers */ + cp15_fault_regs ns_cp15_fault_regs; /* cp15 fault status registers */ +} banked_cp15_context; + +typedef struct gen_tmr_ctx { + unsigned cntfrq; + unsigned long long cntvoff; + unsigned cnthctl; + unsigned cntkctl; + unsigned long long cntp_cval; + unsigned cntp_tval; + unsigned cntp_ctl; + unsigned long long cntv_cval; + unsigned cntv_tval; + unsigned cntv_ctl; + unsigned long long cnthp_cval; + unsigned cnthp_tval; + unsigned cnthp_ctl; +} generic_timer_context; + +typedef struct ns_cpu_context { + unsigned int banked_cpu_regs[32]; /* Banked cpu registers */ + banked_cp15_context banked_cp15_regs; /* Per cpu banked cp15 context */ + unsigned int pmon_regs[32]; /* Generic performance monitor registers */ + generic_timer_context cp15_timer_ctx; /* Global counter registers if accessible in NS world */ + gic_cpu_context gic_cpu_ctx; /* Per cpu GIC distributor and interface context */ + unsigned int endianess; /* Per cpu endianess */ + unsigned int vfp_regs[34]; /* Dummy entry for VFP context. */ + unsigned int debug_regs[32]; /* Dummy entry for Debug context. TODO */ +} cpu_context; + +typedef struct ns_global_context { + unsigned int gic_dist_if_regs[512]; /* GIC distributor context to be saved by the last cpu. */ + unsigned int generic_timer_regs[8]; /* Global timers if the NS world has access to them */ +} global_context; + +/* + * Structure to preserve the OS mmu and stack state for swtich from OS to Switcher + * context handler. + */ +typedef struct os_state { + unsigned sctlr; + unsigned dacr; + unsigned ttbr0; + unsigned nmrr; + unsigned prrr; +} os_state; + +/* + * Top level structure to hold the complete context of a core in a cluster in + * a multi-cluster system + */ +typedef struct core_context { + /* + * Non-secure context save area + */ + cpu_context ns_cpu_ctx; + +} core_context; + +/* + * Top level structure to hold the complete context of a cluster in a multi- + * cluster system + */ +typedef struct cluster_context { + core_context core[MAX_CORES]; + unsigned num_cores; + global_context ns_cluster_ctx; +} cluster_context; + +/* + * Top level structure to hold the complete context of a multi cluster system + */ +typedef struct system_context { + cluster_context cluster; + unsigned num_clusters; + unsigned warm_reset; +} system_context; + +extern void context_save(unsigned, unsigned); +extern void context_restore(unsigned, unsigned); +extern void save_generic_timers(generic_timer_context *); +extern void restore_eagle_timers(generic_timer_context *); +extern void save_hyp_context(unsigned, unsigned); +extern void restore_hyp_context(unsigned, unsigned); +extern void save_vfp(unsigned *); +extern void restore_vfp(unsigned *); +extern void enable_trigger(unsigned); +#endif /* __CONTEXT_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/events.h b/linaro/arm-virt-bl/big-little/include/events.h new file mode 100644 index 0000000..629404f --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/events.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +#include "context.h" +#include "virt_helpers.h" +#include "misc.h" + +/* + * Events for inter/intra-cluster sync + */ +#define MAX_EVENTS 12 + +/* Inter cluster events */ +#define IB_CONTEXT_DONE 0 +#define OB_CONTEXT_DONE 1 + +/* Intra cluster events */ +#define L2_READY 2 +#define L1_DONE 3 +#define CCI_READY 4 +#define GIC_READY 5 +/* Cores have finished performing inbound headstart specific initialisation */ +#define HS_DONE 6 +/* + * Holding pen to ensure that all other context is restored only after all + * cpus have finished initialised local and global HYP mode context. + */ +#define HYP_CONTEXT_DONE 7 +/* + * Holding pen to ensure that all cores have setup the local and global + * virtualisor context before any one of them uses it + */ +#define VIRT_SETUP_DONE 8 +/* + * Event to synchronise creation of HYP mode pagetables + */ +#define VIRT_PGT_DONE 9 + +#define CACHE_GEOM_DONE 10 +#define VID_REGS_DONE 11 + +/* Defines for Secure events */ +#define MAX_SEC_EVENTS 4 +#define SEC_L1_DONE 0 +#define OB_SHUTDOWN 1 +#define FLUSH_L2 2 +#define SETUP_RST 3 + +extern void set_event(unsigned, unsigned); +extern void set_events(unsigned); +extern unsigned get_event(unsigned, unsigned); +extern void reset_event(unsigned, unsigned); +extern void wait_for_event(unsigned, unsigned); +extern void wait_for_events(unsigned); + +#endif /* __EVENTS_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/gic_registers.h b/linaro/arm-virt-bl/big-little/include/gic_registers.h new file mode 100644 index 0000000..70f75e9 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/gic_registers.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __GIC_REGISTERS_H__ +#define __GIC_REGISTERS_H__ + +#include "hyp_vmmap.h" + +#define MAX_INTS 256 + +/* Distributor interface registers */ +#define GICD_CTL 0x0 +#define GICD_CTR 0x4 +#define GICD_SEC 0x80 +#define GICD_ENABLESET 0x100 +#define GICD_ENABLECLEAR 0x180 +#define GICD_PENDINGSET 0x200 +#define GICD_PENDINGCLEAR 0x280 +#define GICD_ACTIVESET 0x300 +#define GICD_ACTIVECLEAR 0x380 +#define GICD_PRI 0x400 +#define GICD_CPUS 0x800 +#define GICD_CONFIG 0xC00 +#define GICD_SW 0xF00 +#define GICD_CPENDSGIR 0xF10 +#define GICD_SPENDSGIR 0xF20 + +/* Physical CPU Interface registers */ +#define GICC_CTL 0x0 +#define GICC_PRIMASK 0x4 +#define GICC_BP 0x8 +#define GICC_INTACK 0xC +#define GICC_EOI 0x10 +#define GICC_RUNNINGPRI 0x14 +#define GICC_HIGHESTPEND 0x18 +#define GICC_DEACTIVATE 0x1000 +#define GICC_PRIODROP GICC_EOI + +/* HYP view virtual CPU Interface registers */ +#define GICH_CTL 0x0 +#define GICH_VTR 0x4 +#define GICH_ELRSR0 0x30 +#define GICH_ELRSR1 0x34 +#define GICH_APR0 0xF0 +#define GICH_LR_BASE 0x100 + +/* GuestOS view virtual CPU Interface registers */ +#define GICV_CTL 0x0 +#define GICV_PRIMASK 0x4 +#define GICV_BP 0x8 +#define GICV_INTACK 0xC +#define GICV_EOI 0x10 +#define GICV_RUNNINGPRI 0x14 +#define GICV_HIGHESTPEND 0x18 +#define GICV_DEACTIVATE 0x1000 + +#define VGICH_HCR_EN 0x1 +#define VGICV_NS_EN 0x2 + +#define GS_ENABLED 0x01 +#define GS_EDGE 0x02 +#define GIC_INTS 128 +#define GIC_PRIMASK 0xF8 /* 32 levels only */ +#define GIC_DISTENABLE 0x1 +#define GIC_CPUIFENABLE 0x2 + +#define VGIC_PRI 0x200 +#define VGIC_LIST 0x100 +#define VGIC_CONTROL 0x0 +/* + * TODO: + * Current mechanism to find free slots uses unsigned ints + * and is thus restricted to storing just 32 free slots. + */ +#define VGIC_LISTENTRIES 64 + +#define VGIC_ENTRY_HW 0x80000000 +#define VGIC_ENTRY_ACTIVE 0x20000000 +#define VGIC_ENTRY_ACTIVE_PENDING 0x30000000 +#define VGIC_ENTRY_PENDING 0x10000000 + +#endif /* __GIC_REGISTERS_H__ */ + diff --git a/linaro/arm-virt-bl/big-little/include/handler.h b/linaro/arm-virt-bl/big-little/include/handler.h new file mode 100644 index 0000000..7246b9e --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/handler.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __HANDLER_H__ +#define __HANDLER_H__ + +#include "virt_helpers.h" +#include "context.h" +#include "misc.h" + +extern system_context switcher_context; + +#endif /* __HANDLER_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/hvc.h b/linaro/arm-virt-bl/big-little/include/hvc.h new file mode 100644 index 0000000..d0df974 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/hvc.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __HVC_H__ +#define __HVC_H__ + +#include "traps.h" +#include "handler.h" +#include "context.h" +#include "int_master.h" + +/* Opcode to trigger a switch from the OS */ +#define SWITCHER_ENTRY 0 +/* Opcode to return to the trigger handler after a switch (NS SVC -> HYP) */ +#define SWITCHER_EXIT 1 +/* Opcode to save HYP mode context */ +#define HYP_SAVE 2 +/* Opcode to restore HYP mode context */ +#define HYP_RESTORE 3 +/* Opcode to test vGIC active bit reg */ +#define VGIC_TEST 4 + +vm_context *hvc_handler(unsigned, vm_context *); + +#endif /* __HVC_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/hyp_types.h b/linaro/arm-virt-bl/big-little/include/hyp_types.h new file mode 100755 index 0000000..441320b --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/hyp_types.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __HYP_TYPES_H__ +#define __HYP_TYPES_H__ + +typedef signed int int32_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#define PRIVATE static +#define PUBLIC + +#endif /* __HYP_TYPES_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/hyp_vmmap.h b/linaro/arm-virt-bl/big-little/include/hyp_vmmap.h new file mode 100644 index 0000000..4da98bb --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/hyp_vmmap.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __HYP_VMMAP_H__ +#define __HYP_VMMAP_H__ + +#include "hyp_types.h" +#include "misc.h" + +/* ---------------------------------------------------------------------------- + * d e f i n e s + * --------------------------------------------------------------------------*/ + +#define GIC_ID_PHY_BASE 0x2C001000 /* Physical Distributor */ +#define GIC_IC_PHY_BASE 0x2C002000 /* Physical CPU interface */ + +#define VGIC_HV_PHY_BASE 0x2C004000 /* Hypervisor's VIew */ +#define VGIC_VM_PHY_BASE 0x2C006000 /* Virtual Machine view */ + +#define UART0_PHY_BASE 0x1C090000 +#define UART1_PHY_BASE 0x1C0A0000 + +#endif /* __HYP_VMMAP_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/int_master.h b/linaro/arm-virt-bl/big-little/include/int_master.h new file mode 100644 index 0000000..4224fde --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/int_master.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/* + * Master interrupt controller driver - talks to real IC and dispatches + * * interrupts to slave ICs or monitor drivers as appropriate + */ + +#ifndef _INT_MASTER_H_ +#define _INT_MASTER_H_ + +#include "bl.h" + +#define INT_ENABLED 0x1 /* Interrupt is enabled, something to pass it on to */ +#define INT_ACTIVE 0x2 /* Interrupt is currently actually disabled at the real controller because it is active */ + +#define INT_TRIGGER 0 +#define INT_ENABLE 1 +#define INT_DISABLE 2 +#define INT_GETRAW 3 +#define INT_UNTRIGGER 4 + +vm_context *handle_interrupt(vm_context * context); +int gic_masterhandler(void *ptr, unsigned int num, unsigned int op); +void gic_masterinit(void); +void gic_deactivate_int(unsigned int num); +void gic_setup_secure(unsigned, unsigned); +void enable_2ndstage(void); +void setup_hcr(void); +void test_vgic(void); +#endif diff --git a/linaro/arm-virt-bl/big-little/include/misc.h b/linaro/arm-virt-bl/big-little/include/misc.h new file mode 100644 index 0000000..103f94c --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/misc.h @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef MISC_H +#define MISC_H + +#include <stdio.h> +#include <string.h> + +#define NUM_CPUS 8 + +#define inline __inline + +#define A7 0xC07 +#define A15 0xC0F +#define PART_NO(x) ((x >> 4) & 0xfff) +#define REVISION(x) (x & 0xf) +#define VARIANT(x) ((x >> 20) & 0xf) + +#define MAX_CLUSTERS 2 +#define MAX_CORES 8 +#define MAX_CPUIFS 8 +#define STACK_SIZE 96 + +#define TRUE 1 +#define FALSE 0 +#define CONTEXT_SAVE 0 +#define CONTEXT_RESTORE 1 +#define SYNC_SWITCHOVER 1 +#define READ_MPIDR 2 + +/************************************************* + * Virtual GIC defines + *************************************************/ + +/* Bit definitions in the secure GICC_CTLR */ +#define EOI_MODE_NS (1 << 10) +#define EOI_MODE_S (1 << 9) + +/* Bit definitions in the Active list registers */ +#define HW_IRQ ((unsigned) 1 << 31) +#define NS_IRQ (1 << 30) +#define STATE(x) ((x & 0x3) << 28) +#define PENDING 0x1 + +/* Misc */ +#define INTACK_CPUID_MASK 0x7 + +/************************************************* + * Bit definitions in the HYP configuration + * register. + *************************************************/ +#define HCR_AMO (1 << 5) +#define HCR_IMO (1 << 4) +#define HCR_FMO (1 << 3) +#define HCR_VM (1 << 0) +#define HCR_TID2 (1 << 17) +#define HCR_TSW (1 << 22) + +/************************************************* + * TEX remap defines for first level translations + *************************************************/ +/* PRRR fields for memory attributes */ +#define TR0(x) ((x) << 0) // SO +#define TR1(x) ((x) << 2) // DV +#define TR4(x) ((x) << 8) // NC +#define TR7(x) ((x) << 14) // C +/* PRRR fields for shareability attributes */ +#define NOS0(x) ((x) << 24) +#define NOS1(x) ((x) << 25) +#define NOS4(x) ((x) << 28) +#define NOS7(x) ((x) << 31) +#define NS1(x) ((x) << 19) +#define DS1(x) ((x) << 17) + +/* Memory attributes */ +#define NORMAL_MEM 0x2 +#define DEVICE_MEM 0x1 +#define SO_MEM 0x0 +#define INNER_SH 0x1 +#define SHAREABLE 0x1 + +/* NMRR fields */ +#define IR7(x) ((x) << 14) // Inner Cache attributes for TEX,C,B = 1,1,1 +#define IR4(x) ((x) << 8) // Inner Cache attributes for TEX,C,B = 1,0,0 +#define OR7(x) ((x) << 30) // Outer Cache attributes for TEX,C,B = 1,1,1 +#define OR4(x) ((x) << 24) // Outer Cache attributes for TEX,C,B = 1,0,0 + +/* Normal memory attributes */ +#define NMRR_NC 0x0 +#define NMRR_WBWA 0x1 + +/************************************************ + * Page table walk attributes in TTBR0/1 + ************************************************/ +#define NOS(x) ((x) << 5) +#define RGN(x) ((x) << 3) +#define SH(x) ((x) << 1) +#define IRGN(x) ((((x) & 0x2) << 5) | ((x) & 0x1)) + +#define TTBR_SH 0x1 +#define TTBR_WBWA 0x1 + +/* + * Bit definitions of Level 2 translation + * table entries. + */ + +/* Mapping type[1:0] */ +#define INVALID_MAPPING 0x0 +#define BLOCK_MAPPING 0x1 +#define TABLE_MAPPING 0x3 + +/* + * Bit definitions of Level 3 translation + * table entries. + */ + +/* Mapping type[1:0] */ +#define VALID_MAPPING 0x3 + +/* Lower block attributes[11:2] */ +#define NON_GLOBAL (1 << 11) +#define ACCESS_FLAG (1 << 10) +#define SHAREABILITY(x) ((x & 0x3) << 8) +#define ACCESS_PERM(x) ((x & 0x3) << 6) +#define MEM_ATTR(x) ((x & 0xf) << 2) + +/* Upper block attributes[63:52]. Defined as the upper word */ +#define XN (1 << 22) +#define PXN (1 << 21) + +/* + * Cache levels. + */ +#define L1 0x0 +#define L2 0x1 + +/* + * Cache maintenance op types. + */ +#define INV 0x0 +#define CLN 0x1 +#define CLN_INV 0x2 + +/* + * Cache line length in bytes + */ +#define CACHE_LINE_SZ 64 + +/* + * CCI defines + */ +#define CCI_BASE 0x2c090000 +#define CCI_PERF_CNT(x) CCI_BASE + ((0xa + x ) << 12) +#define CCI_CYCLE_CNT CCI_BASE + 0x9000 +#define A15_SL_IFACE_BASE CCI_BASE + 0x4000 +#define A7_SL_IFACE_BASE CCI_BASE + 0x5000 + +/* PMU Counter Registers */ +#define EVNT_SEL_REG 0x0 +#define CNT_REG 0x4 +#define CNT_CTLR_REG 0x8 +#define OVRFLW_STAT_REG 0xc + +/* Control interface register offsets */ +#define CTLR_OVERRIDE_REG 0x0 +#define SPEC_CTLR_REG 0x4 +#define SECURE_ACCESS_REG 0x8 +#define STATUS_REG 0xc +#define IMPRECISE_ERR_REG 0x10 +#define PERF_MON_CTRL_REG 0x100 + +/* Slave interface register */ +#define SNOOP_CTLR_REG 0x0 + +/* PMCR bits */ +#define PMCR_CEN (1 << 0) +#define PMCR_RST (1 << 1) +#define PMCR_CCR (1 << 2) +#define PMCR_CCD (1 << 3) +#define reset_cci_pmu() write32(CCI_BASE + PERF_MON_CTRL_REG, PMCR_RST | PMCR_CCR) +#define enable_cci_pmu() write32(CCI_BASE + PERF_MON_CTRL_REG, PMCR_CEN) +#define enable_cci_cntr(x) write32(CCI_PERF_CNT(x) + CNT_CTLR_REG, 0x1) +#define disable_cci_cntr(x) write32(CCI_PERF_CNT(x) + CNT_CTLR_REG, 0x0) +#define select_cci_event(x, y) write32(CCI_PERF_CNT(x) + EVNT_SEL_REG, y) +#define read_cci_cntr(x) read32(CCI_PERF_CNT(x) + CNT_REG) +/* + * TODO: + * Move platform specific definitions to the right places + */ +#define KFSCB_BASE 0x60000000 + +#define RST_HOLD0 0x0 +#define RST_HOLD1 0x4 +#define SYS_SWRESET 0x8 +#define RST_STAT0 0xc +#define RST_STAT1 0x10 +#define EAG_CFG_R 0x20 +#define EAG_CFG_W 0x24 +#define KFC_CFG_R 0x28 +#define KFC_CFG_W 0x2c +#define KFS_CFG_R 0x30 +#define RST_HANDLER0 0x40 +#define RST_HANDLER1 0x48 +#define RST_HANDLER2 0x50 +#define RST_HANDLER3 0x58 +#define RST_HANDLER4 0x60 +#define RST_HANDLER5 0x68 +#define RST_HANDLER6 0x70 +#define RST_HANDLER7 0x78 +#define KFS_ID 0xffc + +/* + * KFSCB Tube offsets. Models only + */ +#define KFS_TUBE0 0x400 +#define KFS_TUBE1 0x420 +#define KFS_TUBE2 0x440 +#define KFS_TUBE3 0x460 + +/* + * Map the 4 tubes to the Secure + * & non-secure worlds + */ +#define SEC_TUBE0 KFS_TUBE0 +#define SEC_TUBE1 KFS_TUBE1 +#define NS_TUBE0 KFS_TUBE2 +#define NS_TUBE1 KFS_TUBE3 + +/* KFSCB Tube register offsets. */ +#define TUBE_CHAR 0x00 +#define TUBE_DATA0 0x08 +#define TUBE_DATA1 0x10 +#define TUBE_DATA2 0x18 + +#define CLUSTER_CPU_COUNT(x) (((read32(KFSCB_BASE + KFS_CFG_R) >> 16) >> (x << 2)) & 0xf) +#define DC_SYSTYPE ((read32(KFSCB_BASE + KFS_ID) >> 16) & 0xf) +#define asym_clusters() (((read32(KFSCB_BASE + KFS_CFG_R) >> 16) & 0xf) == \ + ((read32(KFSCB_BASE + KFS_CFG_R) >> 20) & 0xf)) + +/* + * "Always on" uses cpuids that span across clusters e.g. + * 0-7 for an MPx4+MPx4 system. + */ +#define abs_cpuid(cpu_id, cluster_id) (cluster_id ? cpu_id + CLUSTER_CPU_COUNT(!cluster_id) : cpu_id) +#define CLUSTER_LVL_RST (1 << 0) +#define RST_BIT(x) (1 << 4) << x +#define RST_LVL(x, y) ((x & 0x3) << 8) << (y << 1) +#define CORE_RESET 0x0 +#define CORE_PORESET 0x1 +#define CLUSTER_RESET 0x2 +#define EAGLE_CORES(x) ((x & 0xf) << 16) +#define KFC_CORES(x) ((x & 0xf) << 20) +#define SW_RESET (1 << 2) + +#define ENTER_RESET 0x1 +#define EXIT_RESET 0x2 +#define CASCADE_RESET 0x4 + +#define A15_A15 0x0 +#define A7_A15 0x1 +#define A15_A7 0x2 + +#define EAGLE 0x0 +#define KFC 0x1 + +/* Control register bits */ +#define CR_M (1<<0) /* MMU enabled */ +#define CR_A (1<<1) /* Align fault enable */ +#define CR_C (1<<2) /* Data cache */ +#define CR_W (1<<3) /* Write buffer */ +#define CR_Z (1<<11) /* Branch prediction */ +#define CR_I (1<<12) /* Instruction cache */ +#define CR_V (1<<13) /* Vectors */ +#define CR_XP (1<<23) /* Extended page tables */ +#define CR_TRE (1<<28) /* TEX Remap */ + +/* + * Processor modes + */ +#define MON_MODE 0x16 +#define SVC_MODE 0x13 +#define HYP_MODE 0x1A +#define USR_MODE 0x10 + +/* Timer Bits */ +#define HYP_TIMER_MULT 0xa /* 12Mhz * 10 i.e. interrupt every 10ms. Linux uses 12MHz * 10 */ +#define LCL_TIMER_FREQ 0x7f /* Every 128th timer acts as a trigger */ +#define HYP_TIMER_IRQ 0x1a +#define LCL_TIMER_IRQ 0x1e +#define TIMER_ENABLE 0x1 +#define TIMER_DISABLE 0x0 +#define TIMER_MASK_IRQ 0x2 +#define TIMER_IRQ_STAT 0x4 + +/* Trap ids provided in the HSR */ +#define NUM_TRAPS 0x27 +#define TRAP_UNKNOWN 0x0 +#define TRAP_WFE_WFI 0x1 +#define TRAP_CP15_32 0x3 +#define TRAP_CP15_64 0x4 +#define TRAP_CP14_32 0x5 +#define TRAP_CP14_LDC_STC 0x6 +#define TRAP_HCPTR_1 0x7 +#define TRAP_HCPTR_2 0x8 +#define TRAP_JAZELLE 0x9 +#define TRAP_BXJ 0xA +#define TRAP_CP14_64 0xC +#define TRAP_HYP_SVC 0x11 +#define TRAP_HVC 0x12 +#define TRAP_HYP_SMC 0x13 +#define TRAP_IABORT 0x20 +#define TRAP_HYP_IABORT 0x21 +#define TRAP_DABORT 0x24 +#define TRAP_HYP_DABORT 0x25 + +/* + * Defines for making SMC calls + */ +#define SMC_SEC_INIT 0x0 +#define SMC_SEC_SAVE 0x1 +#define SMC_SEC_SHUTDOWN 0x2 + +#define MAX_CACHE_LEVELS 0x8 +#define CRN_C0 0x0 +#define CRN_C7 0x7 +#define CRN_C9 0x9 +#define CRN_C15 0xf + +/* + * Opcode2 definitions in the corresponding cp15 instruction + */ +#define MIDR 0x0 +#define CTR 0x1 +#define TCMTR 0x2 +#define TLBTR 0x3 +#define MPIDR 0x5 +#define CCSIDR 0x0 +#define CLIDR 0x1 +#define AIDR 0x4 +#define CSSELR 0x0 +#define DCISW 0x2 +#define DCCSW 0x2 +#define DCCISW 0x2 + +#define ID_PFR0 0x0 +#define ID_PFR1 0x1 +#define ID_DFR0 0x2 +#define ID_AFR0 0x3 +#define ID_MMFR0 0x4 +#define ID_MMFR1 0x5 +#define ID_MMFR2 0x6 +#define ID_MMFR3 0x7 +#define ID_ISAR0 0x0 +#define ID_ISAR1 0x1 +#define ID_ISAR2 0x2 +#define ID_ISAR3 0x3 +#define ID_ISAR4 0x4 +#define ID_ISAR5 0x5 + +extern void enable_cci_snoops(unsigned); +extern void disable_cci_snoops(unsigned); +extern void switch_cluster(unsigned); +extern unsigned long long *get_powerdown_stack(unsigned); +extern void spin_lock(unsigned int *); +extern void spin_unlock(unsigned int *); +extern void panic(void); +extern unsigned get_inbound(void); +extern unsigned reset_status(unsigned, unsigned, unsigned); +extern unsigned map_cpuif(unsigned, unsigned); +extern unsigned get_cpuif(unsigned, unsigned); +extern unsigned remap_cpuif(unsigned *); +extern unsigned get_cpuif_mask(unsigned); +extern unsigned get_cpu_mask(unsigned); + +#ifdef BUILD_RVCT +extern unsigned BL_DV_PAGE$$Base __asm(".data.BL_DV_PAGE$$Base"); +extern unsigned BL_SEC_DV_PAGE$$Base __asm(".data.BL_SEC_DV_PAGE$$Base"); +#define BL_DV_PAGE_base (&BL_DV_PAGE$$Base) +#define BL_SEC_DV_PAGE_base (&BL_SEC_DV_PAGE$$Base) +#else +extern unsigned __BL_DV_PAGE_base; +extern unsigned __BL_SEC_DV_PAGE_base; +#define BL_DV_PAGE_base (&__BL_DV_PAGE_base) +#define BL_SEC_DV_PAGE_base (&__BL_SEC_DV_PAGE_base) +#endif + +#define bitindex(x) (31-__builtin_clz(x)) +#define find_first_cpu() 0 +#define write32(addr, val) (*(volatile unsigned int *)(addr) = (val)) +#define read32(addr) (*(volatile unsigned int *)(addr)) +#endif diff --git a/linaro/arm-virt-bl/big-little/include/traps.h b/linaro/arm-virt-bl/big-little/include/traps.h new file mode 100755 index 0000000..2d36210 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/traps.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __TRAPS_H__ +#define __TRAPS_H__ + +#include "misc.h" + +/* + * Ignoring the condition field [24:20] for now. + */ +#define HSR_ISS_OP2 (0x7 << 17) +#define HSR_ISS_OP1 (0x7 << 14) +#define HSR_ISS_CRN (0xf << 10) +#define HSR_ISS_CRM (0xf << 1) +#define HSR_ISS_RW (0x1 << 0) + +/* + * Macro to convert the cp15 instruction info in the HSR + * into a unique integer. The integer is used to identify + * the handler for that instruction. Format of the integer + * is [Op2:Op1:CRn:CRm:RW] + */ +#define GET_CP15_OP(x) ((x & HSR_ISS_OP2) >> 5) | ((x & HSR_ISS_OP1) >> 5) | ((x & HSR_ISS_CRN) >> 5) |\ + (x & HSR_ISS_CRM) | (x & HSR_ISS_RW) + +#define MAKE_CP15_OP(op2, op1, crn, crm, rw) ((op2 << 12) | (op1 << 9) | (crn << 5) | (crm << 1) | rw) + +#define READ_MIDR MAKE_CP15_OP(0x0, 0x0, 0x0, 0x0, 0x1) +#define READ_MPIDR MAKE_CP15_OP(0x5, 0x0, 0x0, 0x0, 0x1) +#define READ_AUXCTRL MAKE_CP15_OP(0x1, 0x0, 0x1, 0x0, 0x1) + +#define WRITE_MIDR MAKE_CP15_OP(0x0, 0x0, 0x0, 0x0, 0x0) +#define WRITE_MPIDR MAKE_CP15_OP(0x5, 0x0, 0x0, 0x0, 0x0) +#define WRITE_AUXCTRL MAKE_CP15_OP(0x1, 0x0, 0x1, 0x0, 0x0) + +/* + * Indices into arrays of registers to whom acceses will be + * trapped. + */ +#define AUXCTRL 0x0 +#define MIDR 0x1 +#define MPIDR 0x2 +#define MAX_REGS 0x10 + +/* + * Indices into array of handlers of the registered traps. + * Numbers correspond to the Exception Class field of HSR. + */ +#define UNKNOWN 0x0 +#define MRC_MCR_CP15 0x3 +#define MAX_TRAPS 0x25 + +/* + * Structure to hold the registered traps + */ +typedef struct tlist { + unsigned int hcr; + unsigned int hstr; +} trap_list; + +/* + * Structure to hold registers to whom accesses will be trapped + */ +typedef struct rlist { + unsigned int reg[MAX_REGS]; +} reg_list; + +/* + * Structure to hold platform defined trap handlers + */ +typedef struct hlist { + int (*handle[MAX_TRAPS]) (unsigned int hsr, unsigned int *operand); +} handler_list; + +extern trap_list cp15_trap_list[NUM_CPUS]; +extern reg_list cp15_reg_list[NUM_CPUS]; +extern handler_list plat_handler_list[NUM_CPUS]; + +#if !DEBUG +#define printf(...) +#endif +#endif /* __TRAPS_H__ */ diff --git a/linaro/arm-virt-bl/big-little/include/vgiclib.h b/linaro/arm-virt-bl/big-little/include/vgiclib.h new file mode 100644 index 0000000..0d5f461 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/vgiclib.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef VGICLIB_H +#define VGICLIB_H + +#include "gic_registers.h" + +struct overflowint { + /* This is encoded in the value, but speed optimise by splitting out */ + unsigned int priority; + unsigned int value; + struct overflowint *next; +}; + +struct gic_cpuif { + unsigned int status; + unsigned int activepris; /* Copies of the state from the VGIC itself */ + unsigned int elrsr[2]; /* Copies of Empty list register status registers */ + unsigned int ints[VGIC_LISTENTRIES]; + + struct overflowint *overflow; /* List of overflowed interrupts */ + unsigned int freelist; /* Bitmask of which list entries are in use */ +}; + +void vgic_init(void); +void vgic_savestate(unsigned int cpu); +void vgic_loadstate(unsigned int cpu); +void vgic_refresh(unsigned int cpu); +void enqueue_interrupt(unsigned int descr, unsigned int cpu); + +#endif /* VGICLIB_H */ diff --git a/linaro/arm-virt-bl/big-little/include/virt_helpers.h b/linaro/arm-virt-bl/big-little/include/virt_helpers.h new file mode 100644 index 0000000..7ec73c9 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/include/virt_helpers.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef _VIRT_HELPERS_H_ +#define _VIRT_HELPERS_H_ + +#include "bakery.h" +#include "helpers.h" +#include "misc.h" + +/******************************************************* + * Export prototypes of the functions which will be used + * to save/restore the Non-secure context. + *******************************************************/ + +/* + * Misc functions + */ +extern unsigned read_sp(unsigned); +extern unsigned read_lr(unsigned); +extern unsigned num_secondaries(void); +extern unsigned *get_sp(unsigned, unsigned); + +extern void virt_dead(void); +extern void smc(unsigned, unsigned); +extern void dcisw(unsigned); +extern void dccsw(unsigned); +extern void dccisw(unsigned); +extern void write_sp(unsigned, unsigned); +extern void write_lr(unsigned, unsigned); + +/* + * V7 functions + */ +extern void disable_clean_inv_l1_dcache_v7(void); +extern void cache_maint_op(unsigned, unsigned); +extern unsigned get_loc(void); +extern void disable_coherency(void); +extern void disable_dcache(void); +extern void enable_coherency(void); +extern void enable_dcache(void); +extern void flush_to_loc(void); +extern void inv_tlb_all(void); +extern void inv_bpred_all(void); +extern void inv_tlb_mva(unsigned *); +extern void inv_icache_all(void); +extern void inv_icache_mva_pou(unsigned *); +extern void inv_dcache_mva_poc(unsigned *); +extern void cln_dcache_mva_poc(unsigned *); +extern void cln_dcache_mva_pou(unsigned *); + +/* + * GIC functions + */ +extern void save_gic_interface(unsigned int *pointer, + unsigned gic_interface_address); +extern int save_gic_distributor_private(unsigned int *pointer, + unsigned gic_distributor_address); +extern int save_gic_distributor_shared(unsigned int *pointer, + unsigned gic_distributor_address); +extern void restore_gic_interface(unsigned int *pointer, + unsigned gic_interface_address); +extern void restore_gic_distributor_private(unsigned int *pointer, + unsigned gic_distributor_address); +extern void restore_gic_distributor_shared(unsigned int *pointer, + unsigned gic_distributor_address); +extern void hyp_save(unsigned, unsigned); + +/* + * Tube functions + */ +#if TUBE +extern void write_trace(bakery_t *, unsigned, char *, unsigned long long, + unsigned long long, unsigned long long); +#else +#define write_trace(...) +#endif + +#endif /* _VIRT_HELPERS_H_ */ diff --git a/linaro/arm-virt-bl/big-little/lib/bakery.c b/linaro/arm-virt-bl/big-little/lib/bakery.c new file mode 100644 index 0000000..068ac0d --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/bakery.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/* + * bakery.c: Lamport's Bakery algorithm for spinlock handling + * + * Note that the algorithm requires the stack and the bakery struct + * to be in Strongly-Ordered memory. + */ + +#include "misc.h" +#include <string.h> +#include "bakery.h" + +void init_bakery_spinlock(bakery_t * bakery) +{ + memset(bakery, 0, sizeof(bakery_t)); +} + +void get_bakery_spinlock(unsigned cpuid, bakery_t * bakery) +{ + unsigned i, max = 0, my_full_number, his_full_number; + + /* Get a ticket */ + bakery->entering[cpuid] = TRUE; + for (i = 0; i < MAX_CPUS; ++i) { + if (bakery->number[i] > max) { + max = bakery->number[i]; + } + } + ++max; + bakery->number[cpuid] = max; + bakery->entering[cpuid] = FALSE; + + /* Wait for our turn */ + my_full_number = (max << 8) + cpuid; + for (i = 0; i < MAX_CPUS; ++i) { + while (bakery->entering[i]) ; /* Wait */ + do { + his_full_number = bakery->number[i]; + if (his_full_number) { + his_full_number = (his_full_number << 8) + i; + } + } + while (his_full_number && (his_full_number < my_full_number)); + } +} + +void release_bakery_spinlock(unsigned cpuid, bakery_t * bakery) +{ + bakery->number[cpuid] = 0; +} diff --git a/linaro/arm-virt-bl/big-little/lib/idiv0.c b/linaro/arm-virt-bl/big-little/lib/idiv0.c new file mode 100644 index 0000000..36d21f3 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/idiv0.c @@ -0,0 +1,6 @@ +/* Trivial divide-by-zero handler */ + +int __aeabi_idiv0(void) +{ + return 0; +} diff --git a/linaro/arm-virt-bl/big-little/lib/ldiv0.c b/linaro/arm-virt-bl/big-little/lib/ldiv0.c new file mode 100644 index 0000000..46e4840 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/ldiv0.c @@ -0,0 +1,6 @@ +/* Trivial divide-by-zero handler */ + +long long __aeabi_ldiv0(void) +{ + return 0; +} diff --git a/linaro/arm-virt-bl/big-little/lib/printf.c b/linaro/arm-virt-bl/big-little/lib/printf.c new file mode 100644 index 0000000..45b1b2c --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/printf.c @@ -0,0 +1,27 @@ +/* + * printf.c + */ + +#include <stdio.h> +#include <stdarg.h> + +#define BUFFER_SIZE 256 + +int printf(const char *format, ...) +{ + char buffer[BUFFER_SIZE]; + va_list ap; + int rv; + + va_start(ap, format); + rv = vsnprintf(buffer, BUFFER_SIZE, format, ap); + va_end(ap); + + if (rv < 0) + return rv; + + if (rv > BUFFER_SIZE - 1) + rv = BUFFER_SIZE - 1; + + return _write(buffer, rv); +} diff --git a/linaro/arm-virt-bl/big-little/lib/puts.c b/linaro/arm-virt-bl/big-little/lib/puts.c new file mode 100644 index 0000000..a14ebe7 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/puts.c @@ -0,0 +1,10 @@ +#include <stdio.h> + +extern void output_string(const char *string); + +int puts(const char *s) +{ + output_string(s); + output_string("\n"); + return 0; +} diff --git a/linaro/arm-virt-bl/big-little/lib/raise.c b/linaro/arm-virt-bl/big-little/lib/raise.c new file mode 100644 index 0000000..5877f93 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/raise.c @@ -0,0 +1,10 @@ +/* + * Trivial implementation of raise() which just hangs the platform. + * This is needed so that libgcc division helpers can link, + * even though it may not be used if the divide-by-zero handler is overridden + */ + +void raise(void) +{ + while (1); +} diff --git a/linaro/arm-virt-bl/big-little/lib/string.c b/linaro/arm-virt-bl/big-little/lib/string.c new file mode 100644 index 0000000..714d03d --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/string.c @@ -0,0 +1,29 @@ +#include <string.h> + +void *memcpy(void *__dest, __const void *__src, size_t __n) +{ + int i = 0; + unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src; + + while (__n--) + *d++ = *s++; + + return __dest; +} + +size_t strlen(const char *s) +{ + const char *sc = s; + + while (*sc != '\0') + sc++; + return sc - s; +} + +void *memset(void *s, int c, size_t count) +{ + char *xs = s; + while (count--) + *xs++ = c; + return s; +} diff --git a/linaro/arm-virt-bl/big-little/lib/tube.c b/linaro/arm-virt-bl/big-little/lib/tube.c new file mode 100755 index 0000000..8ab693e --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/tube.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "misc.h" +#include "virt_helpers.h" +#include "bakery.h" + +#if TUBE +void write_trace(bakery_t * lock, + unsigned tube_offset, + char *msg, + unsigned long long data0, + unsigned long long data1, unsigned long long data2) +{ + unsigned long long volatile *data = 0x0; + unsigned cpu_id = read_cpuid(); + unsigned cluster_id = read_clusterid(); + + get_bakery_spinlock(cpu_id, lock); + + /* Write the 3 double words that the tube supports */ + data = + (unsigned long long volatile *)(KFSCB_BASE + tube_offset + + TUBE_DATA0); + *data++ = data0; + *data++ = data1; + *data = data2; + + /* Write the string to the tube. */ + while (*msg != '\0') { + write32(KFSCB_BASE + tube_offset + TUBE_CHAR, (unsigned)*msg); + msg++; + } + write32(KFSCB_BASE + tube_offset + TUBE_CHAR, *msg); + + release_bakery_spinlock(cpu_id, lock); + + return; +} +#endif diff --git a/linaro/arm-virt-bl/big-little/lib/uart.c b/linaro/arm-virt-bl/big-little/lib/uart.c new file mode 100644 index 0000000..5265592 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/uart.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/* + * uart.c - boot code to output characters on a PL011 uart + * Not SMP-safe, so make sure you only call these functions + * from one CPU at a time. + * Call config_uart first. + */ + +#include "misc.h" +#include "hyp_vmmap.h" +#include "virt_helpers.h" + +//* PL011 Registers Offsets from UART Base adress */ +#define PL011_DR 0x0 +#define PL011_RSR 0x4 +#define PL011_ECR 0x4 +#define PL011_FR 0x18 +#define PL011_ILPR 0x20 +#define PL011_IBRD 0x24 +#define PL011_FBRD 0x28 +#define PL011_LCRH 0x2C +#define PL011_CR 0x30 +#define PL011_IFLS 0x34 +#define PL011_IMSC 0x38 +#define PL011_RIS 0x3C +#define PL011_MIS 0x40 +#define PL011_ICR 0x44 +#define PL011_DMACR 0x48 + +#define PL011_TXFE 0x80 +#define PL011_TXFF 0x20 + +typedef unsigned size_t; +typedef int ssize_t; + +static unsigned uart_base = 0; + +#define write32(addr, val) (*(volatile unsigned int *)(addr) = (val)) +#define read32(addr) (*(volatile unsigned int *)(addr)) + +void config_uart(void) +{ + uart_base = UART1_PHY_BASE; + write32(uart_base + PL011_CR, 0); + write32(uart_base + PL011_FBRD, 0x01); + write32(uart_base + PL011_IBRD, 0x27); + write32(uart_base + PL011_LCRH, 0x70); + write32(uart_base + PL011_CR, 0xf01); /* TXE|RXE|En|DTR|CTS */ +} + +void drain_uart_fifo(void) +{ + while (!(read32(uart_base + PL011_FR) & PL011_TXFE)) { + /* Do nothing */ + } +} + +static __inline void wait_for_space(void) +{ + while ((read32(uart_base + PL011_FR) & PL011_TXFF)) { + /* Do nothing */ + } +} + +void output_char(int c) +{ + if (c == '\n') { + wait_for_space(); + write32(uart_base + PL011_DR, '\r'); + } + wait_for_space(); + write32(uart_base + PL011_DR, c); +} + +void output_string(const char *string) +{ + int i; + + for (i = 0; string[i]; ++i) { + output_char(string[i]); + } +} + +void hexword(unsigned value) +{ + printf(" 0x%8.8x", value); + drain_uart_fifo(); +} + +ssize_t _write(const void *buf, size_t count) +{ + const unsigned char *b = buf; + int c = count; + + while (c--) + output_char(*b++); + + return count; +} diff --git a/linaro/arm-virt-bl/big-little/lib/unwind-personality.c b/linaro/arm-virt-bl/big-little/lib/unwind-personality.c new file mode 100644 index 0000000..8296a0e --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/unwind-personality.c @@ -0,0 +1,3 @@ +/* Dummy unwind personality routine, needed by ligbcc */ + +void __aeabi_unwind_cpp_pr0(void) { } diff --git a/linaro/arm-virt-bl/big-little/lib/virt_events.c b/linaro/arm-virt-bl/big-little/lib/virt_events.c new file mode 100644 index 0000000..ef5faca --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/virt_events.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "events.h" +#include "misc.h" +#include "virt_helpers.h" + +#ifndef SWITCHER +#define SWITCHER 0 +#endif + +/* + * cpu ids are used as is when "switcher" is true. In the + * "always on" case absolute cpu ids are used i.e 0-7 for + * an MPx4+MPx4 configuration. + */ +/* + * Pick up the event definition from the world that wants + * to use them. + */ +extern unsigned event[][MAX_EVENTS]; + +/* + * Set the specified event for that cpu. + */ +void set_event(unsigned event_id, unsigned cpu_id) +{ + event[cpu_id][event_id] = TRUE; + dsb(); + sev(); + return; +} + +inline unsigned get_event(unsigned event_id, unsigned cpu_id) +{ + return event[cpu_id][event_id]; +} + +void reset_event(unsigned event_id, unsigned cpu_id) +{ + event[cpu_id][event_id] = FALSE; + return; +} + +void wait_for_event(unsigned event_id, unsigned cpu_id) +{ + while (FALSE == get_event(event_id, cpu_id)) { + wfe(); + } + + return; +} + +/* + * Wait for events from each core. Its a little trickier than + * waiting for a single event. The event register as per the + * architecture is just a single bit to flag an event rather + * than the number of events. If multiple events are sent by + * the time we enter wfe() then each flag variable should be + * checked. + */ +void wait_for_events(unsigned event_id) +{ + unsigned ctr, event_count = 0, num_cpus = 0; + + if (SWITCHER) { + num_cpus = num_secondaries() + 1; + } else { + num_cpus = CLUSTER_CPU_COUNT(HOST_CLUSTER) + + CLUSTER_CPU_COUNT(!HOST_CLUSTER); + } + + do { + for (ctr = 0; ctr < num_cpus; ctr++) { + if (TRUE == get_event(event_id, ctr)) { + event_count++; + reset_event(event_id, ctr); + } + } + + if (event_count != num_cpus) + wfe(); + else + break; + } while (1); + + return; +} + +void set_events(unsigned event_id) +{ + unsigned ctr, num_cpus = 0; + + if (SWITCHER) { + num_cpus = num_secondaries() + 1; + } else { + num_cpus = CLUSTER_CPU_COUNT(HOST_CLUSTER) + + CLUSTER_CPU_COUNT(!HOST_CLUSTER); + } + + for (ctr = 0; ctr < num_cpus; ctr++) { + set_event(event_id, ctr); + } + return; +} diff --git a/linaro/arm-virt-bl/big-little/lib/virt_helpers.S b/linaro/arm-virt-bl/big-little/lib/virt_helpers.S new file mode 100644 index 0000000..eb3c909 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/virt_helpers.S @@ -0,0 +1,442 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + + IMPORT read_actlr + IMPORT write_actlr + + EXPORT smc + EXPORT dcisw + EXPORT dccsw + EXPORT dccisw + EXPORT read_lr + EXPORT read_sp + EXPORT write_sp + EXPORT write_lr + EXPORT panic + EXPORT spin_lock + EXPORT spin_trylock + EXPORT spin_unlock + EXPORT virt_memset + EXPORT hyp_save + EXPORT num_secondaries + EXPORT virt_dead + EXPORT get_sp + EXPORT disable_coherency + EXPORT enable_coherency + EXPORT inv_tlb_all + EXPORT inv_tlb_mva + EXPORT inv_icache_all + EXPORT inv_bpred_is + EXPORT inv_bpred_all + EXPORT inv_icache_mva_pou + EXPORT inv_dcache_mva_poc + EXPORT cln_dcache_mva_pou + EXPORT cln_dcache_mva_poc + EXPORT cache_maint_op + +; Cache maintenance op types +INV EQU 0x0 +CLN EQU 0x1 +CLN_INV EQU 0x2 + + AREA |.text|, CODE + +read_lr FUNCTION + ; Save r1 + push {r1} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r1, cpsr + and r1, r1, #0x1f + ; Check if the desired lr is of the current mode + cmp r0, r1 + moveq r0, LR + beq read_lr_out + ; Check if desired lr is of user mode + cmp r0, #0x10 + mrseq r0, LR_usr + beq read_lr_out + ; Check if desired lr is of supervisor mode + cmp r0, #0x13 + mrseq r0, LR_svc +read_lr_out + pop {r1} + bx lr + ENDFUNC + +write_lr FUNCTION + ; Save r2 + push {r2} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r2, cpsr + and r2, r2, #0x1f + ; Check if the lr is of the current mode + cmp r0, r2 + moveq LR, r1 + beq write_lr_out + ; Check if the lr is of user mode + cmp r0, #0x10 + msreq LR_usr, r1 + beq write_lr_out + ; Check if the lr is of supervisor mode + cmp r0, #0x13 + msreq LR_svc, r1 +write_lr_out + pop {r2} + bx lr + ENDFUNC + +read_sp FUNCTION + ; Save r1 + push {r1} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r1, cpsr + and r1, r1, #0x1f + ; Check if the desired sp is of the current mode + cmp r0, r1 + moveq r0, SP + beq read_sp_out + ; Check if desired sp is of user mode + cmp r0, #0x10 + mrseq r0, SP_usr + beq read_sp_out + ; Check if desired sp is of supervisor mode + cmp r0, #0x13 + mrseq r0, SP_svc + beq read_sp_out + ; Check if desired sp is of irq mode + cmp r0, #0x12 + mrseq r0, SP_irq + beq read_sp_out + ; Check if desired sp is of supervisor mode + cmp r0, #0x1a + mrseq r0, SP_hyp + beq read_sp_out + ; Check if desired sp is of monitor mode + cmp r0, #0x16 + mrseq r0, SP_mon +read_sp_out + pop {r1} + bx lr + ENDFUNC + +write_sp FUNCTION + ; Save r2 + push {r2} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r2, cpsr + and r2, r2, #0x1f + ; Check if the sp is of the current mode + cmp r0, r2 + moveq SP, r1 + beq write_sp_out + ; Check if the sp is of user mode + cmp r0, #0x10 + msreq SP_usr, r1 + beq write_sp_out + ; Check if the sp is of supervisor mode + cmp r0, #0x13 + msreq SP_svc, r1 + beq write_sp_out + ; Check if the sp is of irq mode + cmp r0, #0x12 + msreq SP_irq, r1 + beq write_sp_out + ; Check if the sp is of hyp mode + cmp r0, #0x1a + msreq SP_hyp, r1 + beq write_sp_out + ; Check if the sp is of monitor mode + cmp r0, #0x16 + msreq SP_mon, r1 +write_sp_out + pop {r2} + bx lr + ENDFUNC + + ALIGN 4 + +;-------------------------------------------------------- +; spin_lock +;-------------------------------------------------------- +spin_lock FUNCTION + MOV r2, #1 +sl_tryloop + LDREX r1, [r0] + CMP r1, #0 + STREXEQ r1, r2, [r0] + CMPEQ r1, #0 + BNE sl_tryloop + MCR p15, 0, r0, c7, c10, 4 + bx lr + ENDFUNC + +;-------------------------------------------------------- +; spin_lock +;-------------------------------------------------------- +spin_trylock FUNCTION + MOV r2, #1 + LDREX r1, [r0] + CMP r1, #0 + STREXEQ r1, r2, [r0] + MOV r0, r1 + MCR p15, 0, r0, c7, c10, 4 + bx lr + ENDFUNC + + ALIGN 4 + +;-------------------------------------------------------- +; spin_unlock +;-------------------------------------------------------- +spin_unlock FUNCTION + MOV r1, #0 + STR r1, [r0] + MCR p15, 0, r0, c7, c10, 4 + bx lr + ENDFUNC + + ALIGN 4 + +;-------------------------------------------------------- +; panic +;-------------------------------------------------------- +panic FUNCTION + isb + dsb + CPSID aif + B panic + ENDFUNC + +;-------------------------------------------------------------- +; Utility function that takes a pointer (r0), stack size (r1). +; It returns the pointer to the stack offset for the asked cpu +;-------------------------------------------------------------- +get_sp FUNCTION + ldr r2, =0x2c001800 + ldr r2, [r2] + and r2, r2, #0xff + clz r2, r2 + mov r3, #32 + sub r2, r3, r2 + mul r2, r2, r1 + add r0, r0, r2 + bx lr + ENDFUNC + +disable_coherency FUNCTION + push {lr} + bl read_actlr + bic r0, r0, #0x40 + bl write_actlr + dsb + isb + pop {lr} + bx lr + ENDFUNC + +enable_coherency FUNCTION + push {lr} + bl read_actlr + orr r0, r0, #0x40 + bl write_actlr + dsb + isb + pop {lr} + bx lr + ENDFUNC + +inv_bpred_is FUNCTION + mcr p15, 0, r0, c7, c1, 6 + bx lr + ENDFUNC + +inv_bpred_all FUNCTION + mcr p15, 0, r0, c7, c5, 6 + bx lr + ENDFUNC + +inv_tlb_all FUNCTION + mcr p15, 0, r0, c8, c7, 0 + dsb + isb + bx lr + ENDFUNC + +inv_tlb_mva FUNCTION + mcr p15, 0, r0, c8, c7, 1 + dsb + isb + bx lr + ENDFUNC + +inv_icache_all FUNCTION + mcr p15, 0, r10, c7, c5, 0 ; invalidate I cache + dsb + isb + bx lr + ENDFUNC + +inv_icache_mva_pou FUNCTION + mcr p15, 0, r0, c7, c5, 1 + dsb + isb + bx lr + ENDFUNC + +cln_dcache_mva_pou FUNCTION + mcr p15, 0, r0, c7, c11, 1 + dsb + isb + bx lr + ENDFUNC + +cln_dcache_mva_poc FUNCTION + mcr p15, 0, r0, c7, c10, 1 + dsb + isb + bx lr + ENDFUNC + +inv_dcache_mva_poc FUNCTION + mcr p15, 0, r0, c7, c6, 1 + dsb + isb + bx lr + ENDFUNC + + ; Clean/Invalidate/Clean and invalidate a specified cache level. + ; Ignore if the level does not exist. +cache_maint_op FUNCTION + push {r4-r11} + dsb + lsl r10, r0, #1 ; start clean at specified cache level + mrc p15, 1, r0, c0, c0, 1 ; read clidr +10 + add r2, r10, r10, lsr #1 ; work out 3x current cache level + mov r3, r0, lsr r2 ; extract cache type bits from clidr + and r3, r3, #7 ; mask of the bits for current cache only + cmp r3, #2 ; see what cache we have at this level + blt %f50 ; skip if no cache, or just i-cache + mcr p15, 2, r10, c0, c0, 0 ; select current cache level in cssr + isb ; isb to sych the new cssr&csidr + mrc p15, 1, r3, c0, c0, 0 ; read the new csidr + and r2, r3, #7 ; extract the length of the cache lines + add r2, r2, #4 ; add 4 (line length offset) + ldr r4, =0x3ff + ands r4, r4, r3, lsr #3 ; find maximum number on the way size + clz r5, r4 ; find bit position of way size increment + ldr r7, =0x7fff + ands r7, r7, r3, lsr #13 ; extract max number of the index size +20 + mov r9, r4 ; create working copy of max way size +30 + orr r11, r10, r9, lsl r5 ; factor way and cache number into r11 + lsl r6, r9, r5 + orr r11, r10, r6 ; factor way and cache number into r11 + orr r11, r11, r7, lsl r2 ; factor index number into r11 + lsl r6, r7, r2 + orr r11, r11, r6 ; factor index number into r11 + cmp r1, #INV + mcreq p15, 0, r11, c7, c6, 2 ; invalidate by set/way + beq %f40 + cmp r1, #CLN + mcreq p15, 0, r11, c7, c10, 2 ; clean by set/way + beq %f40 + mcr p15, 0, r11, c7, c14, 2 ; clean & invalidate by set/way +; nop ; nop +40 + subs r9, r9, #1 ; decrement the way + bge %b30 + subs r7, r7, #1 ; decrement the index + bge %b20 +50 + mov r10, #0 ; swith back to cache level 0 + mcr p15, 2, r10, c0, c0, 0 ; select current cache level in cssr + dsb + isb + pop {r4-r11} + bx lr + ENDFUNC + +smc FUNCTION + push {r4-r12, lr} + smc #0 + pop {r4-r12, pc} + ENDFUNC + +hyp_save FUNCTION + hvc #2 + bx lr + ENDFUNC + +virt_memcpy FUNCTION + cmp r2, #0 + bxeq lr +0 ldrb r3, [r1], #1 + strb r3, [r0], #1 + subs r2, #1 + bne %b0 + bx lr + ENDFUNC + +virt_memset FUNCTION + cmp r2, #0 + bxeq lr +0 strb r1, [r0], #1 + subs r2, #1 + bne %b0 + bx lr + ENDFUNC + +virt_dead FUNCTION + b virt_dead + ENDFUNC + +num_secondaries FUNCTION + mrc p15, 1, r0, c9, c0, 2 + lsr r0, r0, #24 + and r0, r0, #3 + bx lr + ENDFUNC + +dcisw FUNCTION + mcr p15, 0, r0, c7, c6, 2 + bx lr + ENDFUNC + +dccsw FUNCTION + mcr p15, 0, r0, c7, c10, 2 + bx lr + ENDFUNC + +dccisw FUNCTION + mcr p15, 0, r0, c7, c14, 2 + bx lr + ENDFUNC + + + END diff --git a/linaro/arm-virt-bl/big-little/lib/vsnprintf.c b/linaro/arm-virt-bl/big-little/lib/vsnprintf.c new file mode 100644 index 0000000..26be710 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/lib/vsnprintf.c @@ -0,0 +1,488 @@ +/* + * vsnprintf.c + * + * vsnprintf(), from which the rest of the printf() + * family is built + */ + +#include <stdarg.h> +#include <stddef.h> +#include <inttypes.h> +#include <string.h> +#include <limits.h> +#include <stdio.h> + +enum flags { + FL_ZERO = 0x01, /* Zero modifier */ + FL_MINUS = 0x02, /* Minus modifier */ + FL_PLUS = 0x04, /* Plus modifier */ + FL_TICK = 0x08, /* ' modifier */ + FL_SPACE = 0x10, /* Space modifier */ + FL_HASH = 0x20, /* # modifier */ + FL_SIGNED = 0x40, /* Number is signed */ + FL_UPPER = 0x80 /* Upper case digits */ +}; + +/* These may have to be adjusted on certain implementations */ +enum ranks { + rank_char = -2, + rank_short = -1, + rank_int = 0, + rank_long = 1, + rank_longlong = 2 +}; + +#define MIN_RANK rank_char +#define MAX_RANK rank_longlong + +#define INTMAX_RANK rank_longlong +#define SIZE_T_RANK rank_long +#define PTRDIFF_T_RANK rank_long + +#define EMIT(x) ({ if (o<n){*q++ = (x);} o++; }) + +static size_t +format_int(char *q, size_t n, uintmax_t val, enum flags flags, + int base, int width, int prec) +{ + char *qq; + size_t o = 0, oo; + static const char lcdigits[] = "0123456789abcdef"; + static const char ucdigits[] = "0123456789ABCDEF"; + const char *digits; + uintmax_t tmpval; + int minus = 0; + int ndigits = 0, nchars; + int tickskip, b4tick; + + /* Select type of digits */ + digits = (flags & FL_UPPER) ? ucdigits : lcdigits; + + /* If signed, separate out the minus */ + if (flags & FL_SIGNED && (intmax_t) val < 0) { + minus = 1; + val = (uintmax_t) (-(intmax_t) val); + } + + /* Count the number of digits needed. This returns zero for 0. */ + tmpval = val; + while (tmpval) { + tmpval /= base; + ndigits++; + } + + /* Adjust ndigits for size of output */ + + if (flags & FL_HASH && base == 8) { + if (prec < ndigits + 1) + prec = ndigits + 1; + } + + if (ndigits < prec) { + ndigits = prec; /* Mandatory number padding */ + } else if (val == 0) { + ndigits = 1; /* Zero still requires space */ + } + + /* For ', figure out what the skip should be */ + if (flags & FL_TICK) { + tickskip = (base == 16) ? 4 : 3; + } else { + tickskip = ndigits; /* No tick marks */ + } + + /* Tick marks aren't digits, but generated by the number converter */ + ndigits += (ndigits - 1) / tickskip; + + /* Now compute the number of nondigits */ + nchars = ndigits; + + if (minus || (flags & (FL_PLUS | FL_SPACE))) + nchars++; /* Need space for sign */ + if ((flags & FL_HASH) && base == 16) { + nchars += 2; /* Add 0x for hex */ + } + + /* Emit early space padding */ + if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars) { + while (width > nchars) { + EMIT(' '); + width--; + } + } + + /* Emit nondigits */ + if (minus) + EMIT('-'); + else if (flags & FL_PLUS) + EMIT('+'); + else if (flags & FL_SPACE) + EMIT(' '); + + if ((flags & FL_HASH) && base == 16) { + EMIT('0'); + EMIT((flags & FL_UPPER) ? 'X' : 'x'); + } + + /* Emit zero padding */ + if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits) { + while (width > nchars) { + EMIT('0'); + width--; + } + } + + /* Generate the number. This is done from right to left. */ + q += ndigits; /* Advance the pointer to end of number */ + o += ndigits; + qq = q; + oo = o; /* Temporary values */ + + b4tick = tickskip; + while (ndigits > 0) { + if (!b4tick--) { + qq--; + oo--; + ndigits--; + if (oo < n) + *qq = '_'; + b4tick = tickskip - 1; + } + qq--; + oo--; + ndigits--; + if (oo < n) + *qq = digits[val % base]; + val /= base; + } + + /* Emit late space padding */ + while ((flags & FL_MINUS) && width > nchars) { + EMIT(' '); + width--; + } + + return o; +} + +int vsnprintf(char *buffer, size_t n, const char *format, va_list ap) +{ + const char *p = format; + char ch; + char *q = buffer; + size_t o = 0; /* Number of characters output */ + uintmax_t val = 0; + int rank = rank_int; /* Default rank */ + int width = 0; + int prec = -1; + int base; + size_t sz; + enum flags flags = 0; + enum { + st_normal, /* Ground state */ + st_flags, /* Special flags */ + st_width, /* Field width */ + st_prec, /* Field precision */ + st_modifiers /* Length or conversion modifiers */ + } state = st_normal; + const char *sarg; /* %s string argument */ + char carg; /* %c char argument */ + int slen; /* String length */ + + while ((ch = *p++)) { + switch (state) { + case st_normal: + if (ch == '%') { + state = st_flags; + flags = 0; + rank = rank_int; + width = 0; + prec = -1; + } else { + EMIT(ch); + } + break; + + case st_flags: + switch (ch) { + case '-': + flags |= FL_MINUS; + break; + case '+': + flags |= FL_PLUS; + break; + case '\'': + flags |= FL_TICK; + break; + case ' ': + flags |= FL_SPACE; + break; + case '#': + flags |= FL_HASH; + break; + case '0': + flags |= FL_ZERO; + break; + default: + state = st_width; + p--; /* Process this character again */ + break; + } + break; + + case st_width: + if (ch >= '0' && ch <= '9') { + width = width * 10 + (ch - '0'); + } else if (ch == '*') { + width = va_arg(ap, int); + if (width < 0) { + width = -width; + flags |= FL_MINUS; + } + } else if (ch == '.') { + prec = 0; /* Precision given */ + state = st_prec; + } else { + state = st_modifiers; + p--; /* Process this character again */ + } + break; + + case st_prec: + if (ch >= '0' && ch <= '9') { + prec = prec * 10 + (ch - '0'); + } else if (ch == '*') { + prec = va_arg(ap, int); + if (prec < 0) + prec = -1; + } else { + state = st_modifiers; + p--; /* Process this character again */ + } + break; + + case st_modifiers: + switch (ch) { + /* Length modifiers - nonterminal sequences */ + case 'h': + rank--; /* Shorter rank */ + break; + case 'l': + rank++; /* Longer rank */ + break; + case 'j': + rank = INTMAX_RANK; + break; + case 'z': + rank = SIZE_T_RANK; + break; + case 't': + rank = PTRDIFF_T_RANK; + break; + case 'L': + case 'q': + rank += 2; + break; + default: + /* Output modifiers - terminal sequences */ + + /* Next state will be normal */ + state = st_normal; + + /* Canonicalize rank */ + if (rank < MIN_RANK) + rank = MIN_RANK; + else if (rank > MAX_RANK) + rank = MAX_RANK; + + switch (ch) { + case 'P': /* Upper case pointer */ + flags |= FL_UPPER; + /* fall through */ + case 'p': /* Pointer */ + base = 16; + prec = (CHAR_BIT*sizeof(void *)+3)/4; + flags |= FL_HASH; + val = (uintmax_t)(uintptr_t) + va_arg(ap, void *); + goto is_integer; + + case 'd': /* Signed decimal output */ + case 'i': + base = 10; + flags |= FL_SIGNED; + switch (rank) { + case rank_char: + /* Yes, all these casts are + needed... */ + val = (uintmax_t)(intmax_t) + (signed char) + va_arg(ap, signed int); + break; + case rank_short: + val = (uintmax_t)(intmax_t) + (signed short) + va_arg(ap, signed int); + break; + case rank_int: + val = (uintmax_t)(intmax_t) + va_arg(ap, signed int); + break; + case rank_long: + val = (uintmax_t)(intmax_t) + va_arg(ap, signed long); + break; + case rank_longlong: + val = (uintmax_t)(intmax_t) + va_arg(ap, + signed long long); + break; + } + goto is_integer; + case 'o': /* Octal */ + base = 8; + goto is_unsigned; + case 'u': /* Unsigned decimal */ + base = 10; + goto is_unsigned; + case 'X': /* Upper case hexadecimal */ + flags |= FL_UPPER; + /* fall through */ + case 'x': /* Hexadecimal */ + base = 16; + goto is_unsigned; + + is_unsigned: + switch (rank) { + case rank_char: + val = (uintmax_t) + (unsigned char) + va_arg(ap, unsigned + int); + break; + case rank_short: + val = (uintmax_t) + (unsigned short) + va_arg(ap, unsigned + int); + break; + case rank_int: + val = (uintmax_t) + va_arg(ap, unsigned + int); + break; + case rank_long: + val = (uintmax_t) + va_arg(ap, unsigned + long); + break; + case rank_longlong: + val = (uintmax_t) + va_arg(ap, unsigned + long long); + break; + } + /* fall through */ + + is_integer: + sz = format_int(q, (o < n) ? n - o : 0, + val, flags, base, + width, prec); + q += sz; + o += sz; + break; + + case 'c': /* Character */ + carg = (char)va_arg(ap, int); + sarg = &carg; + slen = 1; + goto is_string; + case 's': /* String */ + sarg = va_arg(ap, const char *); + sarg = sarg ? sarg : "(null)"; + slen = strlen(sarg); + goto is_string; + + is_string: + { + char sch; + int i; + + if (prec != -1 && slen > prec) + slen = prec; + + if (width > slen + && !(flags & FL_MINUS)) { + char pad = + (flags & FL_ZERO) ? + '0' : ' '; + while (width > slen) { + EMIT(pad); + width--; + } + } + for (i = slen; i; i--) { + sch = *sarg++; + EMIT(sch); + } + if (width > slen + && (flags & FL_MINUS)) { + while (width > slen) { + EMIT(' '); + width--; + } + } + } + break; + + case 'n': + { + /* Output the number of + characters written */ + + switch (rank) { + case rank_char: + *va_arg(ap, + signed char *) + = o; + break; + case rank_short: + *va_arg(ap, + signed short *) + = o; + break; + case rank_int: + *va_arg(ap, + signed int *) + = o; + break; + case rank_long: + *va_arg(ap, + signed long *) + = o; + break; + case rank_longlong: + *va_arg(ap, + signed long long *) + = o; + break; + } + } + break; + + default: /* Anything else, including % */ + EMIT(ch); + break; + } + } + } + } + + /* Null-terminate the string */ + if (o < n) + *q = '\0'; /* No overflow */ + else if (n > 0) + buffer[n - 1] = '\0'; /* Overflow - terminate at end of buffer */ + + return o; +} diff --git a/linaro/arm-virt-bl/big-little/scf-macros.h b/linaro/arm-virt-bl/big-little/scf-macros.h new file mode 100644 index 0000000..1e08416 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/scf-macros.h @@ -0,0 +1,8 @@ +#ifndef SCF_MACROS_H +#define SCF_MACROS_H + +#define PASTE(a,b) _PASTE(a,b) +#define _PASTE(a,b) a ## b + +#endif + diff --git a/linaro/arm-virt-bl/big-little/secure_world/events.c b/linaro/arm-virt-bl/big-little/secure_world/events.c new file mode 100644 index 0000000..4533039 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/secure_world/events.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "events.h" + +/* + * Set the specified event for that cpu. + */ +void _set_event(unsigned event_id, unsigned cpu_id, unsigned event_type) +{ + dsb(); + secure_event[cpu_id][event_id] = TRUE; + dsb(); + sev(); + return; +} + +inline unsigned _get_event(unsigned event_id, unsigned cpu_id) +{ + return secure_event[cpu_id][event_id]; +} + +void _reset_event(unsigned event_id, unsigned cpu_id, unsigned event_type) +{ + dsb(); + secure_event[cpu_id][event_id] = FALSE; + dsb(); + return; +} + +void _wait_for_event(unsigned event_id, unsigned cpu_id, unsigned event_type) +{ + dsb(); + do { + wfe(); + isb(); + dsb(); + } while (FALSE == _get_event(event_id, cpu_id)); + + return; +} + +/* + * Wait for events from each core. Its a little trickier than + * waiting for a single event. The event register as per the + * architecture is just a single bit to flag an event rather + * than the number of events. If multiple events are sent by + * the time we enter wfe() then each flag variable should be + * checked. + */ +void _wait_for_events(unsigned event_id, unsigned event_type) +{ + unsigned ctr, event_count = 0, num_cpus = num_secondaries() + 1;; + + dsb(); + do { + wfe(); + for (ctr = 0; ctr < num_cpus; ctr++) { + if (TRUE == _get_event(event_id, ctr)) { + event_count++; + _reset_event(event_id, ctr, event_type); + } + } + } while (event_count != num_cpus); + + return; +} + +void _set_events(unsigned event_id, unsigned event_type) +{ + unsigned ctr; + for (ctr = 0; ctr < (num_secondaries() + 1); ctr++) { + _set_event(event_id, ctr, event_type); + } + return; +} diff --git a/linaro/arm-virt-bl/big-little/secure_world/flat_pagetable.S b/linaro/arm-virt-bl/big-little/secure_world/flat_pagetable.S new file mode 100644 index 0000000..f473c66 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/secure_world/flat_pagetable.S @@ -0,0 +1,172 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + PRESERVE8 + AREA |.rodata.PageTable|, DATA, READONLY, ALIGN=14 + EXPORT flat_pagetables + +; Definitions for section descriptors +NGLOBAL EQU (1<<17) +SHARED EQU (1<<16) +APX EQU (1<<15) +TEX1 EQU (1<<12) +TEX2 EQU (1<<13) +TEX3 EQU (1<<14) +AP0 EQU (1<<10) +AP1 EQU (1<<11) +PARITY EQU (1<<9) +XN EQU (1<<4) +CACHE EQU (1<<3) +BUFFER EQU (1<<2) +SECTION EQU 2 +SECURITY EQU 0 + +; Select WBWA for both Inner and Outer cache +MEMORY EQU (TEX1 :OR: CACHE :OR: BUFFER :OR: SECTION :OR: AP0 :OR: AP1 :OR: SECURITY) +S_RO_MEMORY EQU (TEX1 :OR: CACHE :OR: BUFFER :OR: SECTION :OR: AP0 :OR: AP1 :OR: APX) +S_RW_MEMORY EQU (TEX1 :OR: CACHE :OR: BUFFER :OR: SECTION :OR: AP0 :OR: AP1) +; Select WBWA Inner cache, WBnWA Outer cache +;MEMORY EQU (TEX3 | TEX2 | TEX1 | BUFFER | SECTION | AP0 | AP1 | SECURITY) + +NC_MEMORY EQU (TEX1 :OR: SECTION :OR: AP0 :OR: AP1 :OR: SECURITY) +SO_MEMORY EQU (SHARED :OR: SECTION :OR: AP0 :OR: AP1 :OR: SECURITY) + +; *Don't* mark device accesses as nonsecure, or things like secure-side GIC config won't work... +DEVICE EQU (BUFFER :OR: SHARED :OR: SECTION :OR: AP0 :OR: AP1 :OR: XN ) + +NO_MEMORY EQU (SECTION) +SHARED_MEMORY EQU (MEMORY :OR: SHARED) +SHARED_S_RO_MEMORY EQU (S_RO_MEMORY :OR: SHARED) +SHARED_S_RW_MEMORY EQU (S_RW_MEMORY :OR: SHARED) +SHARED_NC_MEMORY EQU (NC_MEMORY :OR: SHARED) +SHARED_SO_MEMORY EQU (SO_MEMORY :OR: SHARED) +SHARED_DEVICE EQU (DEVICE :OR: SHARED) + +; first-level descriptors - all of them are 1MB sections + +flat_pagetables + +#ifdef BUILD_RVCT + + GBLA count16 + GBLA ramstart + +count16 SETA 0 +ramstart SETA 0 + +; NOT FOR RELEASE + WHILE count16 < ramstart+0x40 + ; 0-64MB Secure ROM/NOR Flash + DCD (count16<<20) :OR: SHARED_DEVICE +count16 SETA count16 + 1 + WEND + + WHILE count16 < ramstart+0x80 + ; 64-128MB Secure RAM + DCD (count16<<20) :OR: SHARED_S_RW_MEMORY +count16 SETA count16 + 1 + WEND + + WHILE count16 < ramstart+0x800 + ; 128-2048MB Peripheral space + DCD (count16<<20) :OR: SHARED_DEVICE +count16 SETA count16 + 1 + WEND + + WHILE count16 < ramstart+0x810 + ; 0-16MB Shared Memory + DCD (count16<<20) :OR: SHARED_MEMORY +count16 SETA count16 + 1 + WEND + + WHILE count16 < ramstart+0x81f + ; 16-31MB Strongly Ordered + DCD (count16<<20) :OR: SHARED_SO_MEMORY +count16 SETA count16 + 1 + WEND + + WHILE count16 < ramstart+0x820 + ; 31-32MB Shared Noncached Normal Memory + DCD (count16<<20) :OR: SHARED_NC_MEMORY +count16 SETA count16 + 1 + WEND + + WHILE count16 < ramstart+0x1000 + ; rest of memory is RAM + DCD (count16<<20) :OR: SHARED_MEMORY +count16 SETA count16 + 1 + WEND + +#else /* GNU */ + +.altmacro +.macro range start:req, end:req, insn:req + .if ( \start ) == ( \end ) + \insn ( \start ) + .exitm + .endif + + .if ( \start ) < ( \end ) + range \start , %( \start ) + (( \end ) - ( \start )) / 2, \insn + range %( \start ) + ((( \end ) - ( \start )) / 2 + 1), \end , \insn + .endif +.endm + + @ Declare a single section descriptor: + .macro descriptor phys + .long (( \phys ) << 20) | .L_type + .endm + + + .equ .L_ramstart, 0 + + ; 0-64MB Secure ROM/NOR Flash + .equ .L_type, SHARED_DEVICE + range .L_ramstart, .L_ramstart + 0x40 - 1, descriptor + + ; 64-128MB Secure RAM + .equ .L_type, SHARED_S_RW_MEMORY + range .L_ramstart + 0x40, .L_ramstart + 0x80 - 1, descriptor + + ; 128-2048MB Peripheral space + .equ .L_type, SHARED_DEVICE + range .L_ramstart + 0x80, .L_ramstart + 0x800 - 1, descriptor + + ; 0-16MB Shared Memory + .equ .L_type, SHARED_MEMORY + range .L_ramstart + 0x800, .L_ramstart + 0x810 - 1, descriptor + + ; 16-31MB Strongly Ordered + .equ .L_type, SHARED_SO_MEMORY + range .L_ramstart + 0x810, .L_ramstart + 0x81f - 1, descriptor + + ; 31-32MB Shared Noncached Normal Memory + .equ .L_type, SHARED_NC_MEMORY + range .L_ramstart + 0x81f, .L_ramstart + 0x820 - 1, descriptor + + ; rest of memory is RAM + .equ .L_type, SHARED_MEMORY + range .L_ramstart + 0x820, .L_ramstart + 0x1000 - 1, descriptor + +#endif /* BUILD_RVCT */ + + END diff --git a/linaro/arm-virt-bl/big-little/secure_world/monmode_vectors.S b/linaro/arm-virt-bl/big-little/secure_world/monmode_vectors.S new file mode 100755 index 0000000..0c5204c --- /dev/null +++ b/linaro/arm-virt-bl/big-little/secure_world/monmode_vectors.S @@ -0,0 +1,396 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + + AREA |.text.monmode_vectors|, CODE, ALIGN=5 + PRESERVE8 + +SMC_SEC_INIT EQU 0x0 +SMC_SEC_SAVE EQU 0x1 +SMC_SEC_SHUTDOWN EQU 0x2 +L1 EQU 0x0 +L2 EQU 0x1 +INV EQU 0x0 +CLN EQU 0x1 +CLN_INV EQU 0x2 +CR_M EQU (1<<0) +CR_C EQU (1<<2) +CR_I EQU (1<<12) +CR_Z EQU (1<<11) +CR_U EQU (1<<22) +CR_TRE EQU (1<<28) +SCR_NS EQU 0x01 +PT_IRGN EQU (1<<0) +PT_RGN EQU (1<<3) +PT_SH EQU (1<<1) +PT_NOS EQU (1<<5) +TTBR0_PROP EQU (PT_NOS :OR: PT_SH :OR: PT_RGN :OR: PT_IRGN) +SO_MEM EQU 0x0 +DV_MEM EQU 0x1 +NM_MEM EQU 0x2 +I_SH EQU 0x1 +SH EQU 0x1 +PRRR_TR0 EQU (SO_MEM<<0) +PRRR_TR1 EQU (DV_MEM<<2) +PRRR_TR4 EQU (NM_MEM<<8) +PRRR_TR7 EQU (NM_MEM<<14) +PRRR_DS1 EQU (SH<<17) +PRRR_NS1 EQU (SH<<19) +PRRR_NOS1 EQU (I_SH<<25) +PRRR_NOS4 EQU (I_SH<<28) +PRRR_NOS7 EQU (I_SH<<31) +NC EQU 0x0 +WBWA EQU 0x1 +NMRR_OR4 EQU (NC<<24) +NMRR_OR7 EQU (WBWA<<30) +NMRR_IR4 EQU (NC<<8) +NMRR_IR7 EQU (WBWA<<14) + +; ============================================================================== +; These should be the same the defines in misc.h +; ============================================================================== +MAX_CLUSTERS EQU 2 +MAX_CPUS EQU 8 +STACK_SIZE EQU (96 << 2) + +; ============================================================================== +; Simple vector table +; ============================================================================== + IMPORT ns_entry_ptr + IMPORT secure_context_save + IMPORT enable_caches + IMPORT inv_icache_all + IMPORT flat_pagetables + IMPORT read_sctlr + IMPORT write_sctlr + IMPORT read_ttbr0 + IMPORT write_ttbr0 + IMPORT inv_tlb_all + IMPORT inv_bpred_all + IMPORT write_dacr + IMPORT write_prrr + IMPORT write_nmrr + IMPORT get_sp + IMPORT secure_context_restore + IMPORT powerdown_cluster + IMPORT get_powerdown_stack + IMPORT wfi + IMPORT read_cpuid + IMPORT add_dv_page + EXPORT monmode_vector_table + EXPORT warm_reset + + ; ---------------------------------------------------- + ; Macro to initialise MMU. Corrupts 'r0' + ; ---------------------------------------------------- + MACRO + setup_mmu $r1, $r2 + MOVW $r1, #0x5555 + MOVT $r1, #0x5555 + ; Enable our page tables if not + LDR r0, =flat_pagetables + ORR r0, #TTBR0_PROP + ; Write TTBR0 + MCR p15, 0, r0, c2, c0, 0 + ; Write DACR + MCR p15, 0, $r1, c3, c0, 0 + + ; Enable the remap registers to treat OSH memory as ISH memory + MOV $r1, #PRRR_TR0 + ORR $r1, #PRRR_TR1 + ORR $r1, #PRRR_TR4 + ORR $r1, #PRRR_TR7 + ORR $r1, #PRRR_NOS1 + ORR $r1, #PRRR_NOS4 + ORR $r1, #PRRR_NOS7 + ORR $r1, #PRRR_NS1 + ORR $r1, #PRRR_DS1 + + MOV $r2, #NMRR_IR4 + ORR $r2, #NMRR_IR7 + ORR $r2, #NMRR_OR4 + ORR $r2, #NMRR_OR7 + + MCR p15, 0, $r1, c10, c2, 0 + MCR p15, 0, $r2, c10, c2, 1 + + ; Enable Dcache, TEX Remap & MMU + MRC p15, 0, r0, c1, c0, 0 + ORR r0, #CR_M + ORR r0, #CR_C + ORR r0, #CR_TRE + MCR p15, 0, r0, c1, c0, 0 + DSB + ISB + MEND + + ; ---------------------------------------------------- + ; Macro to setup secure stacks, Corrupts 'r0-r3' + ; ---------------------------------------------------- + MACRO + setup_stack + LDR r0, =secure_stacks + MOV r1, #STACK_SIZE + BL get_sp + MOV sp, r0 + MEND + + ALIGN 32 +monmode_vector_table +monmode_reset_vec + B monmode_reset_vec +monmode_undef_vec + B monmode_undef_vec +monmode_smc_vec + B do_smc +monmode_pabort_vec + B monmode_pabort_vec +monmode_dabort_vec + B monmode_dabort_vec +monmode_unused_vec + B monmode_unused_vec +monmode_irq_vec + B monmode_irq_vec +monmode_fiq_vec + B monmode_fiq_vec + + + ; SMC handler. Currently accepts three types of calls: + ; 1. Init: Sets up stack, mmu, caches & coherency + ; 2. Context Save: Saves the secure world context + ; 3. Powerdown: Cleans the caches and power downs the cluster + ; Also assumes the availability of r4-r7 +do_smc FUNCTION + ; Switch to non-secure banked registers + MRC p15, 0, r2, c1, c1, 0 + BIC r2, #SCR_NS + MCR p15, 0, r2, c1, c1, 0 + ISB + + ; Check if we are being called to setup the world + CMP r0, #SMC_SEC_INIT + BEQ setup_secure + + CMP r0, #SMC_SEC_SAVE + BEQ save_secure + + CMP r0, #SMC_SEC_SHUTDOWN + BEQ shutdown_cluster + +smc_done + ; Return to non-secure banked registers + MRC p15, 0, r0, c1, c1, 0 + ORR r0, #SCR_NS + MCR p15, 0, r0, c1, c1, 0 + ISB + ERET + ENDFUNC + +shutdown_cluster + BL read_cpuid + BL get_powerdown_stack + MOV sp, r0 + BL powerdown_cluster +enter_wfi + BL wfi + B enter_wfi + +save_secure + PUSH {lr} + MOV r0, r1 + BL secure_context_save + POP {lr} + B smc_done + +setup_secure + ; Save the LR + MOV r4, lr + + ; Turn on the I cache, branch predictor and alingment + BL read_sctlr + ORR r0, #CR_I + ORR r0, #CR_U + ORR r0, #CR_Z + BL write_sctlr + dsb + isb + + setup_stack + + ; ---------------------------------------------------- + ; Safely turn on caches + ; TODO: Expensive usage of stacks as we are executing + ; out of SO memory. Done only once so can live with it + ; ---------------------------------------------------- + BL enable_caches + + ; ---------------------------------------------------- + ; Add a page backed by device memory for locks & stacks + ; ---------------------------------------------------- + LDR r0, =flat_pagetables + BL add_dv_page + setup_mmu r1, r2 + + ; Restore LR + MOV lr, r4 + B smc_done + +warm_reset FUNCTION + ; ---------------------------------------------------- + ; Start the SO load of the pagetables asap + ; ---------------------------------------------------- + LDR r4, =flat_pagetables + + ; ---------------------------------------------------- + ; Enable I, C, Z, U bits in the SCTLR and SMP bit in + ; the ACTLR right after reset + ; ---------------------------------------------------- + MRC p15, 0, r0, c1, c0, 0 + ORR r0, r0, #CR_I + ORR r0, r0, #CR_U + ORR r0, r0, #CR_Z + ORR r0, r0, #CR_C + MCR p15, 0, r0, c1, c0, 0 + MRC p15, 0, r1, c1, c0, 1 + ORR r1, r1, #0x40 + MCR p15, 0, r1, c1, c0, 1 + ISB + + ; ---------------------------------------------------- + ; Enable the MMU even though CCI snoops have not been + ; enabled. Should not be a problem as we will not + ; access any inter-cluster data till we do so + ; ---------------------------------------------------- + MOVW r2, #0x5555 + MOVT r2, #0x5555 + ; Enable our page tables if not + ORR r4, #TTBR0_PROP + ; Write TTBR0 + MCR p15, 0, r4, c2, c0, 0 + ; Write DACR + MCR p15, 0, r2, c3, c0, 0 + + ; Enable the remap registers to treat OSH memory as ISH memory + MOV r2, #PRRR_TR0 + ORR r2, #PRRR_TR1 + ORR r2, #PRRR_TR4 + ORR r2, #PRRR_TR7 + ORR r2, #PRRR_NOS1 + ORR r2, #PRRR_NOS4 + ORR r2, #PRRR_NOS7 + ORR r2, #PRRR_NS1 + ORR r2, #PRRR_DS1 + MOV r3, #NMRR_IR4 + ORR r3, #NMRR_IR7 + ORR r3, #NMRR_OR4 + ORR r3, #NMRR_OR7 + MCR p15, 0, r2, c10, c2, 0 + MCR p15, 0, r3, c10, c2, 1 + + ; Enable Dcache, TEX Remap & MMU + MRC p15, 0, r0, c1, c0, 0 + ORR r0, #CR_M + ORR r0, #CR_C + ORR r0, #CR_TRE + MCR p15, 0, r0, c1, c0, 0 + ISB + + ; ---------------------------------------------------- + ; Try Preloading the literal pools before they are + ; accessed. + ; ---------------------------------------------------- + ADR r4, warm_reset_ltrls + PLD [r4] + PLD warm_reset_ltrls + LDR r6, =secure_stacks + + ; ---------------------------------------------------- + ; Safely turn on CCI snoops + ; ---------------------------------------------------- + MOV r4, #0x0 + MOVT r4, #0x2c09 + MRC p15, 0, r0, c0, c0, 5 + UBFX r1, r0, #0, #8 + UBFX r2, r0, #8, #8 + MOV r3, #3 + CMP r2, #0 + BEQ a15_snoops + MOV r5, #0x5000 + CMP r1, #0 + BNE cci_snoop_status + STR r3, [r4, r5] + B cci_snoop_status +a15_snoops + MOV r5, #0x4000 + CMP r1, #0 + BNE cci_snoop_status + STR r3, [r4, r5] +cci_snoop_status + LDR r0, [r4, r5] + TST r0, #3 + BEQ cci_snoop_status + LDR r0, [r4, #0xc] + TST r0, #1 + BNE cci_snoop_status + + ; ---------------------------------------------------- + ; Switch to Monitor mode straight away as we do not want to worry + ; about setting up Secure SVC stacks. All Secure world save/restore + ; takes place in the monitor mode. + ; ---------------------------------------------------- + MRS r5, cpsr ; Get current mode (SVC) in r0 + BIC r1, r5, #0x1f ; Clear all mode bits + ORR r1, r1, #0x16 ; Set bits for Monitor mode + MSR cpsr_cxsf, r1 ; We are now in Monitor Mode + BIC r1, r5, #0x1f ; Clear all mode bits + ORR r1, r1, #0x1a ; Set bits for a return to the HYP mode + MSR spsr_cxsf, r1 + + MOV r0, r6 + MOV r1, #STACK_SIZE + BL get_sp + MOV sp, r0 + + ; Restore secure world context & enable MMU + BL secure_context_restore + + ; Switch to non-secure registers for HYP & + ; later non-secure world restore. + MRC p15, 0, r1, c1, c1, 0 + ORR r1, #SCR_NS + MCR p15, 0, r1, c1, c1, 0 + ISB + + ; Setup the NS link register + MRC p15, 0, r0, c0, c0, 5 + ANDS r0, r0, #0xf + LDR r1, =ns_entry_ptr + ADD r1, r1, r0, lsl #2 + LDR lr, [r1] + ; Switch to Non-secure world + ERET +warm_reset_ltrls + ENDFUNC + + AREA |.bss.stacks|, DATA, NOINIT, ALIGN=6 +secure_stacks SPACE MAX_CLUSTERS*MAX_CPUS*STACK_SIZE + END diff --git a/linaro/arm-virt-bl/big-little/secure_world/secure_context.c b/linaro/arm-virt-bl/big-little/secure_world/secure_context.c new file mode 100644 index 0000000..24c0f24 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/secure_world/secure_context.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "secure_world.h" + +extern powerup_ib_core(unsigned, unsigned); + +sec_context secure_context[MAX_CORES] __attribute__ ((aligned(CACHE_LINE_SZ))); +unsigned ns_entry_ptr[MAX_CORES]; +unsigned small_pagetable[1024] __attribute__ ((aligned(4096))); +unsigned host_cluster = HOST_CLUSTER; +unsigned switcher = SWITCHER; + +/* Bakery lock to serialize access to the tube. */ +static bakery_t lock_tube1 __attribute__ ((section(".data.BL_SEC_DV_PAGE"))) = { +0}; + +void enable_caches(void) +{ + unsigned cpu_id = read_cpuid(); + unsigned cluster_id = read_clusterid(); + unsigned first_cpu = find_first_cpu(); + + write_trace(&lock_tube1, SEC_TUBE1, "Secure Coherency Enable Start", + read_cntpct(), 0x0, 0x0); + + /* Turn on coherency */ + enable_coherency(); + + /* Enable caches */ + write_sctlr(read_sctlr() | CR_I | CR_Z | CR_C); + dsb(); + isb(); + + /* + * Only one cpu should enable the CCI while the other + * cpus wait. + */ + if (first_cpu == cpu_id) { + if (cluster_id) + write32(A7_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x3); + else + write32(A15_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x3); + + dsb(); + } + + /* Wait for the dust to settle down */ + while (read32(CCI_BASE + STATUS_REG) & 0x1) ; + + write_trace(&lock_tube1, SEC_TUBE1, "Secure Coherency Enable End", + read_cntpct(), 0x0, 0x0); + + return; +} + +void secure_context_restore(void) +{ + unsigned cpu_id = read_cpuid(); + sec_context *sec_ctx = &secure_context[cpu_id]; + + write_trace(&lock_tube1, SEC_TUBE1, "Secure Context Restore Start", + read_cntpct(), 0x0, 0x0); + + /* Restore state of CCI SAR */ + write32(CCI_BASE + SECURE_ACCESS_REG, sec_ctx->cci_sar); + + /* Restore the security state of PPIs. */ + write32(GIC_ID_PHY_BASE + GICD_SEC, sec_ctx->vgic_icdisr0); + + /* Restore the Priority mask register */ + write32(GIC_IC_PHY_BASE + GICC_PRIMASK, sec_ctx->vgic_iccpmr); + + /* Restore the coprocessor context */ + write_cntfrq(sec_ctx->cntfrq); + write_mvbar(sec_ctx->mvbar); + write_vbar(sec_ctx->vbar); + write_nsacr(sec_ctx->nsacr); + write_cpacr(sec_ctx->cpacr); + write_actlr(sec_ctx->actlr); + write_scr(sec_ctx->scr); + write_sctlr(read_sctlr() | sec_ctx->sctlr); + dsb(); + isb(); + + write_trace(&lock_tube1, SEC_TUBE1, "Secure Context Restore End", + read_cntpct(), 0x0, 0x0); + return; +} + +void secure_context_save(unsigned ns_entry_point) +{ + unsigned cpu_id = read_cpuid(); + sec_context *sec_ctx = &secure_context[cpu_id]; + + ns_entry_ptr[cpu_id] = ns_entry_point; + sec_ctx->cci_sar = read32(CCI_BASE + SECURE_ACCESS_REG); + sec_ctx->vgic_icdisr0 = read32(GIC_ID_PHY_BASE + GICD_SEC); + sec_ctx->vgic_iccpmr = read32(GIC_IC_PHY_BASE + GICC_PRIMASK); + sec_ctx->mvbar = read_mvbar(); + sec_ctx->vbar = read_vbar(); + sec_ctx->nsacr = read_nsacr(); + sec_ctx->cpacr = read_cpacr(); + sec_ctx->actlr = read_actlr(); + sec_ctx->scr = read_scr(); + sec_ctx->sctlr = read_sctlr(); + sec_ctx->cntfrq = read_cntfrq(); + + /* + * Now that the context has been saved, its safe to bring + * our counterpart on the inbound cluster out of reset. + */ + powerup_ib_core(get_inbound(), cpu_id); + + return; +} + +/* Create the small page level 1 descriptor */ +static void create_l1_sp_desc(unsigned virt_addr, unsigned l1_ttb_va, + unsigned l2_ttb_pa) +{ + unsigned ttb1_index = 0; + unsigned ttb1_desc = 0; + + ttb1_index = (virt_addr & MB_MASK) >> MB_SHIFT; + + /* + * Create a mapping if one is not already present. + * Assuming that page tables are initialized to 0. + */ + if (!(read32(l1_ttb_va + 4 * ttb1_index) & SMALL_PAGE)) { + l2_ttb_pa = l2_ttb_pa & SP_L1_BASE_MASK; + ttb1_desc = l2_ttb_pa | SMALL_PAGE; + write32(l1_ttb_va + 4 * ttb1_index, ttb1_desc); + cln_dcache_mva_pou((unsigned *)l1_ttb_va + 4 * ttb1_index); + } + + return; +} + +/* Create the small page level 2 descriptor */ +static void create_l2_sp_desc(unsigned virt_addr, unsigned phys_addr, + unsigned l2_ttb_va, unsigned attrs) +{ + unsigned int ttb2_index = 0; + unsigned int ttb2_desc = 0; + unsigned int mem_attrs = + SP_SBO | SP_CACHEABLE | SP_BUFFERABLE | SP_TEX0 | SP_SHARED | + SP_AP0; + + /* Use default attributes if the user has not passed any */ + if (attrs) { + mem_attrs = attrs; + } + + /* Left shift by 12 followed by a right shift by 24 gives 2nd level index */ + ttb2_index = (virt_addr << PAGE_SHIFT) >> (PAGE_SHIFT * 2); + + /* + * Create a mapping if one is not already present + * Assuming that page tables are initialized to 0. + */ + if (!(read32(l2_ttb_va + 4 * ttb2_index))) { + ttb2_desc = (phys_addr & PAGE_MASK) | mem_attrs; + write32(l2_ttb_va + 4 * ttb2_index, ttb2_desc); + cln_dcache_mva_pou((unsigned *)l2_ttb_va + 4 * ttb2_index); + } + + return; +} + +void add_dv_page(unsigned pt_base) +{ + unsigned start_addr = (unsigned)BL_SEC_DV_PAGE_base; + unsigned dv_mem_attrs = SP_AP0 | SP_SBO | SP_XN | SP_BUFFERABLE; + unsigned addr = 0x0; + + /* + * Create the L1 small page descriptor using the base address supplied. + * The region specified must all fit within a single 1MB section. + */ + create_l1_sp_desc(start_addr, (unsigned)pt_base, + (unsigned)small_pagetable); + + /* + * We want all memory to be WBWA/S except for a page + * which is device (used for the Bakery locks etc). + */ + for (addr = start_addr & MB_MASK; + addr < (start_addr & MB_MASK) + 0x100000; addr += 4096) { + create_l2_sp_desc(addr, addr, (unsigned)small_pagetable, + (addr == start_addr ? dv_mem_attrs : 0)); + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/secure_world/secure_resets.c b/linaro/arm-virt-bl/big-little/secure_world/secure_resets.c new file mode 100644 index 0000000..7129be1 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/secure_world/secure_resets.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "secure_world.h" +#include "events.h" +#include "bakery.h" + +extern unsigned warm_reset; + +/* Bakery lock to serialize access to the tube. */ +bakery_t lock_tube0 __attribute__ ((section(".data.BL_SEC_DV_PAGE"))) = { +0}; + +/* + * Compile time switch to decided whether the outbound + * L2 will be kept on always for inbound cache warming + * or it will be flushed and reset after the BL context + * has been picked up. + */ +static unsigned flush_ob_l2 = FLUSH_OB_L2; + +#if FM_BETA +/* + * Variable in secure world to indicate the + * reset type i.e. cold (0) or warm reset (!0). + */ +unsigned ve_reset_type[NUM_CPUS]; +#endif + +/* + * Allocate secure events in our device page + */ +volatile unsigned event[MAX_CORES][MAX_EVENTS] + __attribute__ ((section(".data.BL_SEC_DV_PAGE"))); + +/* + * Normal spinlock to guard inbound cluster registers + * in the KFSCB. It will always be used when the MMU + * is on. Each cluster will anyways use it sequentially. + */ +static unsigned lock_ib_kfscb; + +/* + * Bakery lock to guard outbound cluster registers in + * KFSCB. It will always be used when the MMU is off. + * Each cluster will anyways use it sequentially + */ +static bakery_t lock_ob_kfscb + __attribute__ ((section(".data.BL_SEC_DV_PAGE"))) = { +0}; + +/* + * Small stacks for after we have turned our caches off. + */ +static unsigned long long powerdown_stacks[NUM_CPUS][32] + __attribute__ ((section(".data.BL_SEC_DV_PAGE"))); + +/* + * The way a warm reset is detected has changed in the post beta FastModels. + * The following workarounds make the earlier approach coexist with the + * new one. Instead of dealing with a function pointer, they manipulate a + * variable. + */ +static void set_reset_handler(unsigned cluster_id, unsigned cpu_id, + void (*handler) (void)) +{ +#if FM_BETA + ve_reset_type[cpu_id]++; + cln_dcache_mva_poc(&ve_reset_type[cpu_id]); +#else + write32(KFSCB_BASE + RST_HANDLER0 + ((cpu_id + (cluster_id << 2)) << 3), + (unsigned)handler); + dsb(); +#endif +} + +static void (*get_reset_handler(unsigned cluster_id, unsigned cpu_id)) (void) { +#if FM_BETA + return (void (*)(void))ve_reset_type[cpu_id]; +#else + return (void (*)(void))read32(KFSCB_BASE + RST_HANDLER0 + + ((cpu_id + (cluster_id << 2)) << 3)); +#endif +} + +unsigned long long *get_powerdown_stack(unsigned cpu_id) +{ + return &powerdown_stacks[cpu_id + 1][0]; +} + +unsigned get_inbound() +{ + return !read_clusterid(); +} + +/* + * Simple function which will bring our corresponding core out of reset + */ +void powerup_ib_core(unsigned cluster_id, unsigned cpu_id) +{ + unsigned rst_stat_reg = 0x0; + unsigned cpu_mask = 0x0; + void (*cold_reset_handler) (void) = 0x0; + void (*warm_reset_handler) (void) = (void (*)(void))&warm_reset; + + if (cold_reset_handler == get_reset_handler(cluster_id, cpu_id)) { + set_reset_handler(cluster_id, cpu_id, warm_reset_handler); + } else { + if (flush_ob_l2) { +#if FLUSH_L2_FIX + set_event(FLUSH_L2, cpu_id); +#endif + } + + /* + * The outbound cluster's last cpu send an event + * indicating that its finished the last switchover. + * Wait for it before bringing it's cores out of + * reset. + */ + wait_for_event(OB_SHUTDOWN, cpu_id); + reset_event(OB_SHUTDOWN, cpu_id); + } + + write_trace(&lock_tube0, SEC_TUBE0, "Powerup Inbound", read_cntpct(), + 0x0, 0x0); + + spin_lock(&lock_ib_kfscb); + rst_stat_reg = read32(KFSCB_BASE + RST_STAT0 + (cluster_id << 2)); + cpu_mask = 1 << 8 | (1 << 4) << cpu_id | 1 << cpu_id; + rst_stat_reg &= ~cpu_mask; + write32(KFSCB_BASE + RST_HOLD0 + (cluster_id << 2), rst_stat_reg); + spin_unlock(&lock_ib_kfscb); + + return; +} + +/* + * Simple function to place a core in the outbound cluster + * in reset. + */ +void powerdown_ob_core(unsigned cluster_id, unsigned cpu_id) +{ + unsigned val = 0x0; + unsigned mask = 0x0; + + get_bakery_spinlock(cpu_id, &lock_ob_kfscb); + + val = read32(KFSCB_BASE + RST_HOLD0 + (cluster_id << 2)); + mask = (1 << cpu_id) << 4; + val |= mask; + write32(KFSCB_BASE + RST_HOLD0 + (cluster_id << 2), val); + + release_bakery_spinlock(cpu_id, &lock_ob_kfscb); + + return; +} + +/* + * Simple function to the outbound cluster in reset. + */ +void powerdown_ob_cluster(unsigned cluster_id, unsigned cpu_id) +{ + unsigned val = 0x0; + unsigned mask = 0x0; + + get_bakery_spinlock(cpu_id, &lock_ob_kfscb); + + val = read32(KFSCB_BASE + RST_HOLD0 + (cluster_id << 2)); + mask = 1 << 8; + val |= mask; + write32(KFSCB_BASE + RST_HOLD0 + (cluster_id << 2), val); + + release_bakery_spinlock(cpu_id, &lock_ob_kfscb); + + return; +} + +/* + * Do not use this function for Read-Modify-Write of KFSCB registers + * as it does not hold a lock. + */ +unsigned reset_status(unsigned cluster_id, unsigned rst_level, + unsigned cpu_mask) +{ + unsigned rst_stat_reg = 0x0; + + rst_stat_reg = read32(KFSCB_BASE + RST_STAT0 + (cluster_id << 2)); + + switch (rst_level) { + case CLUSTER_RESET: + return rst_stat_reg >> 8; + case CORE_PORESET: + return ((rst_stat_reg >> 4) & 0xf) & cpu_mask; + case CORE_RESET: + return (rst_stat_reg & 0xf) & cpu_mask; + default: + return 0; + } +} + +void powerdown_cluster(void) +{ + unsigned cpu_id = read_cpuid(); + unsigned cluster_id = read_clusterid(); + unsigned secondary_mask = 0x0; + unsigned first_cpu = find_first_cpu(); + + /* + * Brute force way of cleaning the L1 and L2 caches of the outbound cluster. + * All cpus flush their L1 caches. The 'first_cpu' waits for the others to + * finish this operation before flushing the L2 + */ + write_trace(&lock_tube0, SEC_TUBE0, "L1 Flush Begin", read_cntpct(), + 0x0, 0x0); + write_sctlr(read_sctlr() & ~CR_C & ~CR_M); + dsb(); + isb(); + inv_icache_all(); + cache_maint_op(L1, CLN_INV); + disable_coherency(); + write_trace(&lock_tube0, SEC_TUBE0, "L1 Flush End", read_cntpct(), 0x0, + 0x0); + set_event(SEC_L1_DONE, cpu_id); + + if (cpu_id == first_cpu) { + + wait_for_events(SEC_L1_DONE); + + if (flush_ob_l2) { +#if FLUSH_L2_FIX + wait_for_event(FLUSH_L2, cpu_id); + reset_event(FLUSH_L2, cpu_id); +#endif + write_trace(&lock_tube0, SEC_TUBE0, "L2 Flush Begin", + read_cntpct(), 0x0, 0x0); + cache_maint_op(L2, CLN_INV); + write_trace(&lock_tube0, SEC_TUBE0, "L2 Flush End", + read_cntpct(), 0x0, 0x0); + + /* Turn off CCI snoops & DVM messages */ + if (cluster_id) + write32(A7_SL_IFACE_BASE + SNOOP_CTLR_REG, 0x0); + else + write32(A15_SL_IFACE_BASE + SNOOP_CTLR_REG, + 0x0); + + dsb(); + + /* Wait for the dust to settle down */ + while (read32(CCI_BASE + STATUS_REG) & 0x1) ; + } + + /********************* RESET HANDLING ************************************** + * Secondaries place themselves in reset while the 'first_cpu' waits for + * them to do so. + ***************************************************************************/ + + /* + * Read the L2 control to get the number of secondary + * cores present on this cluster. Shift mask by one to + * get correct mask which includes the primary + */ + secondary_mask = (1 << num_secondaries()) - 1; + secondary_mask <<= 1; + + /* Wait for other cpus to enter reset */ + while (secondary_mask != + reset_status(cluster_id, CORE_PORESET, secondary_mask)) ; + + if (flush_ob_l2) + powerdown_ob_cluster(cluster_id, cpu_id); + else + powerdown_ob_core(cluster_id, cpu_id); + + set_events(OB_SHUTDOWN); + + } else { + powerdown_ob_core(cluster_id, cpu_id); + } + + write_trace(&lock_tube0, SEC_TUBE0, "Reset Initiated", read_cntpct(), + 0x0, 0x0); + return; +} diff --git a/linaro/arm-virt-bl/big-little/secure_world/secure_world.h b/linaro/arm-virt-bl/big-little/secure_world/secure_world.h new file mode 100644 index 0000000..d466452 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/secure_world/secure_world.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __SECURE_WORLD_H__ +#define __SECURE_WORLD_H__ + +#include "hyp_types.h" +#include "virt_helpers.h" +#include "events.h" +#include "misc.h" +#include "gic_registers.h" +#include "hyp_vmmap.h" + +/* Definitions for creating a 4K page table entry */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PAGE_ALIGN(x) (x & PAGE_MASK) + +#define MB_SHIFT 20 +#define MB_SIZE (1UL << MB_SHIFT) +#define MB_MASK (~(MB_SIZE-1)) +#define MB_ALIGN(x) (x & MB_MASK) + +#define SP_L1_BASE_SHIFT 10 +#define SP_L1_BASE_MASK (~((1UL << SP_L1_BASE_SHIFT) - 1)) + +/* Definitions for first level small page descriptors */ +#define SMALL_PAGE (1 << 0) +#define SMALL_PAGE_NS (1 << 3) + +/* Definitions for second level small page descriptors */ +#define SP_XN (1 << 0) +#define SP_SBO (1 << 1) +#define SP_BUFFERABLE (1 << 2) +#define SP_CACHEABLE (1 << 3) +#define SP_AP0 (1 << 4) +#define SP_AP1 (1 << 5) +#define SP_AP2 (1 << 9) +#define SP_TEX0 (1 << 6) +#define SP_TEX1 (1 << 7) +#define SP_TEX2 (1 << 8) +#define SP_SHARED (1 << 10) +#define SP_GLOBAL (1 << 11) + +typedef struct sec_stack { + unsigned stack[STACK_SIZE]; +} sec_stack; + +typedef struct sec_context { + unsigned sctlr; + unsigned actlr; + unsigned cpacr; + unsigned nsacr; + unsigned scr; + unsigned vbar; + unsigned mvbar; + unsigned cntfrq; + unsigned cci_sar; + unsigned vgic_icdisr0; + unsigned vgic_iccpmr; +} sec_context; + +extern void enable_caches(void); +extern void secure_context_restore(void); +extern void secure_context_save(unsigned); + +#endif /* __SECURE_WORLD_H__ */ diff --git a/linaro/arm-virt-bl/big-little/secure_world/ve_reset_handler.S b/linaro/arm-virt-bl/big-little/secure_world/ve_reset_handler.S new file mode 100644 index 0000000..c4b0154 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/secure_world/ve_reset_handler.S @@ -0,0 +1,58 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + AREA |.text.test|, CODE + + ENTRY + +#if FM_BETA + IMPORT warm_reset + IMPORT ve_reset_type + + MRC p15, 0, r0, c0, c0, 5 + ANDS r0, r0, #0xf + LDR r2, =ve_reset_type + ADD r2, r2, r0, lsl #2 + LDR r1, [r2] + CMP r1, #0 + MOVEQ r1, #1 + STREQ r1, [r2] + LDREQ PC, =0x80000000 + LDRNE PC, =warm_reset + +#else /* ! FM_BETA */ + + MRC p15, 0, r0, c0, c0, 5 + UBFX r1, r0, #0, #8 + UBFX r2, r0, #8, #8 + ADD r3, r1, r2, lsl #2 + LSL r3, #3 + LDR r4, =0x60000040 + LDR r4, [r4, r3] + CMP r4, #0 + BXNE r4 + LDR pc, =0x80000000 + +#endif + + END + diff --git a/linaro/arm-virt-bl/big-little/switcher/context/gic.c b/linaro/arm-virt-bl/big-little/switcher/context/gic.c new file mode 100644 index 0000000..7686feb --- /dev/null +++ b/linaro/arm-virt-bl/big-little/switcher/context/gic.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virt_helpers.h" +#include "misc.h" + +struct set_and_clear_regs { + volatile unsigned int set[32], clear[32]; +}; + +typedef struct { + /* 0x000 */ volatile unsigned int control; + const unsigned int controller_type; + const unsigned int implementer; + const char padding1[116]; + /* 0x080 */ volatile unsigned int security[32]; + /* 0x100 */ struct set_and_clear_regs enable; + /* 0x200 */ struct set_and_clear_regs pending; + /* 0x300 */ struct set_and_clear_regs active; + /* 0x400 */ volatile unsigned int priority[256]; + /* 0x800 */ volatile unsigned int target[256]; + /* 0xC00 */ volatile unsigned int configuration[64]; + /* 0xD00 */ const char padding3[512]; + /* 0xF00 */ volatile unsigned int software_interrupt; + const char padding4[12]; + /* 0xF10 */ volatile unsigned int sgi_clr_pending[4]; + /* 0xF20 */ volatile unsigned int sgi_set_pending[4]; + const char padding5[176]; + /* 0xFE0 */ unsigned const int peripheral_id[4]; + /* 0xFF0 */ unsigned const int primecell_id[4]; +} interrupt_distributor; + +typedef struct { + /* 0x00 */ volatile unsigned int control; + /* 0x04 */ volatile unsigned int priority_mask; + /* 0x08 */ volatile unsigned int binary_point; + /* 0x0c */ volatile unsigned const int interrupt_ack; + /* 0x10 */ volatile unsigned int end_of_interrupt; + /* 0x14 */ volatile unsigned const int running_priority; + /* 0x18 */ volatile unsigned const int highest_pending; +} cpu_interface; + +static void wcpymem2io(void volatile *dest, void const *src, size_t count) +{ + unsigned long volatile *_dest = dest; + unsigned long *_src = src; + + while (count--) + *_dest++ = *_src++; +} + +static void wcpyio2mem(void *dest, void volatile const *src, size_t count) +{ + unsigned long *_src = src; + unsigned long volatile *_dest = dest; + + while (count--) + *_dest++ = *_src++; +} + +/* + * Saves the GIC CPU interface context + * Requires 3 words of memory + */ +void save_gic_interface(unsigned int *pointer, unsigned gic_interface_address) +{ + cpu_interface *ci = (cpu_interface *) gic_interface_address; + + pointer[0] = ci->control; + pointer[1] = ci->priority_mask; + pointer[2] = ci->binary_point; + +} + +/* + * Saves this CPU's banked parts of the distributor + * Returns non-zero if an SGI/PPI interrupt is pending (after saving all required context) + * Requires 19 words of memory + */ +int save_gic_distributor_private(unsigned int *pointer, + unsigned gic_distributor_address) +{ + interrupt_distributor *id = + (interrupt_distributor *) gic_distributor_address; + unsigned int *ptr = 0x0; + + *pointer = id->enable.set[0]; + ++pointer; + wcpyio2mem(pointer, id->priority, 8); + pointer += 8; + wcpyio2mem(pointer, id->target, 8); + pointer += 8; + + /* Save just the PPI configurations (SGIs are not configurable) */ + *pointer = id->configuration[1]; + ++pointer; + + /* + * Private peripheral interrupts need to be replayed on + * the destination cpu interface for consistency. This + * is the responsibility of the peripheral driver. When + * it sees a pending interrupt while saving its context + * it should record enough information to recreate the + * interrupt while restoring. + * We don't save the Pending/Active status and clear it + * so that it does not interfere when we are back. + */ + id->pending.clear[0] = 0xffffffff; + id->active.clear[0] = 0xffffffff; + + /* + * IPIs are different and can be replayed just by saving + * and restoring the set/clear pending registers + */ + ptr = pointer; + wcpyio2mem(pointer, id->sgi_set_pending, 4); + pointer += 8; + + /* + * Clear the pending SGIs on this cpuif so that they don't + * interfere with the wfi later on. + */ + wcpymem2io(id->sgi_clr_pending, ptr, 4); + + if (*pointer) { + return -1; + } else { + return 0; + } +} + +/* + * Saves the shared parts of the distributor + * Requires 1 word of memory, plus 20 words for each block of 32 SPIs (max 641 words) + * Returns non-zero if an SPI interrupt is pending (after saving all required context) + */ +int save_gic_distributor_shared(unsigned int *pointer, + unsigned gic_distributor_address) +{ + int retval = 0; + interrupt_distributor *id = + (interrupt_distributor *) gic_distributor_address; + unsigned num_spis = 0; + + /* Calculate how many SPIs the GIC supports */ + num_spis = 32 * (id->controller_type & 0x1f); + + /* Save rest of GIC configuration */ + if (num_spis) { + wcpyio2mem(pointer, id->target + 8, num_spis / 4); + pointer += num_spis / 4; + } + + /* Save control register */ + *pointer = id->control; + ++pointer; + + return retval; +} + +void restore_gic_interface(unsigned int *pointer, + unsigned gic_interface_address) +{ + cpu_interface *ci = (cpu_interface *) gic_interface_address; + + ci->priority_mask = pointer[1]; + ci->binary_point = pointer[2]; + + /* Restore control register last */ + ci->control = pointer[0]; +} + +void restore_gic_distributor_private(unsigned int *pointer, + unsigned gic_distributor_address) +{ + interrupt_distributor *id = + (interrupt_distributor *) gic_distributor_address; + unsigned ctr, prev_val = 0, prev_ctr = 0; + + id->enable.set[0] = *pointer; + ++pointer; + + wcpymem2io(id->priority, pointer, 8); + pointer += 8; + wcpymem2io(id->target, pointer, 8); + pointer += 8; + + /* Restore just the PPI configurations (SGIs are not configurable) */ + id->configuration[1] = *pointer; + ++pointer; + + /* + * Clear active and pending PPIs as they will be recreated by the + * peripiherals + */ + id->active.clear[0] = 0xffffffff; + id->pending.clear[0] = 0xffffffff; + + /* + * Restore pending IPIs + */ + for (ctr = 0; ctr < 4; ctr++) { + if (!pointer[ctr]) + continue; + + if (pointer[ctr] == prev_val) { + pointer[ctr] = pointer[prev_ctr]; + } else { + prev_val = pointer[ctr]; + prev_ctr = ctr; + remap_cpuif(&pointer[ctr]); + } + } + + wcpymem2io(id->sgi_set_pending, pointer, 4); + pointer += 4; + + id->pending.set[0] = *pointer; + + return; +} + +/* + * Optimized routine to restore the shared vgic distributor interface. + * Saving on outbound and restoring on inbound is redundant as the + * context is non-volatile across a switch. Hence, simply R-M-W on + * the inbound and remove the 'save' function from the outbound + * critical path. + */ +void restore_gic_distributor_shared(unsigned int *pointer, + unsigned gic_distributor_address) +{ + interrupt_distributor *id = + (interrupt_distributor *) gic_distributor_address; + unsigned num_spis; + unsigned ctr, prev_val = 0, prev_ctr = 0; + + /* Calculate how many SPIs the GIC supports */ + num_spis = 32 * ((id->controller_type) & 0x1f); + + /* Restore rest of GIC configuration */ + if (num_spis) { + wcpyio2mem(pointer, id->target + 8, num_spis / 4); + + for (ctr = 0; ctr < num_spis / 4; ctr++) { + if (!pointer[ctr]) + continue; + + if (pointer[ctr] == prev_val) { + pointer[ctr] = pointer[prev_ctr]; + } else { + prev_val = pointer[ctr]; + prev_ctr = ctr; + remap_cpuif(&pointer[ctr]); + } + } + + wcpymem2io(id->target + 8, pointer, num_spis / 4); + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/switcher/context/ns_context.c b/linaro/arm-virt-bl/big-little/switcher/context/ns_context.c new file mode 100644 index 0000000..9633b3b --- /dev/null +++ b/linaro/arm-virt-bl/big-little/switcher/context/ns_context.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virt_helpers.h" +#include "vgiclib.h" +#include "gic_registers.h" +#include "int_master.h" +#include "context.h" +#include "bl.h" +#include "misc.h" +#include "events.h" +#include "virtualisor.h" +#include "helpers.h" + +#ifndef USE_HYP_TIMERS +#define USE_HYP_TIMERS 0 +#endif +#ifndef ASYNC_SWITCH +#define ASYNC_SWITCH 0 +#endif + +extern void gic_enable_int(unsigned); +extern void SetupVGIC(unsigned); + +/* Bakery locks to serialize access to the tube. */ +static bakery_t lock_tube0 __attribute__ ((section(".data.BL_DV_PAGE"))) = { +0}; + +static bakery_t lock_tube1 __attribute__ ((section(".data.BL_DV_PAGE"))) = { +0}; + +/* + * Top level structure which encapsulates the context of the entire + * Kingfisher system + */ +system_context switcher_context = { 0 }; + +void stop_generic_timer(generic_timer_context * ctr_ctx) +{ + /* + * Disable the timer and mask the irq to prevent + * suprious interrupts on this cpu interface. It + * will bite us when we come back if we don't. It + * will be replayed on the inbound cluster. + */ + write_cntp_ctl(TIMER_MASK_IRQ); + + /* + * If the local timer interrupt was being used as + * the asynchronous trigger, then it was disabled + * in handle_interrupt() to prevent this level- + * triggerred interrupt from firing. Now that its + * been acked at the peripheral. We can renable it + */ + if (!USE_HYP_TIMERS) { + if (ctr_ctx->cntp_ctl & TIMER_IRQ_STAT) + gic_enable_int(LCL_TIMER_IRQ); + } + + return; +} + +void save_context(unsigned first_cpu) +{ + unsigned cpu_id = read_cpuid(); + unsigned cluster_id = read_clusterid(); + cpu_context *ns_cpu_ctx = + &switcher_context.cluster.core[cpu_id].ns_cpu_ctx; + unsigned *pmon_context = ns_cpu_ctx->pmon_regs; + unsigned *gp_context = ns_cpu_ctx->banked_cpu_regs; + unsigned *vfp_context = ns_cpu_ctx->vfp_regs; + banked_cp15_context *cp15_context = &ns_cpu_ctx->banked_cp15_regs; + gic_cpu_context *gic_pvt_context = &ns_cpu_ctx->gic_cpu_ctx; + generic_timer_context *cp15_timer_ctx = &ns_cpu_ctx->cp15_timer_ctx; + cp15_fault_regs *fault_ctx = &cp15_context->ns_cp15_fault_regs; + + write_trace(&lock_tube0, NS_TUBE0, "Context Save Start", read_cntpct(), + 0x0, 0x0); + + /* + * Good place to bring the inbound cluster out of reset, but first + * we need to save the secure world context. + */ + write_trace(&lock_tube0, NS_TUBE0, "Secure Context Save Start", + read_cntpct(), 0x0, 0x0); + smc(SMC_SEC_SAVE, (unsigned)hyp_warm_reset_handler); + write_trace(&lock_tube0, NS_TUBE0, "Secure Context Save End", + read_cntpct(), 0x0, 0x0); + + /* + * Save the 32-bit Generic timer context & stop them + */ + save_generic_timer((unsigned *)cp15_timer_ctx, 0x1); + stop_generic_timer(cp15_timer_ctx); + + /* + * Save v7 generic performance monitors + * Save cpu general purpose banked registers + * Save cp15 context + */ + save_performance_monitors(pmon_context); + save_banked_registers(gp_context); + save_cp15(cp15_context->cp15_misc_regs); + save_control_registers(cp15_context->cp15_ctrl_regs, 0x0); + save_mmu(cp15_context->cp15_mmu_regs); + save_fault_status((unsigned *)fault_ctx); + + /* + * Check if non-secure world has access to the vfp/neon registers + * and save them if so. + */ + if (read_nsacr() & (0x3 << 10)) + save_vfp(vfp_context); + + /* + * Disable the GIC CPU interface tp prevent interrupts from waking + * the core from wfi() subsequently. + */ + write32(GIC_IC_PHY_BASE + GICC_CTL, 0x0); + + /* Save vGIC virtual cpu interface (cpu view) context */ + save_gic_interface(gic_pvt_context->gic_cpu_if_regs, VGIC_VM_PHY_BASE); + + /* + * Save the HYP view registers. These registers contain a snapshot + * of all the physical interrupts acknowledged till we + * entered this HYP mode. + */ + vgic_savestate(cpu_id); + + /* + * TODO: + * Is it safe for the secondary cpu to save its context + * while the GIC distributor is on. Should be as its + * banked context and the cpu itself is the only one + * who can change it. Still have to consider cases e.g + * SGIs/Localtimers becoming pending. + */ + save_gic_distributor_private(gic_pvt_context->gic_dist_if_pvt_regs, + GIC_ID_PHY_BASE); + + /* Safe place to save the Virtualisor context */ + SaveVirtualisor(first_cpu); + + /* + * Indicate to the inbound side that the context has been saved and is ready + * for pickup. + */ + write_trace(&lock_tube0, NS_TUBE0, "Context Save End", read_cntpct(), + 0x0, 0x0); + set_event(OB_CONTEXT_DONE, cpu_id); + + /* + * Now, we wait for the inbound cluster to signal that its done atleast picking + * up the saved context. + */ + if (cpu_id == first_cpu) { + wait_for_events(IB_CONTEXT_DONE); + write_trace(&lock_tube0, NS_TUBE0, "Inbound done", + read_cntpct(), 0x0, 0x0); + } + + return; +} + +void restore_context(unsigned first_cpu) +{ + unsigned cpu_id = read_cpuid(); + unsigned cluster_id = read_clusterid(); + unsigned warm_reset = 1; + cpu_context *ns_cpu_ctx = + &switcher_context.cluster.core[cpu_id].ns_cpu_ctx; + global_context *gbl_context = &switcher_context.cluster.ns_cluster_ctx; + unsigned *pmon_context = ns_cpu_ctx->pmon_regs; + unsigned *gp_context = ns_cpu_ctx->banked_cpu_regs; + unsigned *vfp_context = ns_cpu_ctx->vfp_regs; + gic_cpu_context *gic_pvt_context = &ns_cpu_ctx->gic_cpu_ctx; + generic_timer_context *cp15_timer_ctx = &ns_cpu_ctx->cp15_timer_ctx; + banked_cp15_context *cp15_context = &ns_cpu_ctx->banked_cp15_regs; + cp15_fault_regs *fault_ctx = &cp15_context->ns_cp15_fault_regs; + vm_context *src = 0x0; + vm_context *dest = 0x0; + unsigned dest_cpuif = 0x0; + unsigned src_cpuif = 0x0; + + /* + * Map cpuids to cpu interface numbers so that cpu interface + * specific context can be correctly restored on the external + * vGIC. + */ + map_cpuif(cluster_id, cpu_id); + SetupVGIC(warm_reset); + + /* + * Inbound headstart i.e. the vGIC configuration, secure context + * restore & cache invalidation has been done. Now wait for the + * outbound to provide the context. + */ + write_trace(&lock_tube1, NS_TUBE1, "Wait for context", read_cntpct(), + 0x0, 0x0); + wait_for_event(OB_CONTEXT_DONE, cpu_id); + reset_event(OB_CONTEXT_DONE, cpu_id); + + /* + * First cpu restores the global context while the others take + * care of their own. + */ + write_trace(&lock_tube1, NS_TUBE1, "Context Restore Start ", + read_cntpct(), 0x0, 0x0); + if (cpu_id == first_cpu) + restore_gic_distributor_shared(gbl_context->gic_dist_if_regs, + GIC_ID_PHY_BASE); + restore_gic_distributor_private(gic_pvt_context->gic_dist_if_pvt_regs, + GIC_ID_PHY_BASE); + vgic_loadstate(cpu_id); + + SetupVirtualisor(first_cpu); + + /* Restore NS VGIC context */ + restore_gic_interface(gic_pvt_context->gic_cpu_if_regs, + VGIC_VM_PHY_BASE); + + /* + * Check if non-secure world has access to the vfp/neon registers + * and save them if so. + */ + if (read_nsacr() & (0x3 << 10)) + restore_vfp(vfp_context); + + /* + * Restore cp15 context + * Restore cpu general purpose banked registers + * Restore v7 generic performance monitors + * Restore the 32-bit Generic timer context + */ + restore_fault_status((unsigned *)fault_ctx); + restore_mmu(cp15_context->cp15_mmu_regs); + restore_control_registers(cp15_context->cp15_ctrl_regs, 0x0); + restore_cp15(cp15_context->cp15_misc_regs); + restore_banked_registers(gp_context); + restore_performance_monitors(pmon_context); + restore_generic_timer((unsigned *)cp15_timer_ctx, 0x1); + + /* + * Paranoid check to ensure that all HYP/Secure context & Virtualisor + * is restored before any core enters the non-secure mode to use it. + */ + if (cpu_id == first_cpu) { + set_events(HYP_CONTEXT_DONE); + } + wait_for_event(HYP_CONTEXT_DONE, cpu_id); + reset_event(HYP_CONTEXT_DONE, cpu_id); + + /* + * Return the saved general purpose registers saved above the HYP mode + * stack of our counterpart cpu on the other cluster. + */ + dest_cpuif = get_cpuif(cluster_id, cpu_id); + src_cpuif = get_cpuif(!cluster_id, cpu_id); + dest = &guestos_state[dest_cpuif].context; + src = &guestos_state[src_cpuif].context; + + dest->gp_regs[0] = src->gp_regs[0]; + dest->gp_regs[1] = src->gp_regs[1]; + dest->gp_regs[2] = src->gp_regs[2]; + dest->gp_regs[3] = src->gp_regs[3]; + dest->gp_regs[4] = src->gp_regs[4]; + dest->gp_regs[5] = src->gp_regs[5]; + dest->gp_regs[6] = src->gp_regs[6]; + dest->gp_regs[7] = src->gp_regs[7]; + dest->gp_regs[8] = src->gp_regs[8]; + dest->gp_regs[9] = src->gp_regs[9]; + dest->gp_regs[10] = src->gp_regs[10]; + dest->gp_regs[11] = src->gp_regs[11]; + dest->gp_regs[12] = src->gp_regs[12]; + dest->gp_regs[13] = src->gp_regs[13]; + dest->gp_regs[14] = src->gp_regs[14]; + dest->elr_hyp = src->elr_hyp; + dest->spsr = src->spsr; + dest->usr_lr = src->usr_lr; + + write_trace(&lock_tube1, NS_TUBE1, "Context Restore End", read_cntpct(), + 0x0, 0x0); + set_event(IB_CONTEXT_DONE, cpu_id); + + if (ASYNC_SWITCH && cpu_id == first_cpu) + enable_trigger(read_cntfrq()); + + return; +} diff --git a/linaro/arm-virt-bl/big-little/switcher/context/sh_vgic.c b/linaro/arm-virt-bl/big-little/switcher/context/sh_vgic.c new file mode 100644 index 0000000..3f5eb98 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/switcher/context/sh_vgic.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virt_helpers.h" +#include "gic_registers.h" +#include "misc.h" +#include "context.h" + +/* + * Private data structure that maps each cpuid in a + * multicluster system to its physical cpu interface + * id when a shared vGIC is used. + */ +static unsigned int cpuif_map[MAX_CLUSTERS][MAX_CORES]; + +/* + * Private data structure that maps each cpu interface + * id to the corresponding cpuid & clusterid. In each + * entry top 4 bits store the cluster id while the bottom + * 4 store the cpuid. + * + * TODO: + * No real need for this data structure. Should be + * possible to get this info from the previous data + * structure and the knowledge of number of clusters + * and cpus from the KFSCB + */ +static unsigned int cpuinfo_map[MAX_CPUIFS]; + +/* + * IPI to use for cpu interface discovery. + */ +#define CPUIF_IPI 0xf + +/* + * In the presence of the Switcher and the shared vGIC + * find the mapping between the cpu interface and the + * cpu id. This is required to: + * a) Set processor targets correctly during context + * save & restore and normal operation (IPI handling) + * b) Restoring the context of pending IPIs on the inbound + * cluster. + * Ideally a platform defined register should have done the + * trick. However, we rely on a software mechanism to obtain + * this information. + * + * Assumptions: + * a) Expected to be used only in the "Switching" case when + * there is a mismatch between the cpuids and the cpuif ids + * on the "other" cluster + * b) In the "Switching" case with external vGIC, the distributor + * interface should never get disabled. + * c) Always called in Secure world + * + * Idea is that, without disturbing the existing GIC state too + * much (outbound might be doing things with it), we need to + * ensure that only the IPI which we choose gets through our + * cpu interface. This should not be a problem as the SPIs will + * be targetted to the outbound cluster cpus & there will be no + * local peripheral interrupts expected. There is paranoia about + * getting IPIs from the outbound but this can be dealt with by + * manipulating the IPI priorities so that we only see what we + * want to see. + * + * TODO: + * Assuming no IPIs will be received at this point of time. So + * no changes will be made to the priority mask registers. + */ +unsigned map_cpuif(unsigned cluster_id, unsigned cpu_id) +{ + unsigned cpuif_id = 0; + + cpuif_id = bitindex(read32(GIC_ID_PHY_BASE + GICD_CPUS) & 0xff); + cpuif_map[cluster_id][cpu_id] = cpuif_id; + cpuinfo_map[cpuif_id] = (cluster_id << 4) | cpu_id; + + return 0; +} + +/* + * Given a cpu and cluster id find the cpu interface it maps to. + */ +unsigned get_cpuif(unsigned cluster_id, unsigned cpu_id) +{ + return cpuif_map[cluster_id][cpu_id]; +} + +/* + * Given a cpu interface id, find what cpu and cluster id it maps to. + */ +unsigned get_cpuinfo(unsigned cpuif) +{ + return cpuinfo_map[cpuif]; +} + +/* + * Given a cpu interface mask, find the corresponding cpuid mask on that cluster. + */ +unsigned get_cpu_mask(unsigned cpuif_mask) +{ + unsigned num_bytes = sizeof(unsigned int) / sizeof(unsigned char), ctr; + unsigned cpuif = 0, clusterid = read_clusterid(), cpu_mask = 0; + unsigned cpuid = 0; + + for (ctr = 0; ctr < num_bytes; ctr++) { /* Iterate through the cpu_mask byte wise */ + unsigned byte = 0; + unsigned char lz = 0; + + byte = (cpuif_mask >> (ctr << 3)) & 0xff; + while ((lz = __builtin_clz(byte)) != 0x20) { + cpuif = 31 - lz; + byte &= ~(1 << cpuif); /* Clear the bit just discovered */ + cpuid = get_cpuinfo(cpuif) & 0xf; + cpu_mask |= (1 << cpuid) << (ctr << 3); + } + } + + return cpu_mask; +} + +/* + * Given a cpu mask, find the corresponding cpu interface mask on that cluster. + */ +unsigned get_cpuif_mask(unsigned cpu_mask) +{ + unsigned num_bytes = sizeof(unsigned int) / sizeof(unsigned char), ctr; + unsigned cpuif = 0, clusterid = read_clusterid(), cpuif_mask = 0; + unsigned cpuid = 0; + + for (ctr = 0; ctr < num_bytes; ctr++) { /* Iterate through the cpu_mask byte wise */ + unsigned byte = 0; + unsigned char lz = 0; + + byte = (cpu_mask >> (ctr << 3)) & 0xff; + while ((lz = __builtin_clz(byte)) != 0x20) { + cpuid = 31 - lz; + byte &= ~(1 << cpuid); /* Clear the bit just discovered */ + cpuif = get_cpuif(clusterid, cpuid); + cpuif_mask |= (1 << cpuif) << (ctr << 3); + } + } + + return cpuif_mask; +} + +/* + * Given a cpu interface mask, find its corresponding mask on the other cluster + * NOTE: Creates the new mask in-place. + */ +#if 1 +/* + * This is the fast version of remapping cpu interface ids to cpuids. Instead of + * remapping each bit (target interface) in the arg passed, it simply shifts all + * the bits by the number of cpus available. + */ +unsigned remap_cpuif(unsigned *cpuif_mask) +{ + unsigned cluster_id = read_clusterid(), num_cpus = + num_secondaries() + 1; + + if (cluster_id == EAGLE) + *cpuif_mask = *cpuif_mask >> num_cpus; + else + *cpuif_mask = *cpuif_mask << num_cpus; + + return 0; +} +#else +unsigned remap_cpuif(unsigned *cpuif_mask) +{ + unsigned ib_cpuif_mask = 0, ob_cpuif = 0, ib_cpuif = 0, ob_cpuid = + 0, ob_clusterid = 0, ib_cpuid = 0, ib_clusterid = 0; + unsigned num_bytes = sizeof(unsigned int) / sizeof(unsigned char), ctr; + + for (ctr = 0; ctr < num_bytes; ctr++) { + unsigned byte = 0; + unsigned char lz = 0; + + byte = (*cpuif_mask >> (ctr << 3)) & 0xff; + + while ((lz = __builtin_clz(byte)) != 0x20) { + ob_cpuif = 31 - lz; + byte &= ~(1 << ob_cpuif); /* Clear the bit just discovered */ + ob_cpuid = get_cpuinfo(ob_cpuif) & 0xf; + ob_clusterid = (get_cpuinfo(ob_cpuif) >> 4) & 0xf; + + /* + * TODO: Can we assume that the inbound and outbound clusters will + * always be logical complements of each other + */ + ib_clusterid = !ob_clusterid; + + /* + * TODO: Assuming that the cpuids have a 1:1 mapping i.e. cpuX on + * one cluster will always map to cpuX on the other cluster. + */ + ib_cpuid = ob_cpuid; + ib_cpuif = get_cpuif(ib_clusterid, ib_cpuid); + ib_cpuif_mask |= (1 << ib_cpuif) << (ctr << 3); + } + } + + *cpuif_mask = ib_cpuif_mask; + return 0; +} +#endif diff --git a/linaro/arm-virt-bl/big-little/switcher/trigger/async_switchover.c b/linaro/arm-virt-bl/big-little/switcher/trigger/async_switchover.c new file mode 100644 index 0000000..dc2bd04 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/switcher/trigger/async_switchover.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include <stdio.h> +#include "virt_helpers.h" +#include "misc.h" +#include "gic_registers.h" + +extern void gic_enable_int(unsigned); +extern void gic_disable_int(unsigned); +extern void gic_send_ipi(unsigned, unsigned); +extern void gic_eoi_int(unsigned); +extern void gic_deactivate_int(unsigned); +/* + * Set of flags used by the interrupt handling code + * to distinguish between IPIs sent by the big-little + * code and the payload software. + * TODO: Assumes only one cpu will send an IPI at a + * time rather than multiple cpus sending the same + * IPI to each other at the same time from within the + * HYP mode. + */ +static unsigned lock_ipi_check; +static unsigned hyp_ipi_check[16]; +static unsigned timer_count; +/* Support for the switchover interval randomly but sanely */ +#ifndef RAND_ASYNC +#define RAND_ASYNC 0 +#endif +/* Use HYP timer for async switches */ +#ifndef USE_HYP_TIMERS +#define USE_HYP_TIMERS 0 +#endif + +/* + * Returns the id of the first IPI that is not pending on + * our cpu interface or the first IPI that is pending but + * was not generated by us. Returns 16 if no such IPI is + * found + */ +static unsigned get_free_ipi(void) +{ + unsigned ctr, shift, cpu_if_bit, cpu_id = read_cpuid(), cluster_id = + read_clusterid(); + + cpu_if_bit = 1 << get_cpuif(cluster_id, cpu_id); + + /* Find the register offset */ + for (ctr = 0; ctr < 4; ctr++) + /* Check whether IPI<shift> has already been generated by us */ + for (shift = 0; shift < 4; shift++) { + if (read32 + (GIC_ID_PHY_BASE + GICD_SPENDSGIR + + (ctr << 2)) & (cpu_if_bit << (shift << 3))) + continue; + + return (ctr << 2) + shift; + } + + return 16; +} + +static void ack_trigger(void) +{ + unsigned ctl = 0; + + ctl = read_cnthp_ctl(); + if (ctl & TIMER_IRQ_STAT) { + /* Disable timer and mask interrupt */ + write_cnthp_ctl(TIMER_MASK_IRQ); + } else { + printf("Spurious HYP timer irq \n"); + panic(); + } + + return; +} + +/* + * Broadcast first available IPI so that all cpus can start switching to + * the other cluster. + */ +void signal_switchover(void) +{ + unsigned ipi_no = 0x0; + + /* If x is the no. of cpus then corresponding mask would be (1 << x) - 1 */ + unsigned cpu_mask = (1 << (num_secondaries() + 1)) - 1; + /* + * Map the target cpuids to their cpu interfaces as the 1:1 mapping + * no longer exists with the external vGIC. + */ + unsigned cpuif_mask = get_cpuif_mask(cpu_mask); + + /* + * Send an ipi to all the cpus in the cluster including ourselves + * to start a switch to the inbound cluster. First choose a non- + * pending IPI to avoid a clash with the OS. + */ + ipi_no = get_free_ipi(); + + /* + * For this IPI set the mask in our global variable. We do it, payload software + * does not. But, first check whether any earlier IPIs have already been acked + */ + while (hyp_ipi_check[ipi_no]) ; + spin_lock(&lock_ipi_check); + hyp_ipi_check[ipi_no] = cpuif_mask; + dsb(); + spin_unlock(&lock_ipi_check); + + /* Send the IPI to the cpu_mask */ + gic_send_ipi(cpuif_mask, ipi_no); + + return; +} + +unsigned check_switchover_ipi(unsigned cpu_if, unsigned ipi_no) +{ + unsigned rc = FALSE; + + spin_lock(&lock_ipi_check); + /* + * If this IPI was sent by the big-little code then our cpu_if bit must have + * been set in the ipi_check flag. Reset the bit an indicate that its an + * internal IPI. + */ + if (hyp_ipi_check[ipi_no] & (1 << cpu_if)) { + rc = TRUE; + hyp_ipi_check[ipi_no] &= ~(1 << cpu_if); + dsb(); + } + spin_unlock(&lock_ipi_check); + + return rc; +} + +unsigned check_trigger(unsigned int_id, unsigned int_ack) +{ + unsigned cpuid = read_cpuid(); + unsigned platform = (read32(KFSCB_BASE + KFS_ID) >> 20) & 0xf; + + /* + * If we are not using HYP mode timers for triggering a switchover + * then check whether this is a suitable local timer interrupt to + * switch + */ + if (!USE_HYP_TIMERS) { + /* + * We need to hijack every 128th timer interrupt on cpu0 and + * use it as a stimulus to switchover + */ + if (cpuid == 0 && int_id == LCL_TIMER_IRQ) + timer_count++; + + if (timer_count & LCL_TIMER_FREQ) + return FALSE; + } + /* + * Trigger a switchover upon getting a HYP timer IRQ. Its + * targetted only to cpu0. + */ + else if (int_id != HYP_TIMER_IRQ) + return FALSE; + + /* + * Do the needful now that it is confirmed that we need to move + * to the other cluster + */ + + /* Indicator on emulation that switches are actually taking place */ + if (platform != 0x1) + printf("%d", read_clusterid()); + + /* + * Send an IPI to all the cores in this cluster to start + * a switchover. + */ + signal_switchover(); + + if (USE_HYP_TIMERS) + ack_trigger(); + else + /* + * Complete handling of the local timer interrupt at the physical gic + * level. Its disabled as its level triggerred and will reassert as + * soon as we leave this function since its not been cleared at the + * peripheral just yet. The local timer context is saved and this irq + * cleared in "save_hyp_context". The interrupt is enabled then. + */ + gic_disable_int(int_id); + + /* Finish handling this interrupt */ + gic_eoi_int(int_ack); + if (read32(GIC_IC_PHY_BASE + GICC_CTL) & 0x200) + gic_deactivate_int(int_ack); + + return TRUE; +} + +void keep_trigger_alive(void) +{ + /* + * The OS might have disabled the HYP timer interrupt + * while setting up its view of the vGIC. So enable + * it if disabled upon receiving any other interrupt. + * Better than virtualising vGIC accesses on the TARGET + * CPU. + */ + if (USE_HYP_TIMERS) + if (! + (read32(GIC_ID_PHY_BASE + GICD_ENABLESET) & + (1 << HYP_TIMER_IRQ))) + gic_enable_int(HYP_TIMER_IRQ); + + return; +} + +void enable_trigger(unsigned tval) +{ + unsigned ctl = TIMER_ENABLE; + unsigned platform = read32((KFSCB_BASE + KFS_ID) >> 20) & 0xf; + + /* + * No need to lock this as its accessed by only one cpu + * per cluster and that too one at a time. + */ + unsigned rand_no; + + /* + * Nothing needs to be done if physical local timers + * are being used for doing a switchover. + */ + if (USE_HYP_TIMERS) { + if (RAND_ASYNC) { + static uint64_t rand_val = 0xdeadbeef; + rand_val = (0x5deece66dULL * rand_val) + 0xb; + rand_no = rand_val >> 16; + } + + /* Enable timer and unmask interrupt */ + write_cnthp_ctl(ctl); + + if (RAND_ASYNC) { + unsigned interval; + + /* + * TODO: Assuming that the tval is always 12000000 + * Increment or decrement the timer value randomly + * but never by more than a factor of 10 + */ + if (rand_no % 2) + interval = tval * (rand_no % 10); + else + interval = tval / (rand_no % 10); + + write_cnthp_tval(interval); + + } else { + /* + * Program the timer to fire every 12000000 instructions + * on the FastModel while 1500000 cycles on the Emulator + */ + if (platform == 0x1) + write_cnthp_tval(tval); + else + write_cnthp_tval(tval >> 3); + } + + gic_enable_int(HYP_TIMER_IRQ); + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/switcher/trigger/handle_switchover.S b/linaro/arm-virt-bl/big-little/switcher/trigger/handle_switchover.S new file mode 100755 index 0000000..f7d013f --- /dev/null +++ b/linaro/arm-virt-bl/big-little/switcher/trigger/handle_switchover.S @@ -0,0 +1,61 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + AREA |.text.SwitchoverCode|, CODE, READONLY, ALIGN=5 + + PRESERVE8 + + IMPORT save_context + IMPORT smc + EXPORT switch_cluster + +SMC_SEC_SHUTDOWN EQU 0x2 + + ; ---------------------------------------------------- + ; This function directs the switchover to the inbound + ; cluster. The context is first saved, stacks switched + ; & the cluster is powered down. + ; We need to switch stacks from being resident in normal + ; WBWA/S memory to SO memory to prevent potential stack + ; corruption after turning off the C bit in the HSCTLR. + ; Subsequent accesses will be SO while there will be + ; valid cache lines of the stack from prior accesses + ; ---------------------------------------------------- +switch_cluster FUNCTION + ; ---------------------------------------------------- + ; We don't push any registers on the stack as we are + ; not going to return from this function + ; ---------------------------------------------------- + MOV r4, r0 + BL save_context + ; ---------------------------------------------------- + ; We are now through with saving the context and the + ; inbound cluster has started picking it up. Switch to + ; the secure world to clean the caches and power down + ; the cluster + ; ---------------------------------------------------- + MOV r0, #SMC_SEC_SHUTDOWN + BL smc + ENDFUNC + + END + diff --git a/linaro/arm-virt-bl/big-little/switcher/trigger/sync_switchover.c b/linaro/arm-virt-bl/big-little/switcher/trigger/sync_switchover.c new file mode 100644 index 0000000..e8d8e99 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/switcher/trigger/sync_switchover.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "misc.h" +#include "virt_helpers.h" +#include "bl.h" + +extern void signal_switchover(void); + +unsigned is_hvc() +{ + return ((read_hsr() >> 26) == 0x12 ? TRUE : FALSE); +} + +unsigned HandleHVC(vm_context * context) +{ + unsigned opcode = read_hsr() & 0xffff; + unsigned rc = FALSE; + + switch (opcode) { + + /* + * HVC call to switch to the other cluster. This is done + * by sending a switchover IPI to all the cores in the cluster. + */ + case SYNC_SWITCHOVER: + signal_switchover(); + rc = TRUE; + break; + + /* + * HVC call to return the physical MPIDR + */ + case READ_MPIDR: + context->gp_regs[0] = read_mpidr(); + rc = TRUE; + break; + + default: + break; + + } + + return rc; +} diff --git a/linaro/arm-virt-bl/big-little/virtualisor/cache_geom.c b/linaro/arm-virt-bl/big-little/virtualisor/cache_geom.c new file mode 100644 index 0000000..f156d6d --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/cache_geom.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virtualisor.h" +#include "virt_helpers.h" +#include "misc.h" +#include "context.h" +#include "cache_geom.h" +#include "events.h" + +#ifndef SWITCHER +#define SWITCHER 0 +#endif +#ifndef CMOP_DEBUG +#define CMOP_DEBUG 0 +#endif + +cache_stats cm_op_stats[NUM_CPUS][MAX_CACHE_LEVELS]; +static unsigned tc_prev_line[NUM_CPUS][MAX_CACHE_LEVELS] = { 0 }; +static unsigned cm_line_cnt[NUM_CPUS][MAX_CACHE_LEVELS] = { 0xffffffff }; +static unsigned hc_line_cnt[NUM_CPUS][MAX_CACHE_LEVELS] = { 0 }; +static unsigned cm_ignline_cnt[NUM_CPUS][MAX_CACHE_LEVELS] = { 0 }; +static unsigned cm_extline_cnt[NUM_CPUS][MAX_CACHE_LEVELS] = { 0 }; + +/* + * Iterate through all the implemented cache + * levels and save the geometry at each level. + * + */ +void find_cache_geometry(cache_geometry * cg_ptr) +{ + unsigned ctr, clidr, ccsidr, csselr, old_csselr; + + /* Save Cache size selection register */ + old_csselr = read_csselr(); + clidr = read_clidr(); + cg_ptr->clidr = clidr; + + for (ctr = 0; ctr < MAX_CACHE_LEVELS; ctr++) { + unsigned cache_type = get_cache_type(clidr, ctr); + + /* Only seperate and Unifiied caches */ + if (cache_type >= 0x3) { + /* + * Choose the cache level & Data or Unified cache + * as there are no set/way operations on the ICache + */ + csselr = ctr << 1; + write_csselr(csselr); + + isb(); + + /* + * Read the CCSIDR to record information about this + * cache level. + */ + ccsidr = read_ccsidr(); + cg_ptr->ccsidr[ctr] = ccsidr; + + } else { + /* + * Stop scanning at the first invalid/unsupported + * cache level + */ + break; + } + } + + /* Restore Cache size selection register */ + write_csselr(old_csselr); + return; +} + +/* + * Given two cache geometries, find out how they differ + */ +void find_cache_diff(cache_geometry * hcg_ptr, cache_geometry * tcg_ptr, + cache_diff * cd_ptr) +{ + unsigned tc_size = 0, hc_size = 0, tc_linelen = 0, hc_linelen = 0; + unsigned tc_assoc = 0, hc_assoc = 0, tc_numsets = 0, hc_numsets = 0; + unsigned ctr; + + for (ctr = 0; ctr < MAX_CACHE_LEVELS; ctr++) { + + /* Break at the first unimplemented cache level */ + if (get_cache_type(hcg_ptr->clidr, ctr) == 0) + break; + + /* Cache associativity */ + tc_assoc = get_cache_assoc(tcg_ptr, ctr) + 1; + hc_assoc = get_cache_assoc(hcg_ptr, ctr) + 1; + + /* Number of the sets in the cache */ + tc_numsets = get_cache_numsets(tcg_ptr, ctr) + 1; + hc_numsets = get_cache_numsets(hcg_ptr, ctr) + 1; + + /* Cache line length in words */ + tc_linelen = 1 << (get_cache_linesz(tcg_ptr, ctr) + 2); + hc_linelen = 1 << (get_cache_linesz(hcg_ptr, ctr) + 2); + + /* Cache size in words */ + tc_size = tc_assoc * tc_numsets * tc_linelen; + hc_size = hc_assoc * hc_numsets * hc_linelen; + + /* + * Find the factor by which the cache line sizes differ. + * If so, then the target cacheline will have to be + * multiplied or divided by the factor to get the absolute + * cache line number. Then, find the number of absolute + * cache lines in each cache + */ + if (tc_linelen >= hc_linelen) { + cd_ptr[ctr].tcline_factor = tc_linelen / hc_linelen; + cd_ptr[ctr].tnumabs_clines = + tc_assoc * tc_numsets * cd_ptr[ctr].tcline_factor; + cd_ptr[ctr].hnumabs_clines = hc_assoc * hc_numsets; + } else { + cd_ptr[ctr].hcline_factor = hc_linelen / tc_linelen; + cd_ptr[ctr].hnumabs_clines = + hc_assoc * hc_numsets * cd_ptr[ctr].hcline_factor; + cd_ptr[ctr].tnumabs_clines = tc_assoc * tc_numsets; + } + + /* + * Find if the cache sizes differ. If so, then set a flag + * to indicate whether some set/way operations need to be + * extended on the host cpu or ignored on the target cpu + */ + if (tc_size > hc_size) { + cd_ptr[ctr].csize_diff = TCSZ_BIG; + } + + if (tc_size == hc_size) { + cd_ptr[ctr].csize_diff = TCSZ_EQUAL; + } + + if (tc_size < hc_size) { + cd_ptr[ctr].csize_diff = TCSZ_SMALL; + } + } + + return; +} + +unsigned map_cache_geometries(cache_geometry * hcg_ptr, + cache_geometry * tcg_ptr, cache_diff * cd_ptr) +{ + unsigned rc = 0, cpu_id = read_cpuid(); + unsigned hcr = 0, cluster_id = read_clusterid(), sibling_cpuid = 0; + unsigned abs_cpuid = 0; + + if (!SWITCHER) { + sibling_cpuid = abs_cpuid(cpu_id, !cluster_id); + abs_cpuid = abs_cpuid(cpu_id, cluster_id); + } + + if (cluster_id == HOST_CLUSTER) { + + /* Find host cache topology */ + find_cache_geometry(hcg_ptr); + + /* + * Wait for the target cpu to send an event indicating that + * its discovered its cache topology. + */ + if (!SWITCHER) { + wait_for_event(CACHE_GEOM_DONE, abs_cpuid); + reset_event(CACHE_GEOM_DONE, abs_cpuid); + } + + /* + * Assuming that only no. of sets, ways and cache line + * size will be different across the target and host + * cpu caches. Hence the CLIDRs should look the same + * Support for absence of cache levels and memory + * Also this check ensures that the target cpu is + * always run before the host else the cache geometry + * will have to be hardcoded. + * mapped caches will be added later. + */ + if (hcg_ptr->clidr != tcg_ptr->clidr) { + printf("%s: Host CLIDR=0x%x : Target CLIDR=0x%x \n", + __FUNCTION__, hcg_ptr->clidr, tcg_ptr->clidr); + rc = 1; + goto out; + } + + find_cache_diff(hcg_ptr, tcg_ptr, cd_ptr); + + /* + * Enable bit for trapping set/way operations & + * Cache identification regs + */ + hcr = read_hcr(); + hcr |= HCR_TSW | HCR_TID2; + write_hcr(hcr); + dsb(); + isb(); + + } else { + + /* Find the cache geometry on the target cpu */ + find_cache_geometry(tcg_ptr); + + /* + * Send an event to the host cpu indicating that we have + * discovered our cache topology + */ + if (!SWITCHER) { + set_event(CACHE_GEOM_DONE, sibling_cpuid); + } + } + out: + return rc; +} + +/* + * Given two cache geometries and the difference between them + * handle a cache maintenance operation by set/way + */ +void handle_cm_op(unsigned reg, + void (*op_handler) (unsigned), + cache_geometry * hcg_ptr, + cache_geometry * tcg_ptr, cache_diff * cd_ptr) +{ + unsigned clvl = 0, cpu_id = read_cpuid(); + unsigned tc_assoc = 0, tc_numsets = 0, tc_linesz = 0; + unsigned hc_assoc = 0, hc_numsets = 0, hc_linesz = 0; + unsigned lineno = 0, setno = 0, wayno = 0, abs_lineno = 0; + + /* + * If target cache line size is greater than the host then + * each maintenance op has to be performed on two lines on + * host. Does not matter is the line size if equal + */ + unsigned ctr = cd_ptr[clvl].tcline_factor; + + /* + * Find out the cache level for which the set/way operation has invoked. + * Use this to find the cache geometry in target cache to ascertain the + * set & way number from the argument. Use this info to calculate the + * target cache line number. + */ + clvl = get_cache_level(reg); + tc_linesz = get_cache_linesz(tcg_ptr, clvl); + tc_assoc = get_cache_assoc(tcg_ptr, clvl); + tc_numsets = get_cache_numsets(tcg_ptr, clvl); + + wayno = (reg >> __builtin_clz(tc_assoc)) & tc_assoc; + setno = (reg >> (tc_linesz + 4)) & tc_numsets; + lineno = (setno * (tc_assoc + 1)) + wayno; + + if (CMOP_DEBUG) { + /* + * tc_prev_line is initialised to -1 (unsigned). We can never have so many + * cache lines. Helps determining when to record the start of a cm op. + * If count != lineno then either we are not counting or have been counting + * and now are out of sync. In either case, a new cm op is started + */ + if (tc_prev_line[cpu_id][clvl] != lineno) { + tc_prev_line[cpu_id][clvl] = lineno; + /* All ops start out as partial ops */ + cm_op_stats[cpu_id][clvl].part_cmop_cnt++; + + /* Reset all our counters */ + cm_ignline_cnt[cpu_id][clvl] = 0; + cm_extline_cnt[cpu_id][clvl] = 0; + hc_line_cnt[cpu_id][clvl] = 0; + cm_line_cnt[cpu_id][clvl] = 0; + } + + tc_prev_line[cpu_id][clvl]--; + cm_line_cnt[cpu_id][clvl]++; + } + + /* Convert target cache line no. to absolute cache line no. */ + if (cd_ptr[clvl].tcline_factor) + abs_lineno = lineno * cd_ptr[clvl].tcline_factor; + + /* Convert absolute cache line no. to host cache line no. */ + if (cd_ptr[clvl].hcline_factor) + lineno = abs_lineno / cd_ptr[clvl].hcline_factor; + + /* + * Find out the set & way no. on the host cache corresponding to the + * cache line no. calculated on the target cache. + */ + hc_linesz = get_cache_linesz(hcg_ptr, clvl); + hc_assoc = get_cache_assoc(hcg_ptr, clvl); + hc_numsets = get_cache_numsets(hcg_ptr, clvl); + + switch (cd_ptr[clvl].csize_diff) { + case TCSZ_BIG: + { + if (abs_lineno < cd_ptr[clvl].hnumabs_clines) { + while (ctr) { + setno = lineno / (hc_assoc + 1); + wayno = lineno % (hc_assoc + 1); + reg = + get_setway_reg(wayno, hc_assoc, + setno, hc_linesz, + clvl);; + op_handler(reg); + lineno++; + ctr--; + + if (CMOP_DEBUG) + hc_line_cnt[cpu_id][clvl]++; + + } + } else { + /* Ignore */ + if (CMOP_DEBUG) + cm_ignline_cnt[cpu_id][clvl]++; + + } + } + break; + case TCSZ_EQUAL: + { + while (ctr) { + setno = lineno / (hc_assoc + 1); + wayno = lineno % (hc_assoc + 1); + reg = + get_setway_reg(wayno, hc_assoc, setno, + hc_linesz, clvl);; + op_handler(reg); + lineno++; + ctr--; + + if (CMOP_DEBUG) + hc_line_cnt[cpu_id][clvl]++; + + } + } + break; + + case TCSZ_SMALL: + { + while (ctr) { + setno = lineno / (hc_assoc + 1); + wayno = lineno % (hc_assoc + 1); + reg = + get_setway_reg(wayno, hc_assoc, setno, + hc_linesz, clvl);; + op_handler(reg); + lineno++; + ctr--; + + if (CMOP_DEBUG) + hc_line_cnt[cpu_id][clvl]++; + + } + + /* + * If the target cache is smaller than the host cache then we + * need to extend the maintenance operation to rest of the host + * cache. + */ + if ((abs_lineno + + (1 * cd_ptr[clvl].tcline_factor)) == + cd_ptr[clvl].tnumabs_clines) { + + /* + * TODO: Temp hack. Due to the cache line factor we end up incrementing + * the lineno and miss one line. + */ + lineno--; + for (lineno++; + lineno < (hc_numsets + 1) * (hc_assoc + 1); + lineno++) { + setno = lineno / (hc_assoc + 1); + wayno = lineno % (hc_assoc + 1); + + /* Create new register value for operation on host cache */ + reg = + get_setway_reg(wayno, hc_assoc, + setno, hc_linesz, + clvl);; + /* Perform the operation */ + op_handler(reg); + + if (CMOP_DEBUG) + cm_extline_cnt[cpu_id][clvl]++; + + } + } else { + /* Ignore */ + } + break; + } + } + + if (CMOP_DEBUG) { + /* + * If the op cnt has reached the maximum cache line number then + * print the statistics collected so far + * + * NOTE: We don't reset the counter. It will done at the start + * of the next cm op automatically. Its value now is one more + * than the maximum valid target cache line number. + */ + if (cm_line_cnt[cpu_id][clvl] == + (tc_assoc + 1) * (tc_numsets + 1)) { + + printf("%s", __FUNCTION__); + printf(" : TC Lines=0x%x ", cm_line_cnt[cpu_id][clvl]); + printf(" : HC Lines=0x%x ", hc_line_cnt[cpu_id][clvl]); + printf(" : Ign Lines=0x%x ", + cm_ignline_cnt[cpu_id][clvl]); + printf(" : Extra Lines=0x%x ", + cm_extline_cnt[cpu_id][clvl]); + printf("\n"); + + /* Register this as a complete set/way operation */ + cm_op_stats[cpu_id][clvl].part_cmop_cnt--; + cm_op_stats[cpu_id][clvl].cmpl_cmop_cnt++; + } + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/virtualisor/cpus/a15/a15.c b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a15/a15.c new file mode 100644 index 0000000..50049da --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a15/a15.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "bl.h" +#include "virtualisor.h" +#include "a15.h" + +#ifndef SWITCHER +#define SWITCHER 0 +#endif + +/* Forward declaration */ +static virt_descriptor a15_virt_desc; + +/* + * Dummy functions for setting up any cpu + * specific traps. + */ +unsigned a15_trap_handle(gp_regs * regs, unsigned hsr, unsigned sibling_cpu) +{ + return 0; +} + +unsigned a15_trap_save(unsigned first_cpu, unsigned sibling_cpu) +{ + return 0; +} + +unsigned a15_trap_restore(unsigned first_cpu, unsigned sibling_cpu) +{ + return 0; +} + +unsigned a15_trap_setup(unsigned first_cpu, unsigned sibling_cpu) +{ + if (SWITCHER) { + + } else { + /* Always on */ + } + + /* + * Indicate that cpu specific virtualisor setup + * has been done. Restore context instead on next + * invocation + */ + a15_virt_desc.init[read_cpuid()] = 1; + return 0; +} + +static virt_descriptor a15_virt_desc + __attribute__ ((section(".data.virt_desc_section"))) = { + A15, { +0}, a15_trap_setup, a15_trap_handle, a15_trap_save, a15_trap_restore,}; diff --git a/linaro/arm-virt-bl/big-little/virtualisor/cpus/a15/include/a15.h b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a15/include/a15.h new file mode 100644 index 0000000..3a9515d --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a15/include/a15.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __A15_H__ +#define __A15_H__ + +#endif /* __A15_H__ */ diff --git a/linaro/arm-virt-bl/big-little/virtualisor/cpus/a7/a7.c b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a7/a7.c new file mode 100644 index 0000000..f1f7a39 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a7/a7.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "bl.h" +#include "virtualisor.h" +#include "a7.h" + +#ifndef SWITCHER +#define SWITCHER 0 +#endif + +/* Forward declaration */ +static virt_descriptor a7_virt_desc; + +/* + * Dummy functions for setting up any cpu + * specific traps. + */ +unsigned a7_trap_handle(gp_regs * regs, unsigned hsr, unsigned sibling_cpu) +{ + return 0; +} + +unsigned a7_trap_save(unsigned first_cpu, unsigned sibling_cpu) +{ + return 0; +} + +unsigned a7_trap_restore(unsigned first_cpu, unsigned sibling_cpu) +{ + return 0; +} + +unsigned a7_trap_setup(unsigned first_cpu, unsigned sibling_cpu) +{ + if (SWITCHER) { + + } else { + /* Always on */ + } + + /* + * Indicate that cpu specific virtualisor setup + * has been done. Restore context instead on next + * invocation + */ + a7_virt_desc.init[read_cpuid()] = 1; + return 0; +} + +static virt_descriptor a7_virt_desc + __attribute__ ((section(".data.virt_desc_section"))) = { + A7, { +0}, a7_trap_setup, a7_trap_handle, a7_trap_save, a7_trap_restore,}; diff --git a/linaro/arm-virt-bl/big-little/virtualisor/cpus/a7/include/a7.h b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a7/include/a7.h new file mode 100644 index 0000000..ff3000e --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/cpus/a7/include/a7.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __A7_H__ +#define __A7_H__ + +#endif /* __A7_H__ */ diff --git a/linaro/arm-virt-bl/big-little/virtualisor/include/cache_geom.h b/linaro/arm-virt-bl/big-little/virtualisor/include/cache_geom.h new file mode 100644 index 0000000..f8daa49 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/include/cache_geom.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __CACHE_GEOM_H__ +#define __CACHE_GEOM_H__ + +#define MAX_CACHE_LEVELS 0x8 + +/* Target cpu cache relative to host cpu cache size */ +#define TCSZ_EQUAL 0x0 +#define TCSZ_SMALL 0x1 +#define TCSZ_BIG 0x2 + +#define get_setway_reg(a, b , c, d, e) ((a << __builtin_clz(b)) | (c << (d + 4)) | (e << 1)) +#define get_cache_type(clidr, lvl) ((clidr >> (lvl * 0x3)) & 0x7) +#define get_cache_level(reg) (reg >> 1) & 0x7 +#define get_cache_linesz(cg, lvl) (cg->ccsidr[lvl] & 0x7) +#define get_cache_assoc(cg, lvl) ((cg->ccsidr[lvl] >> 3) & 0x3ff) +#define get_cache_numsets(cg, lvl) ((cg->ccsidr[lvl] >> 13) & 0x7fff) + +/* + * Data structure that stores the foreseeable differences + * between the host and target caches at each implemented + * cache level. + * Absolute cache line numbers are calculated relative to + * the cache line size of the smaller cache to get the + * maximum granularity. + */ +typedef struct cache_diff { + /* Stores whether target cache is =,<,> host cache */ + unsigned csize_diff; + /* + * Stores factor by which target cache line + * has to be multiplied to get absolute line + * no. + */ + unsigned tcline_factor; + /* + * Stores factor by which absolute cache line + * no. has to be divided to get host cache line + * no. + */ + unsigned hcline_factor; + /* Max absolute target cpu cache line number */ + unsigned tnumabs_clines; + /* Max absolute host cpu cache line number */ + unsigned hnumabs_clines; +} cache_diff; + +/* + * Data structure that defines the cache topology of a cpu + */ +typedef struct cache_geom { + unsigned clidr; + /* + * One for each cpu to store the cache level + * the OS thinks its operating on. + */ + unsigned csselr; + /* One for each cache level */ + unsigned ccsidr[MAX_CACHE_LEVELS]; +} cache_geometry; + +/* + * Data structure to hold cache virtualisation statistics. + * Reset for each switchover. + */ +typedef struct cache_stats { + /* Number of cm ops which did not cover the whole cache */ + unsigned part_cmop_cnt; + /* Number of cm ops which spanned the entire cache */ + unsigned cmpl_cmop_cnt; +} cache_stats; + +extern unsigned map_cache_geometries(cache_geometry *, + cache_geometry *, cache_diff *); +extern void find_cache_geometry(cache_geometry *); +extern void find_cache_diff(cache_geometry *, cache_geometry *, cache_diff *); +extern void handle_cm_op(unsigned, + void (*)(unsigned), + cache_geometry *, cache_geometry *, cache_diff *); + +#endif /* __CACHE_GEOM_H__ */ diff --git a/linaro/arm-virt-bl/big-little/virtualisor/include/mem_trap.h b/linaro/arm-virt-bl/big-little/virtualisor/include/mem_trap.h new file mode 100644 index 0000000..7b475aa --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/include/mem_trap.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __MEM_TRAP_H__ +#define __MEM_TRAP_H__ + +/* + * Data structure that holds info about all traps populated + * in the 2nd stage translation tables. It does not need to + * interpret the traps but simple save and restore them. + * This should prevent the usage of trap specific save/restore + * routines. + */ +typedef struct trap_data { + /* Does this structure contain valid data */ + unsigned valid; + /* Which cluster to save/restore this trap on */ + unsigned cluster_id; + /* Translation table address */ + unsigned long long table; + /* Index corresponding to mapping */ + unsigned index; + /* TODO: Revisit why we need two variables here */ + /* Original Descriptor */ + unsigned long long prev_desc; + /* Current Descriptor */ + unsigned long long cur_desc; +} mem_trap_data; + +extern unsigned mem_trap_setup(unsigned, mem_trap_data *); + +#ifdef BUILD_RVCT +extern mem_trap_data s2_trap_section$$Base __asm(".data.s2_trap_section$$Base"); +extern unsigned s2_trap_section$$Length __asm(".data.s2_trap_section$$Length"); +#define S2_TRAP_SECTION_base (&s2_trap_section$$Base) +#define S2_TRAP_SECTION_length ((unsigned)&s2_trap_section$$Length) +#else +extern mem_trap_data __s2_trap_section_base; +extern mem_trap_data __s2_trap_section_end; +#define S2_TRAP_SECTION_base (&__s2_trap_section_base) +#define S2_TRAP_SECTION_length \ + ((char *)&__s2_trap_section_end - (char *)&__s2_trap_section_base) +#endif + +#endif /* __MEM_TRAP_H__ */ diff --git a/linaro/arm-virt-bl/big-little/virtualisor/include/virtualisor.h b/linaro/arm-virt-bl/big-little/virtualisor/include/virtualisor.h new file mode 100644 index 0000000..5de5fdb --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/include/virtualisor.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __VIRTUALISOR_H__ +#define __VIRTUALISOR_H__ + +#include "misc.h" +#include "virt_helpers.h" + +/* + * Data structure that holds a copy of the virtualized regs + */ +typedef struct virt_regs { + unsigned cluster_id; + unsigned mpidr; + unsigned midr; +} virt_reg_data; + +/* + * Data structure that holds all the trap registers exported + * by the Virtualisation Extensions. + */ +typedef struct trap_regs { + unsigned hcr; + unsigned hdcr; + unsigned hcptr; + unsigned hstr; +} reg_trap_data; + +typedef struct gp_regs { + unsigned r[15]; +} gp_regs; + +/* + * Descriptor exported by each processor describing + * which traps it wants to implement along with + * handlers for saving and restoring for each conf- + * -igured trap. + */ +typedef struct virt_desc { + /* cpu midr contents */ + unsigned cpu_no; + /* + * Bitmask to inidicate that Virtualisor setup has been + * done on both host & target cpus. + */ + unsigned char init[NUM_CPUS]; + unsigned (*trap_setup) (unsigned, unsigned); + unsigned (*trap_handle) (gp_regs * regs, unsigned, unsigned); + unsigned (*trap_save) (unsigned, unsigned); + unsigned (*trap_restore) (unsigned, unsigned); +} virt_descriptor; + +extern void SetupVirtualisor(unsigned); +extern void SaveVirtualisor(unsigned); +extern void RestoreVirtualisor(unsigned); +extern void HandleVirtualisor(gp_regs *); +extern void handle_vgic_distif_abort(unsigned, unsigned *, unsigned); +extern unsigned find_sibling_cpu(void); + +#ifdef BUILD_RVCT +extern virt_descriptor virt_desc_section$$Base +__asm(".data.virt_desc_section$$Base"); +extern unsigned virt_desc_section$$Length +__asm(".data.virt_desc_section$$Length"); +#define VIRT_DESC_SECTION_base (&virt_desc_section$$Base) +#define VIRT_DESC_SECTION_length ((unsigned)&virt_desc_section$$Length) +#else +extern virt_descriptor __virt_desc_section_base; +extern virt_descriptor __virt_desc_section_end; +#define VIRT_DESC_SECTION_base (&__virt_desc_section_base) +#define VIRT_DESC_SECTION_length \ + ((char *)&__virt_desc_section_end - (char *)&__virt_desc_section_base) +#endif + +#endif /* __VIRTUALISOR_H__ */ diff --git a/linaro/arm-virt-bl/big-little/virtualisor/mem_trap.c b/linaro/arm-virt-bl/big-little/virtualisor/mem_trap.c new file mode 100644 index 0000000..c40433a --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/mem_trap.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virtualisor.h" +#include "misc.h" +#include "virt_helpers.h" +#include "mem_trap.h" + +/* + * Generic call to make accesses to a peripheral trap into the + * HYP mode by invalidating its descriptor in the 2nd stage + * translation tables + */ +unsigned mem_trap_setup(unsigned periph_addr, mem_trap_data * periph_trap_data) +{ + unsigned rc = 0x0, four_kb_index = 0; + unsigned one_gb_index = 0, two_mb_index = 0; + unsigned long long vtcr = 0x0, hcr = 0x0, level = 0; + unsigned long long pagetable_base = 0x0, l2_desc = 0; + unsigned long long l3_desc = 0, l3_table = 0; + + /* Check if 2nd stage translations are enabled */ + hcr = read_hcr(); + if (!(hcr & HCR_VM)) { + printf("%s: 2nd Stage translations not enabled \n", + __FUNCTION__); + rc = 0x1; + goto out; + } + + /* Check what level of tables we need to start at */ + vtcr = read_vtcr(); + level = (vtcr >> 6) & 0x3; + + /* Read the page table base address. */ + pagetable_base = read_vttbr(); + + /* Calculate the table indices */ + one_gb_index = periph_addr >> 30; + + /* Each GB contains (1 << 9) or 512 2MBs */ + two_mb_index = (periph_addr >> 21) - ((1 << 9) * one_gb_index); + + /* Each GB contains (1 << 18) or 262144 4KBs */ + four_kb_index = (periph_addr >> 12) - ((1 << 9) * (periph_addr >> 21)); + + /* For either starting level find out the level 2 desc */ + switch (level) { + + case 0x1: + { + /* Start from first level */ + unsigned long long l1_desc = 0; + unsigned long long l2_table = 0; + + l1_desc = + ((unsigned long long + *)((unsigned)(&pagetable_base)[0]))[one_gb_index]; + if ((l1_desc & 0x3) != TABLE_MAPPING) { + printf("%s: Invalid 1st level desc : 0x%llu \n", + __FUNCTION__, l1_desc); + rc = 0x1; + goto out; + } + + l2_table = l1_desc & 0xfffffff000UL; + l2_desc = + ((unsigned long long + *)((unsigned)(&l2_table)[0]))[two_mb_index]; + break; + } + + case 0x0: + { + /* Start from second level */ + l2_desc = + ((unsigned long long + *)((unsigned)(&pagetable_base)[0]))[two_mb_index]; + break; + } + + default: + printf("%s: Invalid Pagetable level \n", __FUNCTION__); + rc = 0x1; + } + + /* Validate the 2nd level descriptor */ + if ((l2_desc & 0x3) != TABLE_MAPPING) { + printf("%s: Invalid 2nd level desc : 0x%llu \n", + __FUNCTION__, l2_desc); + rc = 0x1; + goto out; + } + + l3_table = l2_desc & 0xfffffff000UL; + l3_desc = + ((unsigned long long *)((unsigned)(&l3_table)[0]))[four_kb_index]; + + /* + * Validate the 3rd level descriptor. This means that the mapping is + * already invalid and we have not touched it + */ + if ((l3_desc & 0x3) != VALID_MAPPING) { + printf("%s: Invalid 3rd level desc : 0x%llu \n", + __FUNCTION__, l3_desc); + rc = 0x1; + goto out; + } + + /* Save the info gathered so far */ + periph_trap_data->table = l3_table; + periph_trap_data->index = four_kb_index; + periph_trap_data->prev_desc = l3_desc; + periph_trap_data->cluster_id = read_clusterid(); + periph_trap_data->valid = 1; + + /* Invalidate the peripheral page table entry */ + ((unsigned long long *)((unsigned)(&l3_table)[0]))[four_kb_index] = 0x0; + + out: + return rc; +} diff --git a/linaro/arm-virt-bl/big-little/virtualisor/vgic_trap_handler.c b/linaro/arm-virt-bl/big-little/virtualisor/vgic_trap_handler.c new file mode 100644 index 0000000..4e626d0 --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/vgic_trap_handler.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virtualisor.h" +#include "gic_registers.h" +#include "misc.h" +#include "virt_helpers.h" + +/* + * Whether A15 or A7, the distributor accesses are virtualised in + * exactly the same manner. + */ +void handle_vgic_distif_abort(unsigned pa, unsigned *data, unsigned write) +{ + unsigned value = 0, reg_offset = pa & 0xfff; + + switch (reg_offset >> 7) { + + /* Access to Processor Target registers */ + case (GICD_CPUS >> 7): + if (write) { + /* + * OS is trying to reprogram the processor targets register. + * Find out the cpu interface mask for this cluster and use + * that instead to program the register. + */ + value = get_cpuif_mask(*data); + write32(pa, value); + } else { + value = read32(pa); + *data = get_cpu_mask(value); + } + + break; + + /* Access to Software generated interrupt register */ + case (GICD_SW >> 7): + if (write) { + /* Get the updated cpu interface mask */ + value = get_cpuif_mask((*data >> 16) & 0xff) << 16; + value |= *data & ~(0xff << 16); + /* + * Clear the old cpu interface mask & update + * value with new cpu interface mask + */ + write32(pa, value); + } else { + /* Cannot possibly have a read from SGI generation register */ + } + + break; + + default: + if (write) { + write32(pa, *data); + } else { + *data = read32(pa); + } + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/virtualisor/virt_context.c b/linaro/arm-virt-bl/big-little/virtualisor/virt_context.c new file mode 100644 index 0000000..ee48d3b --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/virt_context.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virtualisor.h" +#include "misc.h" +#include "virt_helpers.h" +#include "cache_geom.h" +#include "mem_trap.h" + +#ifndef CMOP_DEBUG +#define CMOP_DEBUG 0 +#endif + +extern virt_reg_data host_virt_regs[]; +extern reg_trap_data host_trap_regs[]; +extern cache_stats cm_op_stats[NUM_CPUS][MAX_CACHE_LEVELS]; + +/* + * Save/Restore of Virtualisor should be done only on the host cpu + * & host cluster unlike setup which is done on both. The cluster + * is need for cases where both clusters have same cpu type and one + * cluster does not use the Virtualisor. + */ +void SaveVirtualisor(unsigned first_cpu) +{ + unsigned len = 0, ctr = 0, cpu_id = read_cpuid(), cpu_no = + PART_NO(read_midr()); + unsigned cluster_id = read_clusterid(), index = 0, vd_len = 0, rc = 0; + mem_trap_data *s2_td = S2_TRAP_SECTION_base; + unsigned long long *cd_ptr = 0x0; + unsigned *periph_addr = 0x0; + virt_descriptor *vd_array = VIRT_DESC_SECTION_base; + unsigned (*handler) (unsigned, unsigned) = 0x0, sibling; + + /* Find our brother from another mother */ + sibling = find_sibling_cpu(); + + if (cluster_id == HOST_CLUSTER) { + /* + * Since there is only one second stage translation table, its + * safe to assume that only one cpu (first_cpu) should save & + * restore the context. + */ + len = S2_TRAP_SECTION_length; + if (cpu_id == first_cpu) { + /* Iterate through the array of 2nd stage translation traps */ + for (ctr = 0; ctr < (len / sizeof(mem_trap_data)); + ctr++) { + if (s2_td[ctr].valid + && s2_td[ctr].cluster_id == cluster_id) { + + /* + * Save the current descriptor and restore the + * previous. Need not worry about synchronisation + * issues, as the existing entry was causing + * translation faults. The TLB never caches fault + * generating translations. + */ + cd_ptr = + &((unsigned long long + *)((unsigned)(&s2_td[ctr].table) + [0]))[s2_td[ctr].index]; + s2_td[ctr].cur_desc = *cd_ptr; + *cd_ptr = s2_td[ctr].prev_desc; + periph_addr = (unsigned *)cd_ptr; + dsb(); + inv_tlb_mva((unsigned *)periph_addr[0]); + inv_bpred_all(); + } + } + } + + /* Save the HYP trap registers for this cpu */ + host_trap_regs[cpu_id].hcr = read_hcr(); + host_trap_regs[cpu_id].hdcr = read_hdcr(); + host_trap_regs[cpu_id].hcptr = read_hcptr(); + host_trap_regs[cpu_id].hstr = read_hstr(); + + if (CMOP_DEBUG) { + /* Print Cache maintenance statistics */ + for (ctr = 0; ctr < MAX_CACHE_LEVELS; ctr++) { + printf("Cache Level %d", ctr); + printf(" : Partial ops=0x%x", + cm_op_stats[cpu_id][ctr].part_cmop_cnt); + printf(" : Complete ops=0x%x", + cm_op_stats[cpu_id][ctr].cmpl_cmop_cnt); + printf("\n"); + } + } + + } + + /* + * Call any cpu specific save routines (if any) + */ + vd_len = VIRT_DESC_SECTION_length; + for (index = 0; index < (vd_len / sizeof(virt_descriptor)); index++) { + + if (cpu_no == vd_array[index].cpu_no) { + handler = vd_array[index].trap_save; + if (handler) { + rc = handler(first_cpu, sibling); + if (rc) { + printf("%s: failed on cpu%d \n", + __FUNCTION__, cpu_no); + goto out; + } + } + } + } + + out: + if (rc) { + printf("%s: Failed : Cpu%d : Host=0x%x : Target=0x%x\n ", + __FUNCTION__, cpu_id, cpu_no, sibling); + panic(); + } + + return; +} + +/* + * TODO: not required as we can invoke the cpu restore function + * directly from SetupVirtualisor and don't need to go through + * the descriptor array again. + */ +void RestoreVirtualisor(unsigned first_cpu) +{ + unsigned len = 0, ctr = 0, cpu_id = read_cpuid(), cpu_no = + PART_NO(read_midr()); + unsigned cluster_id = read_clusterid(), index = 0, vd_len = 0, rc = 0; + mem_trap_data *s2_td = S2_TRAP_SECTION_base; + unsigned long long *cd_ptr = 0x0; + unsigned *periph_addr = 0x0; + virt_descriptor *vd_array = VIRT_DESC_SECTION_base; + unsigned (*handler) (unsigned, unsigned) = 0x0, sibling; + + /* Find our brother from another mother */ + sibling = find_sibling_cpu(); + + if (cluster_id == HOST_CLUSTER) { + /* + * Since there is only one second stage translation table, its + * safe to assume that only one cpu (first_cpu) should save & + * restore the context. + */ + len = S2_TRAP_SECTION_length; + if (cpu_id == first_cpu) { + /* Iterate through the array of 2nd stage translation traps */ + for (ctr = 0; ctr < (len / sizeof(mem_trap_data)); + ctr++) { + if (s2_td[ctr].valid + && s2_td[ctr].cluster_id == cluster_id) { + /* + * Restore the current descriptor and save the previous + */ + cd_ptr = + &((unsigned long long + *)((unsigned)((&s2_td[ctr].table) + [0])))[s2_td + [ctr].index]; + s2_td[ctr].prev_desc = *cd_ptr; + *cd_ptr = s2_td[ctr].cur_desc; + periph_addr = (unsigned *)cd_ptr; + dsb(); + inv_tlb_mva((unsigned *)periph_addr[0]); + inv_bpred_all(); + } + } + } + + /* Now restore the virtualised ID registers for this cpu */ + write_vmidr(host_virt_regs[cpu_id].midr); + write_vmpidr(host_virt_regs[cpu_id].mpidr); + + /* Restore the HYP trap registers for this cpu */ + write_hcr(host_trap_regs[cpu_id].hcr); + write_hdcr(host_trap_regs[cpu_id].hdcr); + write_hcptr(host_trap_regs[cpu_id].hcptr); + write_hstr(host_trap_regs[cpu_id].hstr); + + if (CMOP_DEBUG) { + /* Resetting Cache maintenance statistics */ + for (ctr = 0; ctr < MAX_CACHE_LEVELS; ctr++) { + cm_op_stats[cpu_id][ctr].part_cmop_cnt = 0; + cm_op_stats[cpu_id][ctr].cmpl_cmop_cnt = 0; + } + } + } + + /* + * Call any cpu specific restore routines (if any) + */ + vd_len = VIRT_DESC_SECTION_length; + for (index = 0; index < (vd_len / sizeof(virt_descriptor)); index++) { + + if (cpu_no == vd_array[index].cpu_no) { + handler = vd_array[index].trap_restore; + if (handler) { + rc = handler(first_cpu, sibling); + if (rc) { + printf("%s: failed on cpu%d \n", + __FUNCTION__, cpu_no); + goto out; + } + } + } + } + + out: + if (rc) { + printf("%s: Failed : Cpu%d : Host=0x%x : Target=0x%x\n ", + __FUNCTION__, cpu_id, cpu_no, sibling); + panic(); + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/virtualisor/virt_handle.c b/linaro/arm-virt-bl/big-little/virtualisor/virt_handle.c new file mode 100644 index 0000000..0984cbd --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/virt_handle.c @@ -0,0 +1,610 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virtualisor.h" +#include "virt_helpers.h" +#include "hyp_types.h" +#include "cache_geom.h" +#include "mem_trap.h" +#include "gic_registers.h" +#include "bl.h" + +#ifndef SWITCHER +#define SWITCHER 0 +#endif + +extern cache_geometry host_cache_geometry[]; +extern cache_geometry target_cache_geometry[]; +extern cache_diff cache_delta[NUM_CPUS][MAX_CACHE_LEVELS]; + +void trap_cp15_mrc_mcr_handle(unsigned hsr, gp_regs * regs) +{ + unsigned Op1, Op2, CRn, CRm, Rt, write, cpu_id = read_cpuid(); + + Op2 = (hsr >> 17) & 0x7; + Op1 = (hsr >> 14) & 0x7; + CRn = (hsr >> 10) & 0xf; + Rt = (hsr >> 5) & 0xf; + CRm = (hsr >> 1) & 0xf; + write = !(hsr & 0x1); + + switch (CRn) { + case CRN_C0: + switch (Op1) { + case 0: + switch (CRm) { + case 0: + switch (Op2) { + case MIDR: + if (write) + goto error; + regs->r[Rt] = read_vmidr(); + break; + case CTR: + if (write) + goto error; + regs->r[Rt] = read_ctr(); + break; + case TCMTR: + if (write) + goto error; + regs->r[Rt] = read_tcmtr(); + break; + case TLBTR: + if (write) + goto error; + regs->r[Rt] = read_tlbtr(); + break; + case MPIDR: + if (write) + goto error; + regs->r[Rt] = read_vmpidr(); + break; + default: + goto error; + } + break; + case 1: + switch (Op2) { + case ID_PFR0: + if (write) + goto error; + regs->r[Rt] = read_id_pfr0(); + break; + case ID_PFR1: + if (write) + goto error; + regs->r[Rt] = read_id_pfr1(); + break; + case ID_DFR0: + if (write) + goto error; + regs->r[Rt] = read_id_dfr0(); + break; + case ID_AFR0: + if (write) + goto error; + regs->r[Rt] = read_id_afr0(); + break; + case ID_MMFR0: + if (write) + goto error; + regs->r[Rt] = read_id_mmfr0(); + break; + case ID_MMFR1: + if (write) + goto error; + regs->r[Rt] = read_id_mmfr1(); + break; + case ID_MMFR2: + if (write) + goto error; + regs->r[Rt] = read_id_mmfr2(); + break; + case ID_MMFR3: + if (write) + goto error; + regs->r[Rt] = read_id_mmfr3(); + break; + default: + goto error; + } + break; + case 2: + switch (Op2) { + case ID_ISAR0: + if (write) + goto error; + regs->r[Rt] = read_id_isar0(); + break; + case ID_ISAR1: + if (write) + goto error; + regs->r[Rt] = read_id_isar1(); + break; + case ID_ISAR2: + if (write) + goto error; + regs->r[Rt] = read_id_isar2(); + break; + case ID_ISAR3: + if (write) + goto error; + regs->r[Rt] = read_id_isar3(); + break; + case ID_ISAR4: + if (write) + goto error; + regs->r[Rt] = read_id_isar4(); + break; + case ID_ISAR5: + if (write) + goto error; + regs->r[Rt] = read_id_isar5(); + break; + default: + /* RAZ */ + regs->r[Rt] = 0x0; + } + break; + case 3: + case 4: + case 5: + case 6: + case 7: + if (write) + goto error; + /* RAZ */ + regs->r[Rt] = 0x0; + break; + default: + goto error; + } + break; + case 1: + switch (CRm) { + case 0: + switch (Op2) { + case CCSIDR: + if (write) + goto error; + regs->r[Rt] = + target_cache_geometry[cpu_id].ccsidr + [get_cache_level + (target_cache_geometry + [cpu_id].csselr)]; + break; + case CLIDR: + if (write) + goto error; + regs->r[Rt] = + target_cache_geometry[cpu_id].clidr; + break; + case AIDR: + if (write) + goto error; + regs->r[Rt] = read_aidr(); + break; + default: + goto error; + } + break; + default: + goto error; + } + break; + case 2: + switch (CRm) { + case 0: + switch (Op2) { + case CSSELR: + if (write) + target_cache_geometry + [cpu_id].csselr = + regs->r[Rt]; + else + regs->r[Rt] = + target_cache_geometry + [cpu_id].csselr; + break; + default: + goto error; + } + break; + default: + goto error; + } + break; + default: + goto error; + } + break; + case CRN_C7: + switch (Op1) { + case 0: + switch (CRm) { + case 6: + switch (Op2) { + case DCISW: + { + if (!write) + goto error; + handle_cm_op(regs->r[Rt], + dcisw, + &host_cache_geometry + [cpu_id], + &target_cache_geometry + [cpu_id], + &cache_delta + [cpu_id][0]); + break; + } + default: + goto error; + } + break; + case 10: + switch (Op2) { + case DCCSW: + { + if (!write) + goto error; + handle_cm_op(regs->r[Rt], + dccsw, + &host_cache_geometry + [cpu_id], + &target_cache_geometry + [cpu_id], + &cache_delta + [cpu_id][0]); + break; + } + default: + goto error; + } + break; + case 14: + switch (Op2) { + case DCCISW: + { + if (!write) + goto error; + handle_cm_op(regs->r[Rt], + dccisw, + &host_cache_geometry + [cpu_id], + &target_cache_geometry + [cpu_id], + &cache_delta + [cpu_id][0]); + break; + } + default: + goto error; + } + break; + default: + goto error; + } + break; + default: + goto error; + } + break; + case CRN_C9: + switch (Op1) { + case 1: + switch (CRm) { + case 0: + switch (Op2) { + case 2: + /* + * A write to the L2CTLR register means trouble + * as the A7 version does not have all the fields + * that the A15 has. Handling needs more thought + */ + if (write) { + printf + ("%s: Unexpected L2CTLR write \n", + __FUNCTION__); + goto error; + } + + /* + * A read of the L2CTLR should return the total number + * of cpus across both the clusters in the "always on" + * configuration. Since there are only 2 bits for the + * number of cpus in the L2CTLR we need to flag any + * system with > 4 cpus. + */ + if (!SWITCHER) { + unsigned num_cpus = + CLUSTER_CPU_COUNT + (HOST_CLUSTER) + + + CLUSTER_CPU_COUNT + (!HOST_CLUSTER); + + if (num_cpus > 4) { + printf + ("%s: Unexpected L2CTLR read \n", + __FUNCTION__); + goto error; + } + + regs->r[Rt] &= ~(0x3 << 24); + regs->r[Rt] |= + (num_cpus - 1) << 24; + } else { + regs->r[Rt] = read_l2ctlr(); + } + break; + case 3: + /* + * A write to the L2ECTLR register means trouble + * as it does not exist on A7. Handling needs more + * thought + */ + if (write) { + printf + ("%s: Unexpected L2ECTLR write \n", + __FUNCTION__); + goto error; + } else { + regs->r[Rt] = read_l2ectlr(); + } + break; + default: + goto error; + } + break; + default: + goto error; + } + break; + + /* + * Support for accesses to the PMON space. Its not been + * verified whether all the registers are readable & + * writable. But then, execution will never reach here + * if a reg is inaccessible. It will be a undef abort + * instead. + */ + case 0: + switch (CRm) { + case 14: + switch (Op2) { + case 0: + if (write) + write_pmuserenr(regs->r[Rt]); + else + regs->r[Rt] = read_pmuserenr(); + break; + case 1: + if (write) + write_pmintenset(regs->r[Rt]); + else + regs->r[Rt] = read_pmintenset(); + break; + case 2: + if (write) + write_pmintenclr(regs->r[Rt]); + else + regs->r[Rt] = read_pmintenclr(); + break; + case 3: + if (write) + write_pmovsset(regs->r[Rt]); + else + regs->r[Rt] = read_pmovsset(); + break; + default: + goto error; + } + break; + + case 13: + switch (Op2) { + case 0: + if (write) + write_pmccntr(regs->r[Rt]); + else + regs->r[Rt] = read_pmccntr(); + break; + case 1: + if (write) + write_pmxevtyper(regs->r[Rt]); + else + regs->r[Rt] = read_pmxevtyper(); + break; + case 2: + if (write) + write_pmxevcntr(regs->r[Rt]); + else + regs->r[Rt] = read_pmxevcntr(); + break; + default: + goto error; + } + break; + + case 12: + switch (Op2) { + case 0: + if (write) + write_pmcr(regs->r[Rt]); + else + regs->r[Rt] = read_pmcr(); + break; + case 1: + if (write) + write_pmcntenset(regs->r[Rt]); + else + regs->r[Rt] = read_pmcntenset(); + break; + case 2: + if (write) + write_pmcntenclr(regs->r[Rt]); + else + regs->r[Rt] = read_pmcntenclr(); + break; + case 3: + if (write) + write_pmovsr(regs->r[Rt]); + else + regs->r[Rt] = read_pmovsr(); + break; + case 4: + if (write) + write_pmswinc(regs->r[Rt]); + else + regs->r[Rt] = read_pmswinc(); + break; + case 5: + if (write) + write_pmselr(regs->r[Rt]); + else + regs->r[Rt] = read_pmselr(); + break; + case 6: + if (write) + write_pmceid0(regs->r[Rt]); + else + regs->r[Rt] = read_pmceid0(); + break; + case 7: + if (write) + write_pmceid1(regs->r[Rt]); + else + regs->r[Rt] = read_pmceid1(); + break; + default: + goto error; + } + break; + } + break; + default: + goto error; + } + break; + default: + goto error; + } + + return; + + error: + printf("%s: Unexpected cp15 instruction", __FUNCTION__); + printf(" : %s", write ? "MCR p15" : "MRC p15"); + printf(", %d, %d, %d, %d, %d \n", Op1, Rt, CRn, CRm, Op2); + panic(); + +} + +void trap_dabort_handle(unsigned hsr, gp_regs * regs) +{ + unsigned hdfar = 0x0, hpfar = 0x0, pa = 0x0, *data = 0x0; + unsigned write = 0x0; + + hdfar = read_hdfar(); + hpfar = read_hpfar(); + + pa = ((hpfar >> 4) << 12) + (hdfar & 0xfff); + data = ®s->r[(hsr >> 16) & 0xf]; + write = (hsr >> 6) & 0x1; + + /* Only distributor accesses are virtualised at the moment */ + if ((pa & ~0xfff) == GIC_ID_PHY_BASE) { + handle_vgic_distif_abort(pa, data, write); + } + + return; +} + +void HandleVirtualisor(gp_regs * regs) +{ + unsigned cpu_id = read_cpuid(), cpu_no = PART_NO(read_midr()), rc = 0; + unsigned hsr = read_hsr(), elr = 0, vd_len = 0, index = 0; + virt_descriptor *vd_array = VIRT_DESC_SECTION_base; + unsigned (*handler) (gp_regs *, unsigned, unsigned) = 0x0, sibling; + + /* Find our brother from another mother */ + sibling = find_sibling_cpu(); + + /* + * Perform the generic trap handling + */ + switch (hsr >> 26) { + case TRAP_DABORT: + trap_dabort_handle(hsr, regs); + break; + case TRAP_CP15_32: + trap_cp15_mrc_mcr_handle(hsr, regs); + break; + default: + printf("%s: Unexpected trap", __FUNCTION__); + printf(": HSR=0x%x Regs=0x%x \n", hsr, (unsigned)regs); + panic(); + } + + /* + * Do any cpu specific trap handling. + */ + vd_len = VIRT_DESC_SECTION_length; + for (index = 0; index < (vd_len / sizeof(virt_descriptor)); index++) { + + if (cpu_no == vd_array[index].cpu_no) { + handler = vd_array[index].trap_handle; + if (handler) { + rc = handler(regs, hsr, sibling); + if (rc) { + printf("%s: failed on cpu%d \n", + __FUNCTION__, cpu_no); + goto out; + } + } + } + } + + /* + * This is a trap of the kind where we simply move + * onto the next instruction in the actual program. + * Move by 2 bytes if we came from Thumb mode else + * by 4 bytes. + */ + elr = ((vm_context *) regs)->elr_hyp; + if (hsr & (1 << 25)) + elr += 4; + else + elr += 2; + ((vm_context *) regs)->elr_hyp = elr; + + out: + if (rc) { + printf("%s: Failed : Cpu%d : Host=0x%x : Target=0x%x\n ", + __FUNCTION__, cpu_id, cpu_no, sibling); + panic(); + } + + return; +} diff --git a/linaro/arm-virt-bl/big-little/virtualisor/virt_setup.c b/linaro/arm-virt-bl/big-little/virtualisor/virt_setup.c new file mode 100644 index 0000000..5d28a5a --- /dev/null +++ b/linaro/arm-virt-bl/big-little/virtualisor/virt_setup.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "virt_helpers.h" +#include "virtualisor.h" +#include "events.h" +#include "misc.h" +#include "cache_geom.h" +#include "mem_trap.h" +#include "gic_registers.h" + +#ifndef SWITCHER +#define SWITCHER 0 +#endif + +virt_reg_data host_virt_regs[NUM_CPUS]; +reg_trap_data host_trap_regs[NUM_CPUS]; +cache_geometry host_cache_geometry[NUM_CPUS]; +cache_geometry target_cache_geometry[NUM_CPUS]; + +/* Cache geometry differences for each cpu at each level */ +cache_diff cache_delta[NUM_CPUS][MAX_CACHE_LEVELS]; +static mem_trap_data svgic_distif_trap + __attribute__ ((section(".data.s2_trap_section"))) = { +0, 0x0, 0x0, 0x0, 0x0, 0x0,}; + +/* + * Flags which indicate whether the cpu independent + * functionality of the Virtualisor has been setup + * on both the host and target clusters. + */ +static unsigned virt_init[NUM_CPUS]; + +/* + * Detect the type of dual cluster system we are, read + * our cpu type and then use the KFS_ID register to + * return the type of cpu on the other cluster. + */ +unsigned find_sibling_cpu() +{ + unsigned cpu_no = PART_NO(read_midr()); + + switch (DC_SYSTYPE) { + case A15_A15: + if (cpu_no == A15) + return cpu_no; + break; + case A7_A15: + case A15_A7: + if (cpu_no == A15) + return A7; + else if (cpu_no == A7) + return A15; + else + break; + } + + printf("Unsupported Dual cluster system : 0x%x\n", DC_SYSTYPE); + panic(); + + return 0; +} + +void SetupVirtualisor(unsigned first_cpu) +{ + unsigned rc = 0, cpu_id = read_cpuid(), cpu_no = PART_NO(read_midr()); + unsigned vd_len = 0, index = 0, cluster_id = read_clusterid(); + virt_descriptor *vd_array = VIRT_DESC_SECTION_base; + unsigned (*handler) (unsigned, unsigned) = 0x0, sibling; + unsigned sibling_cpuid = 0, abs_cpuid = 0; + + if (!SWITCHER) { + sibling_cpuid = abs_cpuid(cpu_id, !cluster_id); + abs_cpuid = abs_cpuid(cpu_id, cluster_id); + } + + /* Find our brother from another mother */ + sibling = find_sibling_cpu(); + + /* + * Do the generic trap setup + */ + if (virt_init[cpu_id] == FALSE) { + + /* + * In the "always-on" configuration, both clusters have + * ensure that the L2CTLR register includes the cpu count + * of both the clusters while reporting the number of + * secondary cpus. So setup the necessary trap. + */ + if (!SWITCHER) { + /* + * Enable traps to CRn = 9 cp15 space + */ + write_hstr(read_hstr() | (1 << 9)); + } + + /* + * Cache geometry of each cpu on the host cluster needs + * to be virtualised if the cpu type is different from + * that on the target cluster. This can be done generic- + * ally. + */ + if (cpu_no != sibling) { + rc = map_cache_geometries(&host_cache_geometry[cpu_id], + &target_cache_geometry + [cpu_id], + &cache_delta[cpu_id][0]); + if (rc) { + printf("%s: Failed to map cache geometries \n", + __FUNCTION__); + rc = 1; + goto out; + } + + } + + /* + * Irrespective of what cpu types are present in the + * dual cluster system, the host cluster has to trap + * accesses to the vgic distributor when switching. + */ + if (SWITCHER && cluster_id == HOST_CLUSTER) { + if (cpu_id == first_cpu) { + rc = mem_trap_setup(GIC_ID_PHY_BASE, + &svgic_distif_trap); + if (rc) { + printf + ("%s: svgic distif trap setup failed \n", + __FUNCTION__); + goto out; + } + } + } + + /* + * If the two clusters have different cpu types, then the + * target saves its midr and the host uses the value to + * virtualise its midr. + * mpidr is virtualised on the host cluster whether we are + * running "always on" or "switching". The latter cares + * about the cluster id while the former cares about the + * cpu ids as well. + */ + if (cluster_id != HOST_CLUSTER) { + host_virt_regs[cpu_id].mpidr = read_mpidr(); + if (cpu_no != sibling) + host_virt_regs[cpu_id].midr = read_midr(); + if (!SWITCHER) { + /* + * Send a signal to the host to indicate + * that the regs is ready to be read. The + * cpu id is the absolute cpu number across + * clusters. + */ + set_event(VID_REGS_DONE, sibling_cpuid); + } + } else { + if (!SWITCHER) { + /* + * Wait for the target to read its regs + * before using them. + */ + wait_for_event(VID_REGS_DONE, abs_cpuid); + reset_event(VID_REGS_DONE, abs_cpuid); + + /* + * Add number of cpus in the target cluster to + * the cpuid of this cpu. + */ + host_virt_regs[cpu_id].mpidr += + CLUSTER_CPU_COUNT(!HOST_CLUSTER); + } + write_vmpidr(host_virt_regs[cpu_id].mpidr); + if (cpu_no != sibling) + write_vmidr(host_virt_regs[cpu_id].midr); + } + + if (cluster_id == HOST_CLUSTER) { + /* + * Assuming that with the switcher, the host always + * runs after the target. So, if we are here then + * the target must have completed its initialisation + * + * In the other case, if we are here after exchanging + * the events above, then the target has finished + * initialising. + */ + virt_init[cpu_id] = 1; + } + + } else { + if (SWITCHER) + RestoreVirtualisor(first_cpu); + } + + /* + * Do the cpu specific initialisation (if any) + */ + vd_len = VIRT_DESC_SECTION_length; + for (index = 0; index < (vd_len / sizeof(virt_descriptor)); index++) { + + if (cpu_no == vd_array[index].cpu_no) { + /* If not initialised then setup else restore */ + if (vd_array[index].init[cpu_id] == 0) + handler = vd_array[index].trap_setup; + else + handler = vd_array[index].trap_restore; + + if (handler) { + rc = handler(first_cpu, sibling); + if (rc) { + printf("%s: failed on cpu%d \n", + __FUNCTION__, cpu_no); + goto out; + } + } + } + } + + out: + if (rc) { + printf("%s: Failed : Cpu%d : Host=0x%x : Target=0x%x\n ", + __FUNCTION__, cpu_id, cpu_no, sibling); + panic(); + } + + return; +} diff --git a/linaro/arm-virt-bl/bootwrapper/Makefile b/linaro/arm-virt-bl/bootwrapper/Makefile new file mode 100755 index 0000000..96c9e6c --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/Makefile @@ -0,0 +1,204 @@ +# +# Copyright (c) 2012, ARM Limited. All rights reserved. +# +# Redistribution and use in source and binary forms, with +# or without modification, are permitted provided that the +# following conditions are met: +# +# Redistributions of source code must retain the above +# copyright notice, this list of conditions and the +# following disclaimer. +# +# 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. +# +# Neither the name of ARM nor the names of its +# contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# + +# Decrease the verbosity of the make script +# can be made verbose by passing V=1 at the make command line +ifdef V + KBUILD_VERBOSE = $(V) +else + KBUILD_VERBOSE = 0 +endif + +ifeq "$(KBUILD_VERBOSE)" "0" + Q=@ +else + Q= +endif + +BUILD_RVCT?=FALSE +ifneq ($(BUILD_RVCT),TRUE) +CROSS_COMPILE?= +endif +VE?=TRUE +T2?=FALSE +L2_POLICY?=WF +LOBASE?=0x800 +KERNADDR?=$(LOBASE)08000 +KERNADDRBA?=$(LOBASE)00100 # must be KERNADDR - 0x7f00 +# megabyte at which the vectors are located (almost always zero) +VECTBASE?=$(LOBASE) +# Set the megabyte that the BIOS code will execute at +HIBASE?=0x8FF +FSADDR?=0x8e400000 +DEBUG=TRUE + +ifeq ($(BUILD_RVCT),TRUE) +CC = $(CROSS_COMPILE)armcc +AS = $(CROSS_COMPILE)armasm +LD = $(CROSS_COMPILE)armlink +CFLAGS += $(CFLAGS_RVCT) +ASFLAGS += $(ASFLAGS_RVCT) +LDFLAGS += $(LDFLAGS_RVCT) +APP = cat +LOADMAP_FLAGS += -R +else +CC = $(CROSS_COMPILE)gcc +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +CFLAGS += $(CFLAGS_GNU) +ASFLAGS += $(ASFLAGS_GNU) +LDFLAGS += $(LDFLAGS_GNU) +APP = ../scripts/armasm2gas.pl +LOADMAP_FLAGS += -G +endif +CPP = $(CC) -E +LOADMAP = ../scripts/loadmap + +BOOTARGS ?= mem=255M console=ttyAMA0,115200 migration_cost=500 cachepolicy=writealloc root=/dev/mmcblk0p2 + +CPPFLAGS = \ + -DBOOTARGS="$(BOOTARGS)" \ + -DL2_POLICY_$(L2_POLICY) \ + -DHIBASE=$(HIBASE) \ + -DSETUPMMU=$(SETUPMMU) \ + -DVECTBASE=$(VECTBASE) \ + -DKERNADDR=$(KERNADDR) \ + -DKERNADDRBA=$(KERNADDRBA) \ + -DFSADDR=$(FSADDR) + +ifeq ($(BUILD_RVCT),TRUE) +CPPFLAGS += --md +else +CPPFLAGS += -MD +endif + +ifeq ($(VE),TRUE) +CPPFLAGS += -DVE +endif +ifeq ($(T2),TRUE) +CPPFLAGS += -DT2 +endif +ifeq ($(BUILD_RVCT),TRUE) +CPPFLAGS += -DBUILD_RVCT +endif + +ASFLAGS_RVCT = --apcs /inter --cpu=Eagle --keep +ASFLAGS_GNU = -mcpu=cortex-a15 -mfpu=vfpv3 + +CFLAGS_RVCT = --cpu=Eagle --fpu=none +CFLAGS_GNU = -march=armv7-a -marm -ffreestanding + +LDFLAGS_RVCT = --map --no_remove --entry $(VECTBASE)00000 --scatter $(LDSCRIPT) +LDFLAGS_GNU = --print-map -e $(VECTBASE)00000 -T $(LDSCRIPT) + +ifdef DEBUG +CFLAGS += -g -O0 +ASFLAGS += -g +else +CFLAGS += -O2 +endif + +OBJS= boot.o bootargs.o c_start.o helpers.o kernel.o filesystem.o uart.o \ + vectors.o bl_sec.embed.o bl.embed.o + +ifneq ($(BUILD_RVCT),TRUE) +# Extra library objects to replace ARM C library functionality: +OBJS += printf.o vsnprintf.o string.o ldiv0.o idiv0.o \ + $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +endif + +LDSCRIPT = boot.scf +EMBED_LDSCRIPTS = bl.embed.scf bl_sec.embed.scf + +.PHONY: all +all: img.axf + +-include *.d + +.PHONY: bl +bl: + $(MAKE) -C big-little bl.axf + +.PHONY: bl_sec +bl_sec: + $(MAKE) -C big-little bl_sec.axf wboot.bin + +.PHONY: clean + +clean: + @echo " CLEAN" + $(Q)rm -f *.o img.axf *.map bl.S bl_sec.S *.s *.spp *.scf *.embed.* *.d + $(MAKE) -C big-little clean + +# Since we potentially need an extra preprocessing step, cancel the normal +# built-in rule for .S files: +%.o: %.S + +%.s: %.S + @echo " APP $<" + $(Q)$(CPP) $(CPPFLAGS) -o $@pp $< + $(Q)$(APP) <$@pp >$@ + +%.o: %.s + @echo " AS $<" + $(Q)$(AS) $(ASFLAGS) -o $@ $< + +%.o: %.c + @echo " CC $<" + $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< + +.PHONY: scripts +ifeq ($(BUILD_RVCT),TRUE) +scripts: ; +else +scripts: + $(MAKE) -C ../scripts +endif + +%.scf: %.scf.S + @echo " SCF $<" + $(Q)$(CPP) $(CPPFLAGS) $< | grep -v ^# >$@ + +# Prevent these from being auto-deleted as intermediates: +big-little/bl.axf: +big-little/bl_sec.axf: + +big-little/%.axf: + $(MAKE) -C big-little $*.axf + +$(LOADMAP): + $(MAKE) -C ../scripts loadmap + +%.embed.S: big-little/%.axf $(LOADMAP) + @echo " MAP[AS] $<" + $(Q)$(LOADMAP) $(LOADMAP_FLAGS) -s $< >$@ + +boot.scf: $(EMBED_LDSCRIPTS) + +%.embed.scf: big-little/%.axf $(LOADMAP) + @echo " MAP[LD] $<" + $(Q)$(LOADMAP) $(LOADMAP_FLAGS) -k $< >$@ + +img.axf: $(OBJS) boot.scf + @echo " LD $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $(OBJS) >img.map + diff --git a/linaro/arm-virt-bl/bootwrapper/acsr b/linaro/arm-virt-bl/bootwrapper/acsr new file mode 120000 index 0000000..87fe232 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/acsr @@ -0,0 +1 @@ +../acsr
\ No newline at end of file diff --git a/linaro/arm-virt-bl/bootwrapper/big-little b/linaro/arm-virt-bl/bootwrapper/big-little new file mode 120000 index 0000000..a482b29 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/big-little @@ -0,0 +1 @@ +../big-little
\ No newline at end of file diff --git a/linaro/arm-virt-bl/bootwrapper/big-little-mp1.mxscript b/linaro/arm-virt-bl/bootwrapper/big-little-mp1.mxscript new file mode 100755 index 0000000..b007e3d --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/big-little-mp1.mxscript @@ -0,0 +1,71 @@ +// Replace the string with the absolute path of the Kingfisher model executable +// e.g. string model = "/home/working_dir/RTSM_VE_Cortex-A15x1-A7x1"; +string model = "<path to the model>"; + +// Replace the string with the absolute path of the Virutalizer+Payload software image +// e.g. string app = "/home/working_dir/bootwrapper/img.axf" +string app = "<path to the software image>"; + +int ctr = 0; + +// NOTE +// +// Uncomment the next 4 'string' variables and update them _only_ if the run is required +// to generate trace output as described in docs/04-Cache-hit-rate-howto.txt. Also, +// comment out the system() invocation on line 47 and uncomment the system() command on line 34. +// Each 'trace' parameter is described below. + +// Add the path to the trace plugin +// string trace_plugin = " --trace-plugin <path to>/GenericTrace.so"; + +// Parameters for selecting the trace sources to monitor outbound cache hits +// string trace_sources = " --parameter TRACE.GenericTrace.trace-sources=\*sw_trace_event\*,\*read_for_3_came_from_snoop\*,\*read_for_4_came_from_snoop\* "; + +// Add the path to the trace file where all the output will be collected +// string trace_file = " --parameter TRACE.GenericTrace.trace-file=<path to trace file> "; + +// Miscellaneous parameters. The frequency at which the performance metrics of the +// model appear in the trace source can be changed here (default is 0x100). +// string trace_misc = " -C TRACE.GenericTrace.perf-period=0x100 -C TRACE.GenericTrace.flush=1 "; + +// The commented 'system' command below will launch the model and register the trace +// sources selected in 'trace_sources' with the Generic Trace plugin selected using +// 'trace_plugin'. Other parameters are specified in 'trace_file' & 'trace_misc'. +// system(model + trace_plugin + trace_sources + trace_file + trace_misc + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// NOTE +// +// _Only_ if a run is needed using an optional rootfs MMC image built using the instructions in +// docs/06-Optional-rootfs-build.txt, then comment out the system() invocation +// below (on line 47) and uncomment the following lines taking care to update +// the paths accordingly. +// string mmcimage = "<path to mmc.img>"; +// system(model + " -C motherboard.mmc.p_mmc_file=" + mmcimage + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Invoke the model. It then listens for connection requests from the model debugger +// Vanilla invocation of the model. +system(model + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Wait for the model to load before connecting to it. There will be times when we +// try connecting before the model has loded resulting in a "Connection refused" +// error. Increasing 'ctr' or retrying should solve the problem. +while(ctr < 400000000) +{ + ctr++; +} + +// Model listens at port 7000 +connectToModel("7000"); + +// The following lines can be uncommented to set any breakpoints on each cluster +selectTarget("coretile.cluster0.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); + +// Select the primary cpu on the primary cluster and set the ball rolling +selectTarget("coretile.cluster0.cpu0"); +run(); + diff --git a/linaro/arm-virt-bl/bootwrapper/big-little-mp4.mxscript b/linaro/arm-virt-bl/bootwrapper/big-little-mp4.mxscript new file mode 100755 index 0000000..96bc6bf --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/big-little-mp4.mxscript @@ -0,0 +1,89 @@ +// Replace the string with the absolute path of the Kingfisher model executable +// e.g. string model = "/home/working_dir/models/RTSM_VE_Cortex-A15x4-A7x4" +string model = "<path to the model>"; + +// Replace the string with the absolute path of the Virutalizer+Payload software image +// e.g. string app = "/home/working_dir/bootwrapper/img.axf" +string app = "<path to the software image>"; + +int ctr = 0; + +// NOTE +// +// Uncomment the next 4 'string' variables and update them _only_ if the run is required +// to generate trace output as described in docs/04-Cache-hit-rate-howto.txt. Also, +// comment out the system() invocation on line 47 and uncomment the system() command on line 34. +// Each 'trace' parameter is described below. + +// Add the path to the trace plugin +// string trace_plugin = " --trace-plugin <path to>/GenericTrace.so"; + +// Parameters for selecting the trace sources to monitor outbound cache hits +// string trace_sources = " --parameter TRACE.GenericTrace.trace-sources=\*sw_trace_event\*,\*read_for_3_came_from_snoop\*,\*read_for_4_came_from_snoop\* "; + +// Add the path to the trace file where all the output will be collected +// string trace_file = " --parameter TRACE.GenericTrace.trace-file=<path to trace file> "; + +// Miscellaneous parameters. The frequency at which the performance metrics of the +// model appear in the trace source can be changed here (default is 0x100). +// string trace_misc = " -C TRACE.GenericTrace.perf-period=0x100 -C TRACE.GenericTrace.flush=1 "; + +// The commented 'system' command below will launch the model and register the trace +// sources selected in 'trace_sources' with the Generic Trace plugin selected using +// 'trace_plugin'. Other parameters are specified in 'trace_file' & 'trace_misc'. +// system(model + trace_plugin + trace_sources + trace_file + trace_misc + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// NOTE +// +// _Only_ if a run is needed using an optional rootfs MMC image built using the instructions in +// doc/06-Optional-rootfs-build.txt, then comment out the system() invocation +// below (on line 47) and uncomment the following lines taking care to update +// the paths accordingly. +// string mmcimage = "<path to mmc.img>"; +// system(model + " -C motherboard.mmc.p_mmc_file=" + mmcimage + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Invoke the model. It then listens for connection requests from the model debugger +// Vanilla invocation of the model. +system(model + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Wait for the model to load before connecting to it. There will be times when we +// try connecting before the model has loded resulting in a "Connection refused" +// error. Increasing 'ctr' or retrying should solve the problem. +while(ctr < 400000000) +{ + ctr++; +} + +// Model listens at port 7000 +connectToModel("7000"); + +// The following lines can be uncommented to set any breakpoints on each cluster +selectTarget("coretile.cluster0.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster0.cpu1"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster0.cpu2"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster0.cpu3"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu1"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu2"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu3"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); + +// Select the primary cpu on the primary cluster and set the ball rolling +selectTarget("coretile.cluster0.cpu0"); +run(); + diff --git a/linaro/arm-virt-bl/bootwrapper/bl-mp1-fm-eac.mxscript b/linaro/arm-virt-bl/bootwrapper/bl-mp1-fm-eac.mxscript new file mode 100755 index 0000000..7a7912e --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/bl-mp1-fm-eac.mxscript @@ -0,0 +1,76 @@ +// Replace the string with the absolute path of the Kingfisher model executable +// e.g. string model = "/home/working_dir/RTSM_VE_Cortex-A15x1-A7x1"; +string model = "<path to the model>"; + +// Replace the string with the absolute path of the Virutalizer+Payload software image +// e.g. string app = "/home/working_dir/bootwrapper/img.axf" +string app = "<path to the software image>"; + +// Replace the string with the absolute path of the wboot.bin image created in the +// bootwrapper/big-little directory. This image is load in flash at 0x0 and distinguishes +// between a warm and a cold reset +string wboot = "<path to warm reset handler image>"; + +int ctr = 0; + +// NOTE +// +// Uncomment the next 4 'string' variables and update them _only_ if the run is required +// to generate trace output as described in docs/04-Cache-hit-rate-howto.txt. Also, +// comment out the system() invocation on line 47 and uncomment the system() command on line 34. +// Each 'trace' parameter is described below. + +// Add the path to the trace plugin +// string trace_plugin = " --trace-plugin <path to>/GenericTrace.so"; + +// Parameters for selecting the trace sources to monitor outbound cache hits +// string trace_sources = " --parameter TRACE.GenericTrace.trace-sources=\*sw_trace_event\*,\*read_for_3_came_from_snoop\*,\*read_for_4_came_from_snoop\* "; + +// Add the path to the trace file where all the output will be collected +// string trace_file = " --parameter TRACE.GenericTrace.trace-file=<path to trace file> "; + +// Miscellaneous parameters. The frequency at which the performance metrics of the +// model appear in the trace source can be changed here (default is 0x100). +// string trace_misc = " -C TRACE.GenericTrace.perf-period=0x100 -C TRACE.GenericTrace.flush=1 "; + +// The commented 'system' command below will launch the model and register the trace +// sources selected in 'trace_sources' with the Generic Trace plugin selected using +// 'trace_plugin'. Other parameters are specified in 'trace_file' & 'trace_misc'. +// system(model + trace_plugin + trace_sources + trace_file + trace_misc + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// NOTE +// +// _Only_ if a run is needed using an optional rootfs MMC image built using the instructions in +// docs/06-Optional-rootfs-build.txt, then comment out the system() invocation +// below (on line 47) and uncomment the following lines taking care to update +// the paths accordingly. +// string mmcimage = "<path to mmc.img>"; +// system(model + " -C motherboard.mmc.p_mmc_file=" + mmcimage + trace_plugin + trace_sources + trace_file + trace_misc + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Invoke the model. It then listens for connection requests from the model debugger +// Vanilla invocation of the model. +system(model + " -C motherboard.flashloader0.fname=" + wboot + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Wait for the model to load before connecting to it. There will be times when we +// try connecting before the model has loded resulting in a "Connection refused" +// error. Increasing 'ctr' or retrying should solve the problem. +while(ctr < 400000000) +{ + ctr++; +} + +// Model listens at port 7000 +connectToModel("7000"); + +// The following lines can be uncommented to set any breakpoints on each cluster +selectTarget("coretile.cluster0.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); + +// Select the primary cpu on the primary cluster and set the ball rolling +selectTarget("coretile.cluster0.cpu0"); +run(); + diff --git a/linaro/arm-virt-bl/bootwrapper/bl-mp4-fm-eac.mxscript b/linaro/arm-virt-bl/bootwrapper/bl-mp4-fm-eac.mxscript new file mode 100755 index 0000000..6099351 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/bl-mp4-fm-eac.mxscript @@ -0,0 +1,94 @@ +// Replace the string with the absolute path of the Kingfisher model executable +// e.g. string model = "/home/working_dir/models/RTSM_VE_Cortex-A15x4-A7x4" +string model = "<path to the model>"; + +// Replace the string with the absolute path of the Virutalizer+Payload software image +// e.g. string app = "/home/working_dir/bootwrapper/img.axf" +string app = "<path to the software image>"; + +// Replace the string with the absolute path of the wboot.bin image created in the +// bootwrapper/big-little directory. This image is load in flash at 0x0 and distinguishes +// between a warm and a cold reset +string wboot = "<path to warm reset handler image>"; + +int ctr = 0; + +// NOTE +// +// Uncomment the next 4 'string' variables and update them _only_ if the run is required +// to generate trace output as described in docs/04-Cache-hit-rate-howto.txt. Also, +// comment out the system() invocation on line 47 and uncomment the system() command on line 34. +// Each 'trace' parameter is described below. + +// Add the path to the trace plugin +// string trace_plugin = " --trace-plugin <path to>/GenericTrace.so"; + +// Parameters for selecting the trace sources to monitor outbound cache hits +// string trace_sources = " --parameter TRACE.GenericTrace.trace-sources=\*sw_trace_event\*,\*read_for_3_came_from_snoop\*,\*read_for_4_came_from_snoop\* "; + +// Add the path to the trace file where all the output will be collected +// string trace_file = " --parameter TRACE.GenericTrace.trace-file=<path to trace file> "; + +// Miscellaneous parameters. The frequency at which the performance metrics of the +// model appear in the trace source can be changed here (default is 0x100). +// string trace_misc = " -C TRACE.GenericTrace.perf-period=0x100 -C TRACE.GenericTrace.flush=1 "; + +// The commented 'system' command below will launch the model and register the trace +// sources selected in 'trace_sources' with the Generic Trace plugin selected using +// 'trace_plugin'. Other parameters are specified in 'trace_file' & 'trace_misc'. +// system(model + trace_plugin + trace_sources + trace_file + trace_misc + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// NOTE +// +// _Only_ if a run is needed using an optional rootfs MMC image built using the instructions in +// doc/06-Optional-rootfs-build.txt, then comment out the system() invocation +// below (on line 47) and uncomment the following lines taking care to update +// the paths accordingly. +// string mmcimage = "<path to mmc.img>"; +// system(model + " -C motherboard.mmc.p_mmc_file=" + mmcimage + trace_plugin + trace_sources + trace_file + trace_misc + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Invoke the model. It then listens for connection requests from the model debugger +// Vanilla invocation of the model. +system(model + " -C motherboard.flashloader0.fname=" + wboot + " -C coretile.cache_state_modelled=1" + " -a coretile.cluster0.\*=" + app + " -a coretile.cluster1.\*=" + app + " --verbose -S &"); + +// Wait for the model to load before connecting to it. There will be times when we +// try connecting before the model has loded resulting in a "Connection refused" +// error. Increasing 'ctr' or retrying should solve the problem. +while(ctr < 400000000) +{ + ctr++; +} + +// Model listens at port 7000 +connectToModel("7000"); + +// The following lines can be uncommented to set any breakpoints on each cluster +selectTarget("coretile.cluster0.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster0.cpu1"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster0.cpu2"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster0.cpu3"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu0"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu1"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu2"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); +selectTarget("coretile.cluster1.cpu3"); +//bpAdd(<address>, "Normal"); +//bpAdd(<address>, "Secure"); + +// Select the primary cpu on the primary cluster and set the ball rolling +selectTarget("coretile.cluster0.cpu0"); +run(); + diff --git a/linaro/arm-virt-bl/bootwrapper/boot.S b/linaro/arm-virt-bl/bootwrapper/boot.S new file mode 100755 index 0000000..a4f879d --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/boot.S @@ -0,0 +1,199 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + AREA |.text.boot|, CODE, ALIGN=2 + PRESERVE8 + +#include "emubuild.S" + + IMPORT __use_no_semihosting_swi + IMPORT __use_no_heap_region + IMPORT output_string + IMPORT c_start + IMPORT enable_coherency + IMPORT stack + IMPORT stack_size + IMPORT hexword + IMPORT read_sctlr + IMPORT write_sctlr + IMPORT get_sp + IMPORT inv_icache_all + + EXPORT start + EXPORT dabort + EXPORT fiq + EXPORT irq + EXPORT pabort + EXPORT swi + EXPORT undef + EXPORT unused + EXPORT dead + +;------------------------------------------------------------------------------ +; Boot code starts here - identify the CPU type, set up stacks and call c_start +;------------------------------------------------------------------------------ +start + bl inv_icache_all + ;------------------------------------------------------------------ + ; Enable ICache, branch predictor and alignment + ;------------------------------------------------------------------ + bl read_sctlr + bic r0, r0, #CR_C + orr r0, r0, #CR_Z + orr r0, r0, #CR_I + ;------------------------------------------------------------------ + ; Set U bit - the C compiler produces non-64-bit-aligned LDRD/STRDs + ;------------------------------------------------------------------ + orr r0, #CR_U + bl write_sctlr + + ;------------------------------------------------------------------ + ; Give yourself a stack to make things easier + ;------------------------------------------------------------------ + ldr r0, =stack + ldr r1, =stack_size + ldr r1, [r1] + bl get_sp + mov sp, r0 + + ;------------------------------------------------------------------ + ; Caches are inavlidated at reset & MMU is off. So its safe to + ; enable coherency + ;------------------------------------------------------------------ +;; bl enable_coherency + + ;------------------------------------------------------------------ + ; TODO: Enable MMU & coherency here + ;------------------------------------------------------------------ + + ;------------------------------------------------------------------ + ; Jump to the C handler + ;------------------------------------------------------------------ + bl c_start + + ;------------------------------------------------------------------ + ; Should never come here + ;------------------------------------------------------------------ +kernel_returned + b kernel_returned + +; ============================================================================== +; End of main code +; ============================================================================== + +; ============================================================================== +; Message strings, etc. +; ============================================================================== + + LTORG + ALIGN + +dabort_string + DCB " Emubuild-DAB!", 0 +undef_string + DCB " Emubuild-UND!", 0 +pabort_string + DCB " Emubuild-PAB!", 0 +swi_string + DCB " Emubuild-SWI!", 0 +irq_string + DCB " Emubuild-IRQ!", 0 +fiq_string + DCB " Emubuild-FIQ!", 0 +unused_string + DCB " Emubuild-UNU!", 0 + + ALIGN + +; ============================================================================== +; Exception handlers - for most exceptions we spin +; ============================================================================== + +dabort + mov r12, lr ; save lr, just in case it's interesting + + mov r0, r12 + bl hexword + + mrc p15,0,r0,c5,c0,0 ; DFSR + bl hexword + + mrc p15,0,r0,c6,c0,0 ; DFAR + bl hexword + + ldr r0, =dabort_string + bl output_string + b dead + +undef + push {r0-r1} + ldr r0, [lr,#-4] ; load undeffing instruction + ldr r1, =0xf57ff000 ; ignore unimplemented DSB/DMB/ISB/CLRX + bic r0, r0, #0x000000ff + cmp r0, r1 + popeq {r0-r1} + bxeq lr + mov r0, lr ; print lr, just in case it's interesting + bl hexword + ldr r0, =undef_string + bl output_string + b dead + +pabort + mov r0, lr ; print lr, just in case it's interesting + bl hexword + ldr r0, =pabort_string + bl output_string + b dead + +swi + mov r0, lr ; print lr, just in case it's interesting + bl hexword + ldr r0, =swi_string + bl output_string + b dead + +irq + mov r0, lr ; print lr, just in case it's interesting + bl hexword + ldr r0, =irq_string + bl output_string + b dead + +fiq + mov r0, lr ; print lr, just in case it's interesting + bl hexword + ldr r0, =fiq_string + bl output_string + b dead + +unused + mov r0, lr ; print lr, just in case it's interesting + bl hexword + ldr r0, =unused_string + bl output_string + b dead + +dead + B dead + + END diff --git a/linaro/arm-virt-bl/bootwrapper/boot.scf.S b/linaro/arm-virt-bl/bootwrapper/boot.scf.S new file mode 100644 index 0000000..222d857 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/boot.scf.S @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include "scf-macros.h" + +#ifdef BUILD_RVCT + +VECTORS PASTE(VECTBASE,00000) 0x100 +{ + VECTORSEXEC PASTE(VECTBASE,00000) 0x100 + { + vectors.o (+RO,+RW,+ZI) + } +} + +KERNELBA KERNADDRBA 0x4000 +{ + KERNELBA KERNADDRBA 0x4000 + { + bootargs.o (+RO,+RW,+ZI) + } +} + +KERNEL KERNADDR 0x800000 +{ + KERNEL KERNADDR 0x800000 + { + kernel.o (kernel) + } +} + +FILESYSTEM FSADDR 0x2000000 +{ + FILESYSTEM FSADDR 0x2000000 + { + filesystem.o (filesystem) + } +} + +/* + * BIOS code is placed in the last 128kB of RAM + * Linux can just be told to use 0-HIBASEMB + */ +HIGHCODE PASTE(HIBASE,E0000) 0x00018000 +{ + HIGHCODEALL +0 + { + *.o (*) + } +} + +/* Include generated load map info for payload binaries: */ +#include "bl.embed.scf" +#include "bl_sec.embed.scf" + +#else /* ! BUILD_RVCT */ + +SECTIONS { + +/* + * Include generated load map info for payload binaries: + * These must go first so that wildcards don't pull these into other sections. + */ +#include "bl.embed.scf" +#include "bl_sec.embed.scf" + + VECTORS PASTE(VECTBASE,00000) : { + vectors.o(.text .text.*) + } + + KERNELBA KERNADDRBA : { + bootargs.o(.data .data.*) + } + + KERNEL KERNADDR : { + kernel.o(.rodata .rodata.*) + } + + FILESYSTEM FSADDR : { + filesystem.o(.rodata .rodata.*) + } + +/* + * BIOS code is placed in the last 128kB of RAM + * Linux can just be told to use 0-HIBASEMB + */ + HIGHCODE PASTE(HIBASE,E0000) : { + *(.text .text.*) + *(.rodata .rodata.*) + } + + HIGHDATA : { + *(.data .data.*) + *(COMMON) + *(.bss .bss.*) + } + +/* Include debug information sections: */ + .debug_line 0 : { *(.debug_line) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_ranges 0 : { *(.debug_ranges) } + .debug_str 0 : { *(.debug_str) } + + /DISCARD/ : { + *(*) + } + +} + +#endif /* ! BUILD_RVCT */ + diff --git a/linaro/arm-virt-bl/bootwrapper/bootargs.S b/linaro/arm-virt-bl/bootwrapper/bootargs.S new file mode 100644 index 0000000..4adbaae --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/bootargs.S @@ -0,0 +1,80 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + AREA |.data.bootargs|, DATA, READWRITE, ALIGN=8 + PRESERVE8 + + EXPORT bootargs + EXPORT param_biosep + IMPORT fs_start + IMPORT fs_length +#include "emubuild.S" + +#if !L2_POLICY_NC +#define _ARGS BOOTARGS l2=alreadyon +#else +#define _ARGS BOOTARGS nol2x0 +#endif + +#define _STR(x...) __STR(x) +#define __STR(x...) #x +#define ARGS _STR(_ARGS) + +; ============================================================================== +; Linux "Tagged List" is declared here (see linux/Documentation/arm/Booting) +; ============================================================================== + ALIGN 256 ; gets us to 0x100 - where Linux expects +tags ; to find its boot tags +; 0x100 + DCD 0x00000005 ; Size = 5 words + DCD 0x54410001 ; ATAG_CORE + DCD 0x00000000 ; Flags + DCD 0x00000000 ; PageSize + DCD 0x00000000 ; RootDev +; 0x114 +bootargs_atag +#if BUILD_RVCT + DCD (4*2 + 1 + :LEN:ARGS + 1 + 20 + 3) / 4 ; Size in words +#else + DCD ((end_cmdline - bootargs_atag) + 3) / 4 ; Size in words +#endif + DCD 0x54410009 ; ATAG_CMDLINE + + ; Basic command line, probably the same as compiled into the kernel + DCB " " +bootargs + DCB ARGS + DCB " " + ; Reserve some space for "biosep=0x<bios_entrypoint>" bootarg +param_biosep SPACE 20 + ALIGN 4 +end_cmdline +initrd2 + DCD 0x00000004 ; Size = 4 words + DCD 0x54420005 + DCD fs_start + DCD fs_length + DCD 0x00000000 ; Size = 0 words + DCD 0x00000000 ; ATAG_NONE - end of list + ALIGN 4 + + END diff --git a/linaro/arm-virt-bl/bootwrapper/bootwrapper.h b/linaro/arm-virt-bl/bootwrapper/bootwrapper.h new file mode 100644 index 0000000..8e39d86 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/bootwrapper.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __BOOTWRAPPER_H__ +#define __BOOTWRAPPER_H__ + +/* A stack of 128 words per cpu */ +#define STACK_SIZE 256 +#define NUM_CPUS 4 +#define NUM_CLUSTERS 4 +#define TRUE 1 +#define FALSE 0 +#define PLATFORM_MASK 0x0FFFFFFF + +/* Permissions for architected timers/counters */ +#define PL1PCTEN (1 << 0) +#define PL1PCEN (1 << 1) +#define PL0PCTEN (1 << 0) +#define PL0VCTEN (1 << 1) +#define PL0VTEN (1 << 8) +#define PL0PTEN (1 << 9) +#define CP15_TIMER_FREQ 12000000 + +#define VERSATILE_EXPRESS 2272 +#define UART0_BASE 0X1C090000 +#define VE_SYS_BASE 0X1C010000 +#define CCI_BASE 0x2C090000 +#define SECURE_ACCESS_REG 0x8 +#define FLAGS_SET 0x30 +#define FLAGS_CLR 0x34 + +#define VE_KFSCB_BASE 0x10020000 /* Kingfisher System Configuration Block */ +#define KFS_ID_OFFSET 0xFFC /* Kingfisher System Platform ID register offset (KFS_ID) */ +#define KFS_ID_ARCH_MASK 0x000F0000 /* Mask for extracting KFS architecture */ +#define KFS_ID_ARCH_SHIFT 16 /* Shift for extracting KFS architecture */ +#define KFS_CFG_R 0x30 /* Kingfisher System static configuration read register */ +#define ACTIVE_CLUSTER_MASK 0x3 /* Returns the value that was driven on the CFG_ACTIVECLUSTER configuration inputs at the last system power-on reset. */ +#define KFS_CFG_R_OFFSET 0x30 /* Kingfisher System Static Configuration Read register */ +#define ACTIVE_CLUSTER_MASK 0x3 /* Returns the value that was driven on the CFG_ACTIVECLUSTER configuration input */ + +#define CLUSTER_CPU_COUNT(x) (((read32(VE_KFSCB_BASE + KFS_CFG_R) >> 16) >> (x << 2)) & 0xf) +#define write32(addr, val) (*(volatile unsigned int *)(addr) = (val)) +#define read32(addr) (*(volatile unsigned int *)(addr)) + +extern void config_uart(void); +extern void drain_uart_fifo(void); +extern void start(void); + +#endif /* __BOOTWRAPPER_H__ */ diff --git a/linaro/arm-virt-bl/bootwrapper/c_start.c b/linaro/arm-virt-bl/bootwrapper/c_start.c new file mode 100644 index 0000000..fd25394 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/c_start.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#include <stdio.h> +#include <string.h> +#include "helpers.h" +#include "bootwrapper.h" +#include "vgic.h" + +extern void *vector_table, *__entry_bl_sec; +extern void __entry_bl(unsigned, unsigned, unsigned, unsigned); +extern void kernel_start(int, int, int, int); + +/* Reserve some stack space - STACK_SIZE words per CPU */ +unsigned stack[NUM_CPUS * STACK_SIZE]; +unsigned stack_size = STACK_SIZE * sizeof(unsigned); +unsigned char cpus_ready[NUM_CLUSTERS][NUM_CPUS]; +volatile unsigned model_pen = 0; + +unsigned gic_int_num(void) +{ + unsigned intcount = 0; + + intcount = read32(GIC_ID_PHY_BASE + GICD_CTR); + intcount = ((intcount & 0x1F) + 1) * 32; + + return intcount; +} + +/* + * Function to configure the GIC ready for use in Non-Secure State + */ +void setup_gic_nonsecure(unsigned cluster_id, unsigned cpu_id) +{ + unsigned ctr = 0, num_ints = gic_int_num(); + + /* Ensure all GIC interrupts are Non-Secure */ + write32(GIC_ID_PHY_BASE + GICD_SEC + (ctr << 2), 0xffffffff); /* IRQs 0-31 are Non-Secure */ + if (cpu_id == 0 && cluster_id == 0) { + for (ctr = 1; ctr <= (num_ints >> 5); ctr++) + write32(GIC_ID_PHY_BASE + GICD_SEC + (ctr << 2), 0xffffffff); /* Set all SPIs as non-secure */ + } + + /* Ensure all interrupts can get through the priority mask */ + write32(GIC_IC_PHY_BASE + GICC_PRIMASK, 0xff); +} + +/* + * Function to send wakeup IPI to the secondary CPUs + */ +void kick(unsigned cpu_id, int secondary_cpus) +{ + int cpu_mask = ((1 << (secondary_cpus + 1)) - 1) & ~(1 << cpu_id); + + write32(VE_SYS_BASE + FLAGS_CLR, 0xffffffff); // clear the flags register + write32(VE_SYS_BASE + FLAGS_SET, (unsigned)start); // set the start address in the flags register + write32(GIC_ID_PHY_BASE, 0x1); // turn on the GIC distributor + write32(GIC_IC_PHY_BASE, 0x1); // turn on the GIC CPU interface + write32(GIC_ID_PHY_BASE + GICD_SW, cpu_mask << 16); // send an interrupt to everyone else +} + +/* + * This function doesn't retun - it waits for an address to be + * written into the FLAGs register, then jumps to that address. + */ +void secondary_main(unsigned cluster_id, unsigned cpu_id) +{ + unsigned val; + void (*secondary_start) (void); + + /* Ensure I cache is on and interrupts are masked */ + inv_icache_all(); + write_sctlr(read_sctlr() | (1 << 12)); + write_cpsr(read_cpsr() | 0x80); + + /* tell CPU0 that we are ready */ + cpus_ready[cluster_id][cpu_id] = 1; + + /* + * We're not the primary core, so we need to wait for the primary + * core to tell us what to do. While doing that, go into WFI so we + * don't just sit here consuming system resources (i.e. bus + * badwidth); make sure a soft IRQ gets through to the core, but + * don't actually take the interrupt - that way we'll come out of + * WFI without worrying about interrupt vectors (which may have gone + * away, since the primary core is playing with our memory). + */ + write32(GIC_IC_PHY_BASE + GICC_CTL, 0x1); /* Enable GIC CPU Interface */ + write32(GIC_IC_PHY_BASE + GICC_PRIMASK, 0x000000f0); /* Set Priority Mask to allow interrupts */ + + /* If the start address isn't already set, go to sleep */ + while (val = read32(VE_SYS_BASE + FLAGS_SET), val == 0 + || val == (unsigned)start) { + wfi(); + /* Acknowledge the interrupt that woke us */ + /* Read the Acknowledge register, write End Of Interrupt */ + write32(GIC_IC_PHY_BASE + GICC_EOI, + read32(GIC_IC_PHY_BASE + GICC_INTACK)); + } + + /* TODO: If MMU is enabled, then synchronise caches here */ + secondary_start = (void (*)())val; + secondary_start(); /* No return from here */ +} + +void wait_for_secondaries(unsigned active_clusters, unsigned secondary_cpus) +{ + int i, j, ready; + + printf("Waiting for %d secondary CPUs\n", secondary_cpus); + + while (TRUE) { + ready = 0; + + for (i = 0; i < active_clusters; i++) { + for (j = 0; j < NUM_CPUS; j++) { + if (cpus_ready[i][j]) { + ++ready; + } + } + } + + if (ready == secondary_cpus) { + break; + } + + /* Don't thrash the memory system, give the secondaries some time */ + for (j = 0; j < 1000; ++j) { +#if !BUILD_RVCT +#define __nop() asm("nop") +#endif + + __nop(); + } + } +} + +/* + * Function to determine number of clusters in the system. + * The way to do this will differ on different systems. + * Add support for the system you are running on. + * At the moment, it supports Kingfisher dual cluster. + */ +int get_cluster_count(void) +{ + unsigned int kfs_id, active_clusters; + int num_clusters = 0; + + kfs_id = read32(VE_KFSCB_BASE + KFS_ID_OFFSET); + + switch (((kfs_id & KFS_ID_ARCH_MASK) >> KFS_ID_ARCH_SHIFT)) { + case 0: + case 1: + case 2: + case 3: + active_clusters = + read32(VE_KFSCB_BASE + + KFS_CFG_R_OFFSET) & ACTIVE_CLUSTER_MASK; + num_clusters = (active_clusters == 0x3) ? 2 : 1; + break; + } + + return num_clusters; +} + +void c_start(void) +{ + unsigned cpu_id = read_cpuid(); + unsigned cluster_id = read_clusterid(); + unsigned secondary_cpus = 0; + unsigned platform = VERSATILE_EXPRESS; + unsigned active_clusters = get_cluster_count(); + + secondary_cpus = CLUSTER_CPU_COUNT(cluster_id) - 1; + if (active_clusters > 1) { + secondary_cpus += CLUSTER_CPU_COUNT(!cluster_id); + } + + write_vbar((unsigned)&vector_table); + write_mvbar((unsigned)&__entry_bl_sec); + if (cpu_id == 0 && cluster_id == 0) + config_uart(); + + enable_user_perfmon_access(); + enable_perfmon(); + enable_swp(); + write_cpacr(read_cpacr() | 0xfffffff); + write_nsacr(0x00073fff); + enable_coherency(); + + /* Also grant NS access to CCI registers */ + if (cpu_id == 0 && cluster_id == 0) + write32(CCI_BASE + SECURE_ACCESS_REG, 0x1); + + /* + * Secondaries wait here while initialisation of global peripherals is done + */ + if (model_pen == 0 && (cpu_id || cluster_id)) { + do { + wfe(); + } while (model_pen == 0); + } + + setup_gic_nonsecure(cluster_id, cpu_id); + + if (cpu_id == 0 && cluster_id == 0) { + model_pen = 1; + dsb(); + sev(); + } + + enter_monitor_mode(); + write_scr(0x131); /* HVC, NS, FW and AW bits */ + write_cnthctl(PL1PCTEN | PL1PCEN); + write_cntkctl(PL0PCTEN | PL0VCTEN | PL0VTEN | PL0PTEN); + write_cntfrq(CP15_TIMER_FREQ); + + /* Start secondary CPUs, if any */ + if (cpu_id == 0 && cluster_id == 0 && secondary_cpus > 0) { + printf("Kicking %d secondary CPU(s)\n", secondary_cpus); + drain_uart_fifo(); + kick(cpu_id, secondary_cpus); + } + + enter_nonsecure_world((unsigned)__entry_bl); + + /* Secondary CPUs go off to secondary_main() */ + if (cpu_id || cluster_id) { + secondary_main(cluster_id, cpu_id); /* no return */ + } + + /* Primary waits for the secondaries to get ready before loading the payload */ + wait_for_secondaries(active_clusters, secondary_cpus); + + /* Load the payload kernel */ + printf("Kernel entry point 0x%x (%s)\n", kernel_start, + ((unsigned)kernel_start & 1) ? "thumb" : "arm"); + + drain_uart_fifo(); + + /* Clear FLAGS register, as this is what Linux expects to find */ + write32(VE_SYS_BASE + FLAGS_CLR, 0xffffffff); + + /* TODO: If MMU is enabled then caches need to be cleaned here */ + + /* Start the kernel */ + kernel_start(0, platform & PLATFORM_MASK, 0, 0); /* No return from here */ + + return; +} diff --git a/linaro/arm-virt-bl/bootwrapper/emubuild.S b/linaro/arm-virt-bl/bootwrapper/emubuild.S new file mode 100644 index 0000000..6ff1a94 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/emubuild.S @@ -0,0 +1,50 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + +;; CPSR Mode bits definitions +USR_MODE EQU 16 +FIQ_MODE EQU 17 +IRQ_MODE EQU 18 +SVC_MODE EQU 19 +MON_MODE EQU 22 +ABT_MODE EQU 23 +UND_MODE EQU 27 +SYS_MODE EQU 31 + +;; CPSR mask bit definitions +CPSR_A EQU (1<<8) +CPSR_I EQU (1<<7) +CPSR_F EQU (1<<6) + +;; Control Register bits definition +CR_U EQU (1<<22) +CR_I EQU (1<<12) +CR_C EQU (1<<2) +CR_M EQU (1<<0) +CR_W EQU (1<<3) +CR_Z EQU (1<<11) +CR_XP EQU (1<<23) + +PAGE_MASK EQU ~0xfff + +CLIENT_ACCESS EQU 0x55555555 +MANAGER_ACCESS EQU 0xffffffff diff --git a/linaro/arm-virt-bl/bootwrapper/filesystem.S b/linaro/arm-virt-bl/bootwrapper/filesystem.S new file mode 100644 index 0000000..ab822ac --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/filesystem.S @@ -0,0 +1,29 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + AREA |.rodata.filesystem|, DATA, READONLY, ALIGN=2 + + EXPORT fs_start + EXPORT fs_length +fs_start + INCBIN payload/fsimg +fs_length EQU . - fs_start + END diff --git a/linaro/arm-virt-bl/bootwrapper/helpers.S b/linaro/arm-virt-bl/bootwrapper/helpers.S new file mode 100755 index 0000000..57cd1b8 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/helpers.S @@ -0,0 +1,1320 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + EXPORT wfi + EXPORT wfe + EXPORT sev + EXPORT dmb + EXPORT dsb + EXPORT isb + EXPORT smc + EXPORT dcisw + EXPORT dccsw + EXPORT dccisw + + EXPORT read_dacr + EXPORT read_ttbr0 + EXPORT read_cpacr + EXPORT read_scr + EXPORT read_cpsr + EXPORT read_midr + EXPORT read_mpidr + EXPORT read_cntpct + EXPORT read_cntfrq + EXPORT read_vmpidr + EXPORT read_vmidr + EXPORT read_id_pfr0 + EXPORT read_id_pfr1 + EXPORT read_id_dfr0 + EXPORT read_id_afr0 + EXPORT read_id_mmfr0 + EXPORT read_id_mmfr1 + EXPORT read_id_mmfr2 + EXPORT read_id_mmfr3 + EXPORT read_id_isar0 + EXPORT read_id_isar1 + EXPORT read_id_isar2 + EXPORT read_id_isar3 + EXPORT read_id_isar4 + EXPORT read_id_isar5 + EXPORT read_cpuid + EXPORT read_aidr + EXPORT read_ctr + EXPORT read_tcmtr + EXPORT read_tlbtr + EXPORT read_clusterid + EXPORT read_sctlr + EXPORT read_hsctlr + EXPORT read_hdfar + EXPORT read_hpfar + EXPORT read_vtcr + EXPORT read_hcr + EXPORT read_hdcr + EXPORT read_hcptr + EXPORT read_hstr + EXPORT read_cnthctl + EXPORT read_cntkctl + EXPORT read_cntp_ctl + EXPORT read_cntp_tval + EXPORT read_cnthp_ctl + EXPORT read_cnthp_tval + EXPORT read_cnthp_cval + EXPORT read_ttbcr + EXPORT read_clidr + EXPORT read_lr + EXPORT read_sp + EXPORT read_actlr + EXPORT read_nsacr + EXPORT read_clidr + EXPORT read_csselr + EXPORT read_ccsidr + EXPORT read_nmrr + EXPORT read_prrr + EXPORT read_mvbar + EXPORT read_vbar + EXPORT read_hsr + EXPORT read_dfar + EXPORT read_ifar + EXPORT read_dfsr + EXPORT read_ifsr + EXPORT read_adfsr + EXPORT read_aifsr + + EXPORT write_dacr + EXPORT write_prrr + EXPORT write_nmrr + EXPORT write_ttbr0 + EXPORT write_cpacr + EXPORT write_nsacr + EXPORT write_cpsr + EXPORT write_scr + EXPORT write_mvbar + EXPORT write_vbar + EXPORT write_hvbar + EXPORT write_vmpidr + EXPORT write_vmidr + EXPORT write_csselr + EXPORT write_hcr + EXPORT write_hdcr + EXPORT write_hcptr + EXPORT write_hstr + EXPORT write_sctlr + EXPORT write_actlr + EXPORT write_sp + EXPORT write_lr + EXPORT write_ttbcr + EXPORT write_cntfrq + EXPORT write_cnthctl + EXPORT write_cntkctl + EXPORT write_cntp_ctl + EXPORT write_cntp_tval + EXPORT write_cnthp_ctl + EXPORT write_cnthp_tval + EXPORT write_cnthp_cval + EXPORT write_hsctlr + EXPORT write_httbr + EXPORT write_vttbr + EXPORT write_htcr + EXPORT write_vtcr + EXPORT write_hmair0 + EXPORT write_hmair1 + EXPORT write_dfar + EXPORT write_ifar + EXPORT write_dfsr + EXPORT write_ifsr + EXPORT write_adfsr + EXPORT write_aifsr + + EXPORT panic + EXPORT spin_lock + EXPORT spin_trylock + EXPORT spin_unlock + EXPORT copy_words + EXPORT virt_memset + EXPORT disable_gic_dist + EXPORT enable_gic_dist + EXPORT switcher_exit + EXPORT hyp_save + EXPORT num_secondaries + EXPORT virt_dead + EXPORT get_sp + EXPORT disable_coherency + EXPORT enable_coherency + EXPORT inv_tlb_all + EXPORT inv_icache_all + EXPORT inv_bpred_is + EXPORT inv_bpred_all + EXPORT inv_icache_mva_pou + EXPORT inv_dcache_mva_poc + EXPORT cln_dcache_mva_pou + EXPORT cln_dcache_mva_poc + EXPORT enable_user_perfmon_access + EXPORT enable_perfmon + EXPORT enable_swp + EXPORT cache_maint_op + EXPORT enter_monitor_mode + EXPORT enter_nonsecure_world + EXPORT enable_pmu + +; Cache maintenance op types +INV EQU 0x0 +CLN EQU 0x1 +CLN_INV EQU 0x2 + + AREA |.text|, CODE + +read_cntfrq FUNCTION + mrc p15, 0, r0, c14, c0, 0 + bx lr + ENDFUNC + +write_cntfrq FUNCTION + mcr p15, 0, r0, c14, c0, 0 + bx lr + ENDFUNC + +read_cntpct FUNCTION + mrrc p15, 0, r2, r3, c14 + str r2, [r0] + str r3, [r1] + bx lr + ENDFUNC + +dcisw FUNCTION + mcr p15, 0, r0, c7, c6, 2 + bx lr + ENDFUNC + +dccsw FUNCTION + mcr p15, 0, r0, c7, c10, 2 + bx lr + ENDFUNC + +dccisw FUNCTION + mcr p15, 0, r0, c7, c14, 2 + bx lr + ENDFUNC + +virt_dead FUNCTION + b virt_dead + ENDFUNC + +disable_gic_dist FUNCTION + push {lr} + ldr r2, [r1] + str r2, [r0] + mov r2, #0 + str r2, [r1] + dsb + pop {pc} + ENDFUNC + +enable_gic_dist FUNCTION + push {lr} + str r0, [r1] + dsb + pop {pc} + ENDFUNC + +smc FUNCTION + push {r4-r12, lr} + smc #0 + pop {r4-r12, pc} + ENDFUNC + +dmb FUNCTION + dmb + bx lr + ENDFUNC + +wfi FUNCTION + wfi + bx lr + ENDFUNC + +wfe FUNCTION + wfe + bx lr + ENDFUNC + +sev FUNCTION + sev + bx lr + ENDFUNC + +switcher_exit FUNCTION + hvc #1 + bx lr + ENDFUNC + +hyp_save FUNCTION + hvc #2 + bx lr + ENDFUNC + + ; This function takes three arguments + ; r0: Destination start address (must be word aligned) + ; r1: Source start address (must be word aligned) + ; r2: Number of words to copy + ; Return value is updated destination pointer (first unwritten word) +copy_words FUNCTION + push {r4, r5} +0 cmp r2, #3 + ble %f1 + ldmia r1!, {r3, r4, r5, r12} + stmia r0!, {r3, r4, r5, r12} + sub r2, r2, #4 + b %b0 + +1 cmp r2, #0 + beq %f3 +2 ldr r3, [r1], #4 + str r3, [r0], #4 + subs r2, r2, #1 + bne %b2 + +3 pop {r4, r5} + bx lr + ENDFUNC + + +virt_memcpy FUNCTION + cmp r2, #0 + bxeq lr +0 ldrb r3, [r1], #1 + strb r3, [r0], #1 + subs r2, #1 + bne %b0 + bx lr + ENDFUNC + +virt_memset FUNCTION + cmp r2, #0 + bxeq lr +0 strb r1, [r0], #1 + subs r2, #1 + bne %b0 + bx lr + ENDFUNC + + AREA |.text.APPF_ENTRY_POINT|, CODE + + ; Functions we need in the runtime entry point, i.e. before we switch pagetables, + ; are placed in this area. + +dsb FUNCTION + dsb + bx lr + ENDFUNC + +isb FUNCTION + isb + bx lr + ENDFUNC + +num_secondaries FUNCTION + mrc p15, 1, r0, c9, c0, 2 + lsr r0, r0, #24 + and r0, r0, #3 + bx lr + ENDFUNC + +read_vmpidr FUNCTION + mrc p15, 4, r0, c0, c0, 5 + bx lr + ENDFUNC + +read_vmidr FUNCTION + mrc p15, 4, r0, c0, c0, 0 + bx lr + ENDFUNC + +read_id_pfr0 FUNCTION + mrc p15, 0, r0, c0, c1, 0 + bx lr + ENDFUNC + +read_id_pfr1 FUNCTION + mrc p15, 0, r0, c0, c1, 1 + bx lr + ENDFUNC + +read_id_dfr0 FUNCTION + mrc p15, 0, r0, c0, c1, 2 + bx lr + ENDFUNC + +read_id_afr0 FUNCTION + mrc p15, 0, r0, c0, c1, 3 + bx lr + ENDFUNC + +read_id_mmfr0 FUNCTION + mrc p15, 0, r0, c0, c1, 4 + bx lr + ENDFUNC + +read_id_mmfr1 FUNCTION + mrc p15, 0, r0, c0, c1, 5 + bx lr + ENDFUNC + +read_id_mmfr2 FUNCTION + mrc p15, 0, r0, c0, c1, 6 + bx lr + ENDFUNC + +read_id_mmfr3 FUNCTION + mrc p15, 0, r0, c0, c1, 7 + bx lr + ENDFUNC + +read_id_isar0 FUNCTION + mrc p15, 0, r0, c0, c2, 0 + bx lr + ENDFUNC + +read_id_isar1 FUNCTION + mrc p15, 0, r0, c0, c2, 1 + bx lr + ENDFUNC + +read_id_isar2 FUNCTION + mrc p15, 0, r0, c0, c2, 2 + bx lr + ENDFUNC + +read_id_isar3 FUNCTION + mrc p15, 0, r0, c0, c2, 3 + bx lr + ENDFUNC + +read_id_isar4 FUNCTION + mrc p15, 0, r0, c0, c2, 4 + bx lr + ENDFUNC + +read_id_isar5 FUNCTION + mrc p15, 0, r0, c0, c2, 5 + bx lr + ENDFUNC + +read_ctr FUNCTION + mrc p15, 0, r0, c0, c0, 1 + bx lr + ENDFUNC + +read_tcmtr FUNCTION + mrc p15, 0, r0, c0, c0, 2 + bx lr + ENDFUNC + +read_tlbtr FUNCTION + mrc p15, 0, r0, c0, c0, 3 + bx lr + ENDFUNC + +read_aidr FUNCTION + mrc p15, 1, r0, c0, c0, 7 + bx lr + ENDFUNC + +va_to_pa FUNCTION ; Note: assumes conversion will be successful! + mov r1, r0 + mcr p15, 0, r0, c7, c8, 1 ; Priv Write Current World VA-PA + mrc p15, 0, r0, c7, c4, 0 ; Get PA + bfc r0, #0, #12 ; We want top bits of translated addr + bfc r1, #12, #20 ; plus bottom bits of input addr + orr r0, r0, r1 + bx lr + ENDFUNC + +read_dacr FUNCTION + mrc p15, 0, r0, c3, c0, 0 + bx lr + ENDFUNC + +read_ttbr0 FUNCTION + mrc p15, 0, r0, c2, c0, 0 + dsb + bx lr + ENDFUNC + +write_dacr FUNCTION + mcr p15, 0, r0, c3, c0, 0 + isb + bx lr + ENDFUNC + +read_cpacr FUNCTION + mrc p15, 0, r0, c1, c0, 2 + bx lr + ENDFUNC + +write_cpacr FUNCTION + mcr p15, 0, r0, c1, c0, 2 + bx lr + ENDFUNC + +read_midr FUNCTION + mrc p15, 0, r0, c0, c0, 0; + bx lr + ENDFUNC + +read_mpidr FUNCTION + mrc p15, 0, r0, c0, c0, 5 + bx lr + ENDFUNC + +read_scr FUNCTION + mrc p15, 0, r0, c1, c1, 0 + bx lr + ENDFUNC + +write_scr FUNCTION + mcr p15, 0, r0, c1, c1, 0 + isb + dsb + bx lr + ENDFUNC + +write_nsacr FUNCTION + mcr p15, 0, r0, c1, c1, 2 + isb + dsb + bx lr + ENDFUNC + +read_cpsr FUNCTION + mrs r0, CPSR + bx lr + ENDFUNC + +write_cpsr FUNCTION + msr CPSR_c, r0 + bx lr + ENDFUNC + +write_mvbar FUNCTION + mcr p15, 0, r0, c12, c0, 1 + bx lr + ENDFUNC + +write_vbar FUNCTION + mcr p15, 0, r0, c12, c0, 0 + bx lr + ENDFUNC + +write_hvbar FUNCTION + mcr p15, 4, r0, c12, c0, 0 + bx lr + ENDFUNC + +read_mvbar FUNCTION + mrc p15, 0, r0, c12, c0, 1 + bx lr + ENDFUNC + +read_vbar FUNCTION + mrc p15, 0, r0, c12, c0, 0 + bx lr + ENDFUNC + +read_cpuid FUNCTION + mrc p15, 0, r0, c0, c0, 5 + ands r0, r0, #0xf + bx lr + ENDFUNC + +read_clusterid FUNCTION + mrc p15, 0, r0, c0, c0, 5 + lsr r0, r0, #0x8 + ands r0, r0, #0xf + bx lr + ENDFUNC + +write_ttbr0 FUNCTION + mcr p15, 0, r0, c2, c0, 0 + mcr p15, 0, r0, c7, c5, 6 + mcr p15, 0, r0, c8, c7, 0 + isb + dsb + bx lr + ENDFUNC + +read_ttbcr FUNCTION + mrc p15, 0, r0, c2, c0, 2 + bx lr + ENDFUNC + +write_ttbcr FUNCTION + mcr p15, 0, r0, c2, c0, 2 + bx lr + ENDFUNC + +write_vmpidr FUNCTION + mcr p15, 4, r0, c0, c0, 5 + isb + bx lr + ENDFUNC + +write_vmidr FUNCTION + mcr p15, 4, r0, c0, c0, 0 + isb + bx lr + ENDFUNC + +read_vtcr FUNCTION + mrc p15, 4, r0, c2, c1, 2 + bx lr + ENDFUNC + +read_hcr FUNCTION + mrc p15, 4, r0, c1, c1, 0 + bx lr + ENDFUNC + +read_hdcr FUNCTION + mrc p15, 4, r0, c1, c1, 1 + bx lr + ENDFUNC + +read_hcptr FUNCTION + mrc p15, 4, r0, c1, c1, 2 + bx lr + ENDFUNC + +read_hstr FUNCTION + mrc p15, 4, r0, c1, c1, 3 + bx lr + ENDFUNC + +write_hcr FUNCTION + mcr p15, 4, r0, c1, c1, 0 + isb + dsb + bx lr + ENDFUNC + +write_hdcr FUNCTION + mcr p15, 4, r0, c1, c1, 1 + bx lr + ENDFUNC + +write_hcptr FUNCTION + mcr p15, 4, r0, c1, c1, 2 + bx lr + ENDFUNC + +write_hstr FUNCTION + mcr p15, 4, r0, c1, c1, 3 + bx lr + ENDFUNC + +write_httbr FUNCTION + mcrr p15, 4, r0, r1, c2 + mcr p15, 0, r0, c7, c5, 6 + mcr p15, 0, r0, c8, c7, 0 + isb + dsb + bx lr + ENDFUNC + +write_vttbr FUNCTION + mcrr p15, 6, r0, r1, c2 + mcr p15, 0, r0, c7, c5, 6 + mcr p15, 0, r0, c8, c7, 0 + isb + dsb + bx lr + ENDFUNC + +write_htcr FUNCTION + mcr p15, 4, r0, c2, c0, 2 + bx lr + ENDFUNC + +write_vtcr FUNCTION + mcr p15, 4, r0, c2, c1, 2 + bx lr + ENDFUNC + +write_hmair0 FUNCTION + mcr p15, 4, r0, c10, c2, 0 + bx lr + ENDFUNC + +write_hmair1 FUNCTION + mcr p15, 4, r0, c10, c2, 1 + bx lr + ENDFUNC + +read_nsacr FUNCTION + mrc p15, 0, r0, c1, c1, 2 + bx lr + ENDFUNC + +read_sctlr FUNCTION + mrc p15, 0, r0, c1, c0, 0 + bx lr + ENDFUNC + +write_sctlr FUNCTION + mcr p15, 0, r0, c1, c0, 0 + isb + dsb + bx lr + ENDFUNC + +read_hsctlr FUNCTION + mrc p15, 4, r0, c1, c0, 0 + bx lr + ENDFUNC + +read_hdfar FUNCTION + mrc p15, 4, r0, c6, c0, 0 + bx lr + ENDFUNC + +read_hpfar FUNCTION + mrc p15, 4, r0, c6, c0, 4 + bx lr + ENDFUNC + +read_hsr FUNCTION + mrc p15, 4, r0, c5, c2, 0 + bx lr + ENDFUNC + +write_hsctlr FUNCTION + mcr p15, 4, r0, c1, c0, 0 + isb + dsb + bx lr + ENDFUNC + +read_cnthctl FUNCTION + mrc p15, 4, r0, c14, c1, 0 + bx lr + ENDFUNC + +read_cntkctl FUNCTION + mrc p15, 0, r0, c14, c1, 0 + bx lr + ENDFUNC + +read_cnthp_cval FUNCTION + mrrc p15, 6, r0, r1, c14 + bx lr + ENDFUNC + +read_cnthp_tval FUNCTION + mrc p15, 4, r0, c14, c2, 0 + bx lr + ENDFUNC + +read_cntp_tval FUNCTION + mrc p15, 0, r0, c14, c2, 0 + bx lr + ENDFUNC + +read_cntp_ctl FUNCTION + mrc p15, 0, r0, c14, c2, 1 + bx lr + ENDFUNC + +read_cnthp_ctl FUNCTION + mrc p15, 4, r0, c14, c2, 1 + bx lr + ENDFUNC + +write_cnthctl FUNCTION + mcr p15, 4, r0, c14, c1, 0 + bx lr + ENDFUNC + +write_cntkctl FUNCTION + mcr p15, 0, r0, c14, c1, 0 + bx lr + ENDFUNC + +write_cntp_tval FUNCTION + mcr p15, 0, r0, c14, c2, 0 + isb + bx lr + ENDFUNC + +write_cntp_ctl FUNCTION + mcr p15, 0, r0, c14, c2, 1 + isb + dsb + bx lr + ENDFUNC + +write_cnthp_cval FUNCTION + mcrr p15, 6, r0, r1, c14 + isb + dsb + bx lr + ENDFUNC + +write_cnthp_tval FUNCTION + mcr p15, 4, r0, c14, c2, 0 + isb + dsb + bx lr + ENDFUNC + +write_cnthp_ctl FUNCTION + mcr p15, 4, r0, c14, c2, 1 + isb + dsb + bx lr + ENDFUNC + +read_clidr FUNCTION + mrc p15, 1, r0, c0, c0, 1 ; read clidr + bx lr + ENDFUNC + +read_ccsidr FUNCTION + mrc p15, 1, r0, c0, c0, 0 ; read ccsidr + bx lr + ENDFUNC + +read_csselr FUNCTION + mrc p15, 2, r0, c0, c0, 0 ; read csselr + bx lr + ENDFUNC + +write_csselr FUNCTION + mcr p15, 2, r0, c0, c0, 0 ; read csselr + isb + dsb + bx lr + ENDFUNC + +read_actlr FUNCTION + mrc p15, 0, r0, c1, c0, 1 + bx lr + ENDFUNC + +write_actlr FUNCTION + mcr p15, 0, r0, c1, c0, 1 + isb + dsb + bx lr + ENDFUNC + +read_prrr FUNCTION + mrc p15, 0, r0, c10, c2, 0 + bx lr + ENDFUNC + +read_nmrr FUNCTION + mrc p15, 0, r0, c10, c2, 1 + bx lr + ENDFUNC + +write_prrr FUNCTION + mcr p15, 0, r0, c10, c2, 0 + isb + dsb + bx lr + ENDFUNC + +write_nmrr FUNCTION + mcr p15, 0, r0, c10, c2, 1 + isb + dsb + bx lr + ENDFUNC + +read_dfar FUNCTION + mrc p15, 0, r0, c6, c0, 0 + bx lr + ENDFUNC + +read_ifar FUNCTION + mrc p15, 0, r0, c6, c0, 2 + bx lr + ENDFUNC + +read_dfsr FUNCTION + mrc p15, 0, r0, c5, c0, 0 + bx lr + ENDFUNC + +read_ifsr FUNCTION + mrc p15, 0, r0, c5, c0, 1 + bx lr + ENDFUNC + +read_adfsr FUNCTION + mrc p15, 0, r0, c5, c1, 0 + bx lr + ENDFUNC + +read_aifsr FUNCTION + mrc p15, 0, r0, c5, c1, 1 + bx lr + ENDFUNC + +write_dfar FUNCTION + mcr p15, 0, r0, c6, c0, 0 + isb + dsb + bx lr + ENDFUNC + +write_ifar FUNCTION + mcr p15, 0, r0, c6, c0, 2 + isb + dsb + bx lr + ENDFUNC + +write_dfsr FUNCTION + mcr p15, 0, r0, c5, c0, 0 + isb + dsb + bx lr + ENDFUNC + +write_ifsr FUNCTION + mcr p15, 0, r0, c5, c0, 1 + isb + dsb + bx lr + ENDFUNC + +write_adfsr FUNCTION + mcr p15, 0, r0, c5, c1, 0 + isb + dsb + bx lr + ENDFUNC + +write_aifsr FUNCTION + mcr p15, 0, r0, c5, c1, 1 + isb + dsb + bx lr + ENDFUNC + +read_lr FUNCTION + ; Save r1 + push {r1} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r1, cpsr + and r1, r1, #0x1f + ; Check if the desired lr is of the current mode + cmp r0, r1 + moveq r0, LR + beq read_lr_out + ; Check if desired lr is of user mode + cmp r0, #0x10 + mrseq r0, LR_usr + beq read_lr_out + ; Check if desired lr is of supervisor mode + cmp r0, #0x13 + mrseq r0, LR_svc +read_lr_out + pop {r1} + bx lr + ENDFUNC + +write_lr FUNCTION + ; Save r2 + push {r2} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r2, cpsr + and r2, r2, #0x1f + ; Check if the lr is of the current mode + cmp r0, r2 + moveq LR, r1 + beq write_lr_out + ; Check if the lr is of user mode + cmp r0, #0x10 + msreq LR_usr, r1 + beq write_lr_out + ; Check if the lr is of supervisor mode + cmp r0, #0x13 + msreq LR_svc, r1 +write_lr_out + pop {r2} + bx lr + ENDFUNC + +read_sp FUNCTION + ; Save r1 + push {r1} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r1, cpsr + and r1, r1, #0x1f + ; Check if the desired sp is of the current mode + cmp r0, r1 + moveq r0, SP + beq read_sp_out + ; Check if desired sp is of user mode + cmp r0, #0x10 + mrseq r0, SP_usr + beq read_sp_out + ; Check if desired sp is of supervisor mode + cmp r0, #0x13 + mrseq r0, SP_svc + beq read_sp_out + ; Check if desired sp is of irq mode + cmp r0, #0x12 + mrseq r0, SP_irq + beq read_sp_out + ; Check if desired sp is of supervisor mode + cmp r0, #0x1a + mrseq r0, SP_hyp + beq read_sp_out + ; Check if desired sp is of monitor mode + cmp r0, #0x16 + mrseq r0, SP_mon +read_sp_out + pop {r1} + bx lr + ENDFUNC + +write_sp FUNCTION + ; Save r2 + push {r2} + and r0, r0, #0x1f + ; Read the current cpsr + mrs r2, cpsr + and r2, r2, #0x1f + ; Check if the sp is of the current mode + cmp r0, r2 + moveq SP, r1 + beq write_sp_out + ; Check if the sp is of user mode + cmp r0, #0x10 + msreq SP_usr, r1 + beq write_sp_out + ; Check if the sp is of supervisor mode + cmp r0, #0x13 + msreq SP_svc, r1 + beq write_sp_out + ; Check if the sp is of irq mode + cmp r0, #0x12 + msreq SP_irq, r1 + beq write_sp_out + ; Check if the sp is of hyp mode + cmp r0, #0x1a + msreq SP_hyp, r1 + beq write_sp_out + ; Check if the sp is of monitor mode + cmp r0, #0x16 + msreq SP_mon, r1 +write_sp_out + pop {r2} + bx lr + ENDFUNC + + ALIGN 4 + +;-------------------------------------------------------- +; spin_lock +;-------------------------------------------------------- +spin_lock FUNCTION + MOV r2, #1 +sl_tryloop + LDREX r1, [r0] + CMP r1, #0 + STREXEQ r1, r2, [r0] + CMPEQ r1, #0 + BNE sl_tryloop + MCR p15, 0, r0, c7, c10, 4 + bx lr + ENDFUNC + +;-------------------------------------------------------- +; spin_lock +;-------------------------------------------------------- +spin_trylock FUNCTION + MOV r2, #1 + LDREX r1, [r0] + CMP r1, #0 + STREXEQ r1, r2, [r0] + MOV r0, r1 + MCR p15, 0, r0, c7, c10, 4 + bx lr + ENDFUNC + + ALIGN 4 + +;-------------------------------------------------------- +; spin_unlock +;-------------------------------------------------------- +spin_unlock FUNCTION + MOV r1, #0 + STR r1, [r0] + MCR p15, 0, r0, c7, c10, 4 + bx lr + ENDFUNC + + ALIGN 4 + +;-------------------------------------------------------- +; panic +;-------------------------------------------------------- +panic FUNCTION + isb + dsb + CPSID aif + B panic + ENDFUNC + +;-------------------------------------------------------------- +; Utility function that takes a pointer (r0), stack size (r1). +; It returns the pointer to the stack offset for the asked cpu +;-------------------------------------------------------------- +get_sp FUNCTION + ldr r2, =0x2c001800 + ldr r2, [r2] + and r2, r2, #0xff + clz r2, r2 + mov r3, #32 + sub r2, r3, r2 + mul r2, r2, r1 + add r0, r0, r2 + bx lr + ENDFUNC + +disable_coherency FUNCTION + push {lr} + bl read_actlr + bic r0, r0, #0x40 + bl write_actlr + isb + dsb + pop {lr} + bx lr + ENDFUNC + +enable_coherency FUNCTION + push {lr} + bl read_actlr + orr r0, r0, #0x40 + bl write_actlr + isb + dsb + pop {lr} + bx lr + ENDFUNC + +inv_bpred_is FUNCTION + mcr p15, 0, r0, c7, c1, 6 + bx lr + ENDFUNC + +inv_bpred_all FUNCTION + mcr p15, 0, r0, c7, c5, 6 + bx lr + ENDFUNC + +inv_tlb_all FUNCTION + mcr p15, 0, r0, c8, c7, 0 + isb + dsb + bx lr + ENDFUNC + +inv_icache_all FUNCTION + mcr p15, 0, r10, c7, c5, 0 ; invalidate I cache + isb + dsb + bx lr + ENDFUNC + +inv_icache_mva_pou FUNCTION + mcr p15, 0, r0, c7, c5, 1 + isb + dsb + bx lr + ENDFUNC + +cln_dcache_mva_pou FUNCTION + mcr p15, 0, r0, c7, c11, 1 + isb + dsb + bx lr + ENDFUNC + +cln_dcache_mva_poc FUNCTION + mcr p15, 0, r0, c7, c10, 1 + isb + dsb + bx lr + ENDFUNC + +inv_dcache_mva_poc FUNCTION + mcr p15, 0, r0, c7, c6, 1 + isb + dsb + bx lr + ENDFUNC + + ; Clean/Invalidate/Clean and invalidate a specified cache level. + ; Ignore if the level does not exist. +cache_maint_op FUNCTION + push {r4-r11} + dsb + lsl r10, r0, #1 ; start clean at specified cache level + mrc p15, 1, r0, c0, c0, 1 ; read clidr +10 + add r2, r10, r10, lsr #1 ; work out 3x current cache level + mov r3, r0, lsr r2 ; extract cache type bits from clidr + and r3, r3, #7 ; mask of the bits for current cache only + cmp r3, #2 ; see what cache we have at this level + blt %f50 ; skip if no cache, or just i-cache + mcr p15, 2, r10, c0, c0, 0 ; select current cache level in cssr + isb ; isb to sych the new cssr&csidr + mrc p15, 1, r3, c0, c0, 0 ; read the new csidr + and r2, r3, #7 ; extract the length of the cache lines + add r2, r2, #4 ; add 4 (line length offset) + ldr r4, =0x3ff + ands r4, r4, r3, lsr #3 ; find maximum number on the way size + clz r5, r4 ; find bit position of way size increment + ldr r7, =0x7fff + ands r7, r7, r3, lsr #13 ; extract max number of the index size +20 + mov r9, r4 ; create working copy of max way size +30 + orr r11, r10, r9, lsl r5 ; factor way and cache number into r11 + lsl r6, r9, r5 + orr r11, r10, r6 ; factor way and cache number into r11 + orr r11, r11, r7, lsl r2 ; factor index number into r11 + lsl r6, r7, r2 + orr r11, r11, r6 ; factor index number into r11 + cmp r1, #INV + mcreq p15, 0, r11, c7, c6, 2 ; invalidate by set/way + beq %f40 + cmp r1, #CLN + mcreq p15, 0, r11, c7, c10, 2 ; clean by set/way + beq %f40 + mcr p15, 0, r11, c7, c14, 2 ; clean & invalidate by set/way +; nop ; nop +40 + subs r9, r9, #1 ; decrement the way + bge %b30 + subs r7, r7, #1 ; decrement the index + bge %b20 +50 + mov r10, #0 ; swith back to cache level 0 + mcr p15, 2, r10, c0, c0, 0 ; select current cache level in cssr + dsb + isb + pop {r4-r11} + bx lr + ENDFUNC + +enable_user_perfmon_access FUNCTION ; V7 and above + mov r0, #1 + mcr p15, 0, r0, c9, c14, 0 ; write PMUSERENR enable + bx lr + ENDFUNC + +enable_perfmon FUNCTION ; V7 and above + mov r0, #(1<<1)+(1<<2)+(1<<4) ; set C, P, X bits + mcr p15, 0, r0, c9, c12, 0 ; PMCR + mov r0, #(1<<31) ; cycle counter enable + mcr p15, 0, r0, c9, c12, 1 ; PMCNTENSET + bx lr + ENDFUNC + +enable_swp FUNCTION ; V7 and above + mrc p15, 0, r0, c1, c0, 0 + orr r0, #0x400 + mcr p15, 0, r0, c1, c0, 0 + bx lr + ENDFUNC + +enter_monitor_mode FUNCTION + mov r0, sp ; Save current sp + mov r2, lr ; Save current lr + mrs r1, cpsr ; Get current mode (SVC) in r1 + bic r3, r1, #0x1f ; Clear all mode bits + orr r3, r3, #0x16 ; Set bits for Monitor mode + msr cpsr_cxsf, r3 ; We are now in Monitor Mode + mov sp, r0 ; Use the same sp as before + mov lr, r2 ; Use the same lr as before + msr spsr_cxsf, r1 ; Use saved mode for the MOVS jump to the kernel + bx lr + ENDFUNC + +enter_nonsecure_world FUNCTION + push {r4-r7} + mov r4, sp ; Save current sp + mov r5, lr ; Save current lr + mrs r6, spsr ; Get target mode (SVC) in r6 + bic r7, r6, #0x1f ; Clear all mode bits + orr r7, r7, #0x1A ; Set bits for HYP mode + msr spsr_cxsf, r7 + adr lr, hyp_entry + movs pc, lr +hyp_entry ; We are now in HYP mode + ; Set the HYP spsr to itself, so that the entry point + ; does not see the difference between a function call + ; and an exception return. + msr spsr_cxsf, r7 + blx r0 + msr spsr_cxsf, r6 ; Setup SPSR to jump to NS SVC mode + adr r7, ns_svc_entry + msr elr_hyp, r7 + ERET +ns_svc_entry + mov sp, r4 + mov lr, r5 + pop {r4-r7} + bx lr + ENDFUNC + +enable_pmu FUNCTION + mov r0, #0x0000003f + mrc p15, 0, r1, c9, c14, 2 ; Disable overflow interrupts + orr r1, r1, r0 + mcr p15, 0, r1, c9, c14, 2 ; Disable overflow interrupts + isb + mrc p15, 0, r1, c9, c12, 3 ; Clear overflow flags + orr r1, r1, r0 + mcr p15, 0, r1, c9, c12, 3 ; Clear overflow flags + isb + mrc p15, 0, r1, c9, c12, 1 ; Enable counters + orr r1, r1, r0 + mcr p15, 0, r1, c9, c12, 1 ; Enable counters + isb + mov r0, #0x3 + mrc p15, 0, r1, c9, c12, 0 ; + orr r1, r1, r0 + mcr p15, 0, r1, c9, c12, 0 ; Reset and Master Enable counters + bx lr + ENDFUNC + + END diff --git a/linaro/arm-virt-bl/bootwrapper/helpers.h b/linaro/arm-virt-bl/bootwrapper/helpers.h new file mode 100644 index 0000000..07ffc47 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/helpers.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef _VIRT_HELPERS_H_ +#define _VIRT_HELPERS_H_ + +extern unsigned int DORMANT_BASE; +/******************************************************* + * Export prototypes of the functions which will be used + * to save/restore the Non-secure context. + *******************************************************/ +extern void wfe(void); +extern void sev(void); +extern void wfi(void); +extern void dmb(void); +extern void dsb(void); +extern void isb(void); +extern void virt_dead(void); +extern void smc(unsigned, unsigned); +extern void dcisw(unsigned); +extern void dccsw(unsigned); +extern void dccisw(unsigned); + +extern void write_sp(unsigned, unsigned); +extern void write_lr(unsigned, unsigned); +extern void write_cpsr(unsigned); +extern void write_sctlr(unsigned); +extern void write_actlr(unsigned); +extern void write_nsacr(unsigned); +extern void write_ttbr0(unsigned); +extern void write_ttbcr(unsigned); +extern void write_cntfrq(unsigned); +extern void write_cnthctl(unsigned); +extern void write_cntkctl(unsigned); +extern void write_cnthp_cval(unsigned, unsigned); +extern void write_cnthp_tval(unsigned); +extern void write_cnthp_ctl(unsigned); +extern void write_cntp_ctl(unsigned); +extern void write_cntp_tval(unsigned); +extern void write_csselr(unsigned); +extern void write_hcr(unsigned); +extern void write_hdcr(unsigned); +extern void write_hcptr(unsigned); +extern void write_hstr(unsigned); +extern void write_hsctlr(unsigned); +extern void write_httbr(unsigned long long); +extern void write_vttbr(unsigned long long); +extern void write_htcr(unsigned); +extern void write_vtcr(unsigned); +extern void write_hmair0(unsigned); +extern void write_hmair1(unsigned); +extern void write_vmpidr(unsigned); +extern void write_vmidr(unsigned); +extern void write_dacr(unsigned); +extern void write_ttbr0(unsigned); +extern void write_cpacr(unsigned); +extern void write_nsacr(unsigned); +extern void write_scr(unsigned); +extern void write_mvbar(unsigned); +extern void write_hvbar(unsigned); +extern void write_vbar(unsigned); +extern void write_prrr(unsigned); +extern void write_nmrr(unsigned); +extern void write_dfar(unsigned); +extern void write_ifar(unsigned); +extern void write_dfsr(unsigned); +extern void write_ifsr(unsigned); +extern void write_adfsr(unsigned); +extern void write_aifsr(unsigned); + +extern void read_cntpct(unsigned *, unsigned *); +extern unsigned read_dfar(void); +extern unsigned read_ifar(void); +extern unsigned read_dfsr(void); +extern unsigned read_ifsr(void); +extern unsigned read_adfsr(void); +extern unsigned read_aifsr(void); +extern unsigned read_cntfrq(void); +extern unsigned read_hsctlr(void); +extern unsigned read_hsr(void); +extern unsigned read_nmrr(void); +extern unsigned read_prrr(void); +extern unsigned read_dacr(void); +extern unsigned read_ttbr0(void); +extern unsigned read_cpacr(void); +extern unsigned read_scr(void); +extern unsigned read_cpsr(void); +extern unsigned read_midr(void); +extern unsigned read_mpidr(void); +extern unsigned read_vmpidr(void); +extern unsigned read_vmidr(void); +extern unsigned read_id_pfr0(void); +extern unsigned read_id_pfr1(void); +extern unsigned read_id_dfr0(void); +extern unsigned read_id_afr0(void); +extern unsigned read_id_mmfr0(void); +extern unsigned read_id_mmfr1(void); +extern unsigned read_id_mmfr2(void); +extern unsigned read_id_mmfr3(void); +extern unsigned read_id_isar0(void); +extern unsigned read_id_isar1(void); +extern unsigned read_id_isar2(void); +extern unsigned read_id_isar3(void); +extern unsigned read_id_isar4(void); +extern unsigned read_id_isar5(void); +extern unsigned read_aidr(void); +extern unsigned read_vbar(void); +extern unsigned read_mvbar(void); +extern unsigned read_ctr(void); +extern unsigned read_tcmtr(void); +extern unsigned read_tlbtr(void); +extern unsigned read_hcr(void); +extern unsigned read_hdcr(void); +extern unsigned read_hcptr(void); +extern unsigned read_hstr(void); +extern unsigned read_vtcr(void); +extern unsigned read_hdfar(void); +extern unsigned read_hpfar(void); +extern unsigned read_cpsr(void); +extern unsigned read_sp(unsigned); +extern unsigned read_lr(unsigned); +extern unsigned read_cpuid(void); +extern unsigned read_clusterid(void); +extern unsigned read_clidr(void); +extern unsigned read_ccsidr(void); +extern unsigned read_csselr(void); +extern unsigned read_sctlr(void); +extern unsigned read_actlr(void); +extern unsigned read_nsacr(void); +extern unsigned read_ttbr0(void); +extern unsigned read_ttbcr(void); +extern unsigned read_cnthctl(void); +extern unsigned read_cntkctl(void); +extern unsigned long read_cnthp_cval(void); +extern unsigned read_cnthp_tval(void); +extern unsigned read_cnthp_ctl(void); +extern unsigned read_cntp_ctl(void); +extern unsigned read_cntp_tval(void); +extern unsigned num_secondaries(void); +extern unsigned *copy_words(volatile unsigned *destination, + volatile unsigned *source, unsigned num_words); +extern unsigned *get_sp(unsigned, unsigned); + +/* + * V7 functions + */ +extern void save_performance_monitors(unsigned int *pointer); +extern void save_banked_registers(unsigned int *pointer); +extern void save_control_registers(unsigned int *context); +extern void save_mmu(unsigned int *pointer); +extern void save_cp15(unsigned int *pointer); + +extern void restore_control_registers(unsigned int *context); +extern void restore_mmu(unsigned int *pointer); +extern void restore_cp15(unsigned int *pointer); +extern void restore_performance_monitors(unsigned int *pointer); +extern void restore_banked_registers(unsigned int *pointer); +extern void disable_clean_inv_l1_dcache_v7(void); +extern void cache_maint_op(unsigned, unsigned); +extern unsigned get_loc(void); +extern void disable_coherency(void); +extern void disable_dcache(void); +extern void enable_coherency(void); +extern void enable_dcache(void); +extern void flush_to_loc(void); +extern void inv_tlb_all(void); +extern void inv_icache_all(void); +extern void inv_icache_mva_pou(unsigned *); +extern void inv_dcache_mva_poc(unsigned *); +extern void cln_dcache_mva_poc(unsigned *); +extern void cln_dcache_mva_pou(unsigned *); +extern void enable_user_perfmon_access(void); +extern void enable_perfmon(void); +extern void enable_swp(void); +extern void enable_pmu(void); +extern void enter_monitor_mode(void); +extern void enter_nonsecure_world(unsigned); + +/* + * GIC functions + */ +extern void save_gic_interface(unsigned int *pointer, + unsigned gic_interface_address); +extern int save_gic_distributor_private(unsigned int *pointer, + unsigned gic_distributor_address); +extern int save_gic_distributor_shared(unsigned int *pointer, + unsigned gic_distributor_address); +extern void restore_gic_interface(unsigned int *pointer, + unsigned gic_interface_address); +extern void restore_gic_distributor_private(unsigned int *pointer, + unsigned gic_distributor_address); +extern void restore_gic_distributor_shared(unsigned int *pointer, + unsigned gic_distributor_address); +extern void disable_gic_dist(unsigned int *tmp, + volatile unsigned int *dist_base); +extern void enable_gic_dist(unsigned int tmp, volatile unsigned int *dist_base); + +extern void switcher_exit(void); +extern void hyp_save(unsigned, unsigned); + +#endif /* _VIRT_HELPERS_H_ */ diff --git a/linaro/arm-virt-bl/bootwrapper/idiv0.c b/linaro/arm-virt-bl/bootwrapper/idiv0.c new file mode 120000 index 0000000..3ff8903 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/idiv0.c @@ -0,0 +1 @@ +../big-little/lib/idiv0.c
\ No newline at end of file diff --git a/linaro/arm-virt-bl/bootwrapper/kernel.S b/linaro/arm-virt-bl/bootwrapper/kernel.S new file mode 100644 index 0000000..52247a9 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/kernel.S @@ -0,0 +1,27 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + AREA |.rodata.kernel|, DATA, READONLY, ALIGN=2 + EXPORT kernel_start +kernel_start + INCBIN payload/kernel + END diff --git a/linaro/arm-virt-bl/bootwrapper/ldiv0.c b/linaro/arm-virt-bl/bootwrapper/ldiv0.c new file mode 120000 index 0000000..332c630 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/ldiv0.c @@ -0,0 +1 @@ +../big-little/lib/ldiv0.c
\ No newline at end of file diff --git a/linaro/arm-virt-bl/bootwrapper/payload/fsimg b/linaro/arm-virt-bl/bootwrapper/payload/fsimg new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/payload/fsimg diff --git a/linaro/arm-virt-bl/bootwrapper/printf.c b/linaro/arm-virt-bl/bootwrapper/printf.c new file mode 120000 index 0000000..c27e7ed --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/printf.c @@ -0,0 +1 @@ +../big-little/lib/printf.c
\ No newline at end of file diff --git a/linaro/arm-virt-bl/bootwrapper/scf-macros.h b/linaro/arm-virt-bl/bootwrapper/scf-macros.h new file mode 120000 index 0000000..74ceb1c --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/scf-macros.h @@ -0,0 +1 @@ +../big-little/scf-macros.h
\ No newline at end of file diff --git a/linaro/arm-virt-bl/bootwrapper/string.c b/linaro/arm-virt-bl/bootwrapper/string.c new file mode 120000 index 0000000..2f24a16 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/string.c @@ -0,0 +1 @@ +../big-little/lib/string.c
\ No newline at end of file diff --git a/linaro/arm-virt-bl/bootwrapper/uart.c b/linaro/arm-virt-bl/bootwrapper/uart.c new file mode 100644 index 0000000..eb32095 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/uart.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +/* + * uart.c - boot code to output characters on a PL011 uart + * Not SMP-safe, so make sure you only call these functions + * from one CPU at a time. + * Call config_uart first. + */ + +#include <stdio.h> + +#include "bootwrapper.h" +#include "helpers.h" + +//* PL011 Registers Offsets from UART Base adress */ +#define PL011_DR 0x0 +#define PL011_RSR 0x4 +#define PL011_ECR 0x4 +#define PL011_FR 0x18 +#define PL011_ILPR 0x20 +#define PL011_IBRD 0x24 +#define PL011_FBRD 0x28 +#define PL011_LCRH 0x2C +#define PL011_CR 0x30 +#define PL011_IFLS 0x34 +#define PL011_IMSC 0x38 +#define PL011_RIS 0x3C +#define PL011_MIS 0x40 +#define PL011_ICR 0x44 +#define PL011_DMACR 0x48 + +#define PL011_TXFE 0x80 +#define PL011_TXFF 0x20 + +typedef unsigned size_t; +typedef int ssize_t; + +static unsigned uart_base = 0; + +void config_uart(void) +{ + uart_base = UART0_BASE; + write32(uart_base + PL011_CR, 0); + write32(uart_base + PL011_FBRD, 0x01); + write32(uart_base + PL011_IBRD, 0x27); + write32(uart_base + PL011_LCRH, 0x70); + write32(uart_base + PL011_CR, 0xf01); /* TXE|RXE|En|DTR|CTS */ +} + +void drain_uart_fifo(void) +{ + while (!(read32(uart_base + PL011_FR) & PL011_TXFE)) { + /* Do nothing */ + } +} + +static __inline void wait_for_space(void) +{ + while ((read32(uart_base + PL011_FR) & PL011_TXFF)) { + /* Do nothing */ + } +} + +void output_char(int c) +{ + if (c == '\n') { + wait_for_space(); + write32(uart_base + PL011_DR, '\r'); + } + wait_for_space(); + write32(uart_base + PL011_DR, c); +} + +void output_string(const char *string) +{ + int i; + + for (i = 0; string[i]; ++i) { + output_char(string[i]); + } +} + +void hexword(unsigned value) +{ + printf(" 0x%8.8x", value); + drain_uart_fifo(); +} + +ssize_t _write(const void *buf, size_t count) +{ + const unsigned char *b = buf; + int c = count; + + while (c--) + output_char(*b++); + + return count; +} diff --git a/linaro/arm-virt-bl/bootwrapper/vectors.S b/linaro/arm-virt-bl/bootwrapper/vectors.S new file mode 100644 index 0000000..b03ae46 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/vectors.S @@ -0,0 +1,73 @@ + ; + ; Copyright (c) 2012, ARM Limited. All rights reserved. + ; + ; Redistribution and use in source and binary forms, with + ; or without modification, are permitted provided that the + ; following conditions are met: + ; + ; Redistributions of source code must retain the above + ; copyright notice, this list of conditions and the + ; following disclaimer. + ; + ; 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. + ; + ; Neither the name of ARM nor the names of its + ; contributors may be used to endorse or promote products + ; derived from this software without specific prior written + ; permission. + ; + + AREA |.text.vectors|, CODE, ALIGN=8 + PRESERVE8 + +; ============================================================================== +; Simple vector table +; ============================================================================== + IMPORT start + IMPORT undef + IMPORT swi + IMPORT pabort + IMPORT dabort + IMPORT unused + IMPORT irq + IMPORT fiq + EXPORT vector_table + +vector_table + LDR PC, pstart + LDR PC, pundef + LDR PC, pswi + LDR PC, ppabort + LDR PC, pdabort + LDR PC, punused + LDR PC, pirq + LDR PC, pfiq + +pstart + DCD start + +pundef + DCD undef + +pswi + DCD swi + +ppabort + DCD pabort + +pdabort + DCD dabort + +punused + DCD unused + +pirq + DCD irq + +pfiq + DCD fiq + + END diff --git a/linaro/arm-virt-bl/bootwrapper/vgic.h b/linaro/arm-virt-bl/bootwrapper/vgic.h new file mode 100644 index 0000000..084e593 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/vgic.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 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. + * + * Neither the name of ARM nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + */ + +#ifndef __VGIC_H__ +#define __VGIC_H__ + +#define GIC_ID_PHY_BASE 0x2C001000 /* Physical Distributor */ +#define GIC_IC_PHY_BASE 0x2C002000 /* Physical CPU interface */ + +/* Distributor interface registers */ +#define GICD_CTL 0x0 +#define GICD_CTR 0x4 +#define GICD_SEC 0x80 +#define GICD_ENABLESET 0x100 +#define GICD_ENABLECLEAR 0x180 +#define GICD_PENDINGSET 0x200 +#define GICD_PENDINGCLEAR 0x280 +#define GICD_ACTIVESET 0x300 +#define GICD_ACTIVECLEAR 0x380 +#define GICD_PRI 0x400 +#define GICD_CPUS 0x800 +#define GICD_CONFIG 0xC00 +#define GICD_SW 0xF00 +#define GICD_CPENDSGIR 0xF10 +#define GICD_SPENDSGIR 0xF20 + +/* Physical CPU Interface registers */ +#define GICC_CTL 0x0 +#define GICC_PRIMASK 0x4 +#define GICC_BP 0x8 +#define GICC_INTACK 0xC +#define GICC_EOI 0x10 +#define GICC_RUNNINGPRI 0x14 +#define GICC_HIGHESTPEND 0x18 +#define GICC_DEACTIVATE 0x1000 +#define GICC_PRIODROP GICC_EOI + +#endif /* __VGIC_H__ */ diff --git a/linaro/arm-virt-bl/bootwrapper/vsnprintf.c b/linaro/arm-virt-bl/bootwrapper/vsnprintf.c new file mode 120000 index 0000000..b7c7fd2 --- /dev/null +++ b/linaro/arm-virt-bl/bootwrapper/vsnprintf.c @@ -0,0 +1 @@ +../big-little/lib/vsnprintf.c
\ No newline at end of file diff --git a/linaro/arm-virt-bl/docs/01-Usage.txt b/linaro/arm-virt-bl/docs/01-Usage.txt new file mode 100644 index 0000000..39d3b7f --- /dev/null +++ b/linaro/arm-virt-bl/docs/01-Usage.txt @@ -0,0 +1,90 @@ +Usage +===== + +1. Requirements/Pre-requisites + + 1. A Linux development environment. This release has been + build tested on the following Linux host environments: + + 1. Linux Ubuntu 10.10 + 2. Red Hat Enterprise Linux WS release 4 (Nahant Update 4) + + This release is not intended to be used on development + environments other than Linux. + + 2. An installation of the ARM RealView Development Suite. This + release was built and tested with version 4.1 [Build 514]. + + 3. An installation of the Perl scripting language. This release + was built and tested with v5.10.1. + + 4. An installation of the GNU coreutils suite + <http://www.gnu.org/software/coreutils/>. This release was + built and tested with v8.5. + +2. Build instructions + + Note that this release relies on the 'env' utility, which is + a part of the coreutils suite. The 'env' utility is expected + to be located at '/bin/env'. If it is at a different + location then this must be reflected in the first line of + the following file: + + arm-virtualizer-v2_2-160212/bootwrapper/makemap + + Failure to make this modification will result in a build + failure. + + To build the software: + + $ tar -jxf arm-virtualizer-v2_2-160212.tar.bz2 + $ cd arm-virtualizer-v2_2-160212/bootwrapper + $ make clean && make + + The resulting file is 'img.axf'. + + This image may be loaded and executed on the model debugger + as explained in section 3 below. + + Note that the pre-built stub kernel image is located at: + + arm-virtualizer-v2_2-160212/bootwrapper/payload/kernel + + .. and the placeholder dummy root filesystem image is located + at: + + arm-virtualizer-v2_2-160212/bootwrapper/payload/fsimg + + These may be replaced with custom built images such as a + suitably configured linux kernel image and a root filesystem + image. + + Look at docs/03-Linux-kernel-build.txt for instructions on + building a suitable Linux kernel. + + Look at docs/06-Optional-rootfs-build.txt for optionally + building a complete root filesystem. + +3. Usage + + If the Real-Time System Model v7.0.1 (RTSM_VE_Cortex_A15x1_A7x1 + and RTSM_VE_Cortex_A15x4_A7x4) is installed, the resulting + img.axf file may be loaded, executed and debugged on the + model and the associated model debugger. + + This model may be obtained from ARM by separate arrangement. + + Steps to run the software: + + a. Depending upon whether the MPx1 or MPx4 model is being used, + update the big-little-mp<x>.mxscript file (x is 1 or + 4 as the case may be) with the absolute + path to the model and the img.axf file. (Comments in the + file indicate where the changes have to be made) + + b. Invoke the modeldebugger and the script file as follows: + + $ <path to modeldebugger> -s <path to big-little-mp<x>.mxscript> + + The default build simultaneously switches clusters + every 12 million cycles (appx). diff --git a/linaro/arm-virt-bl/docs/02-Code-layout.txt b/linaro/arm-virt-bl/docs/02-Code-layout.txt new file mode 100644 index 0000000..ba1690e --- /dev/null +++ b/linaro/arm-virt-bl/docs/02-Code-layout.txt @@ -0,0 +1,563 @@ +Code layout +=========== + +A Introduction + + The software contained in the 'bootwrapper' directory allows + the execution of a software payload e.g. a Linux stack to + alternate between two multi-core clusters of ARM Cortex-A15 + & Cortex-A7 processors connected by a coherent + interconnect. To achieve this aim it provides the ability + to: + + 1. Save the processor context on one cluster (henceforth + called the outbound cluster) and restore it on the other + cluster (henceforth called the inbound cluster). + + 2. Hide any software visible microarchitectural differences + between the Cortex-A15 & Cortex-A7 processors. + + 3. Use the ARM Virtualization Extensions to perform 1. and 2. + in a payload software agnostic manner. + + This software is intended to be executed on the Real-Time + System Model v7.0.1 (RTSM_VE_Cortex_A15x1_A7x1 and + RTSM_VE_Cortex_A15x4_A7x4). + + In addition to switching the payload software execution + between the two clusters, the software also contains support + for executing the payload software simultaneously on the two + clusters. + + This is called the MP configuration. In it's current state, + it mainly involves making the payload software believe that + the A15 cluster includes the cpus present on Cortex-A7 cluster + i.e.there is one cluster with more cpus that there + physically are. [Note that MP support is highly experimental + and unstable. It is NOT the focus of this release and is + intended for purely informational purposes. The cluster + swithing mode of operation remains the focus of this + release.] + + The Virtualizer software needs initialization prior to being + used to perform any of the above functions. The + initialization needs to be done before the payload software + is executed. Hence, it makes sense to do this from the + existing boot firmware being used on the platform. The code + in the 'bootwrapper' directory is a bareminimal bootloader + that: + + 1. Sets up the environment for execution of the payload + software in the Non-secure world by programming the + appropriate coprocessor and memory mapped peripheral + registers from the Secure world. + + 2. Invokes the entry point of the Virtualizer software + (bl_setup()) which does the necessary initialization. + + 3. Passes control to the payload software in the Non-secure + world. + +B Code layout overview + + 1. bootwrapper/ + + Apart from containing the bootloader, this directory + also contains scatter files to load the bootloader, + Virtualizer and the payload software correctly on the + target platform as a single ELF file (img.axf). + + The important files here are: + + 1. vectors.S + + 1. Implements the Secure world exception vectors + which are loaded to the base of physical memory + (0x80000000) at reset. + + 2. boot.S + + 1. Handles a power-on reset. + + 2. Initialises the I-Cache, sets up the stack & + passes control to the C handler for performing + the rest of the initialization. + + 3. c_start.c + + 1. Picks up from where the start() routine left in + the previous file. + + 2. Programs the exception vector tables for the + Secure world. + + 3. Provides Non-secure access to certain + coprocessor registers and memory mapped + peripherals e.g. access to the cache + coherent interconnect registers, coprocessors + etc. + + 4. Enables functionality which can be initialised + only in the Secure world. e.g. Configuration of + interrupts as Non-secure. + + 5. Synchronises execution with the secondary cpus + (if present) so that any global peripheral is + accesses by them only after the primary has + initialised it. + + 6. Enters the non-secure HYP mode and initialises + the Virtualizer. + + 7. Enters the non-secure SVC mode and jumps to the + payload software entry point. + + 4. payload/ + + 1. Contains two files 'fsimg' and 'kernel'. + + 2. The 'kernel' is a raw Linux kernel binary image. + The instructions to build this Linux image can + be found in docs/03-Linux-kernel-build.txt. + This image can be replaced with a raw binary + image of any other software payload which is + desired to be run on this system. + + 3. The 'fsimg' is an empty filesystem stub. If + desired, it can be replaced with a suitable + filesystem image in a Linux initramfs format. A + custom busybox filesystem was used for testing. + More complex filesystems may be used if needed + but will require the use of MMC emulation with + the ARM FastModels. + See docs/06-Optional-rootfs-build.txt for + details. + + 5. boot.map.template + + 1. Scatter file which combines the payload + software, Virtualizer and the bootloader into a + single ELF file (img.axf) which can + then be loaded on the relevant platform. + + 6. makemap + + 1. Simple perl script that takes an ELF image of + the Virtualizer, parses through the relevant + sections & adds those sections to the scatter + file so that a consolidated image can be + created. + + 2. big-little/common + + This directory mainly deals with setting up of the HYP + processor mode and the Virtual GIC. This allows the + payload software to run unmodified while either the + Switching or the MP mode is active in the background. + + The important files here are: + + 1. hyp_vectors.s + + 1. Implements the HYP mode vector table. + + 2. It contains the entry point "bl_setup()" which + is invoked by the bootwrapper to initialise the + Virtualizer software. + + 3. The exception vector for interrupts + [irq_entry()] is the entry point for all + physical interrupts. The exception vector for + hypervisor traps [hvc_entry()] is the entry + point for all accesses made by the payload + software that need to be handled in the HYP + mode. + + 4. Also contained is rudimentary support for fault + exception handlers [dabt_entry(), iabt_entry() & + undef_entry()]. + + 2. hyp_setup.c + + 1. Extends the initialization of the Virtualizer + software into C code after a cold reset. + + 2. If switching is being done asynchronously then + the HYP timer interrupt is setup to periodically + (~12 million instructions) trigger a switchover + to the other cluster. + + 3. If in MP mode, then CCI snoops are enabled for + both the clusters. + + 3. vgic_handle.c + + 1. Extends handling of physical interrupts into C + code from irq_entry(). Interrupts are + acknowledged (optionally EOI'ed) and queued as + virtual interrupts. The HYP timer interrupt is + handled differently. When recieved, its used as + a trigger to initiate the switchover process. + + 4. vgiclib.c + + 1. Implements handling of virtual interrupts once + they have been queued up in the vGIC HYP view + list registers. It maintains the list registers + and also saves and restores the context of the + vGIC HYP view interface. + + 5. pagetable_setup.c + + 1. Creates and sets up the HYP mode and 2nd stage + translation page tables. Accesses by the payload + software to the vGIC physical cpu interface are + mapped to the vGIC virtual cpu interface using + the 2nd stage translation page tables. + + 2. In the MP configuration, the translation tables + are shared by all the cpus in the two clusters. + Hence the first cpu in only one of the clusters + creates them. + + 6. vgic_setup.c + + 1. Enables virtual interrupts and exceptions, + initialises the physical cpu interface and the + HYP view interface. + + 3. big-little/lib + + This directory implements common functionality thats + used across all the Virtualizer code. This includes: + + 1. Locks which can be used with Strongly Ordered and + Device memory. + + 2. Code tracing support on the Fast Models platform + through the use of memory mapped TUBE registers & + the Generic Trace plugin. + Details of this feature can be found in + docs/04-Cache-hit-rate-howto.txt. + + 3. Events to synchronise the switching process between + the clusters and within the clusters. They also used + to synchronise the setup phase after a cold reset in + the MP configuration. + + 4. UART routines to enable support semihosting of + printf family of functions. + + 5. Cache maintenance, Stack manipulation and Locking + routines. + + 4. big-little/include + + 1. This directory contains the headers specific to HYP + mode setup, Switching process and common helper + routines. Most importantly, context.h contains the + data structures which are used to save and restore + the processor context. + + 5. big-little/switcher + + This directory implements code to save and restore + processor context and to initiate/handle a + async/synchronous switchover request. + + 1. context/ + + 1. ns_context.c + + 1. Contains top level routines to save and + restore the Non-secure world context. + + 2. It requests the secure world to save its own + context and bring the inbound cluster out of + reset. It also uses events to synchronise + the switching process between the inbound + and outbound clusters. + + 2. gic.c + + 1. Contains routines to save and restore the + context of the vGIC physical distributor and + cpu interfaces. + + 3. sh_vgic.c + + 1. The two clusters share the interrupt + controller instead of each cluster having + its own. A consequence of this is that there + is no longer a 1 to 1 mapping between cpu + ids and cpu interface ids e.g. on an + MPx1+MPx1 cluster configuration, + cpu0 of the Cortex-A7 cluster would + correspond to cpuinterface1 on the shared + vGIC. This in turn affects routing of + peripheral and software generated + interrupts. This file implements code to + allow use of the shared vGIC correctly + keeping this limitation in mind. + + 2. trigger/ + + 1. async_switchover.c + + 1. Contains code to use the HYP timer interrupt + as a trigger to initiate a switchover + asynchronously. + + 2. sync_switchover.c + + 1. Contains code to handle an HVC instructions + executed by the payload software: + + a. to initiate a synchronous switchover. + ("HVC #1") + + b. to find the id of the cluster on which its + currently executing. ("HVC #2") + + 3. handle_switchover.s + + 1. Contains code to start saving the non-secure + world context and request the secure world to + power down the outbound cluster once the + inbound cluster is up and running. + + 6. big-little/virtualisor + + This directory implements code that using the ARM + Virtualization extensions: + + 1. Hides any microarchitectural differences between the + Cortex-A15 & Cortex-A7 processors visible to the + payload software. + + 2. Provides a different view of the underlying hardware + than what really exists e.g. in the switching mode + it traps accesses made by the host cluster + (Cortex-A7 cluster currently) to the shared vGIC + physical distributor interface, so that routing of + interrupts can take place correctly. In the MP mode, + the L2 control and MPIDR registers are virtualized + to tell the payload software that there is one + cluster with multiple processors instead of two. + + The ARM Virtualization extensions provide a set of trap + registers (HCPTR (Hyp Coprocessor Trap Register), HSTR + (Hyp System Trap Register), HDCR (Hyp Debug + Configuration Register)) to be able to select what + accesses made by the payload software to the coprocessor + block will be trapped in the HYP mode. + + Accesses to memory mapped peripherals e.g. shared vGIC + can betrapped into the HYP mode by populating + appropriate entries in the 2nd stage translation tables. + This is how microarchitectural differences between the + two processor sets are resolved. + + Whenever a trap into HYP mode is taken, the HSR (Hyp + Syndrome Register) contains enough information about the + type of trap taken for the software to take appropriate + action. + + The Virtualizer design centres around the traps + recognized by the HSR. Also, to deal with + microarchitectural differences the concept of a HOST + cluster is introduced. It is possible for each + cpu to find out the system topology using the Kingfisher + System Control Block. Once it knows the host cluster id + & whether the software is expected to switch execution + or run in the MP mode (provided at compile time), the + CPU Can configure itself accordingly. + + The processor cluster for which the payload software has + been built to run on [assumed to be Cortex-A15 for this + release] is termed as the TARGET while the cluster on + which the differences are expected to crop up is called + the HOST (assumed to be Cortex-A7 for this release). + The HOST environment variable is used to specify + the host cluster. The target cluster is assumed to be + the logical complement of the host i.e. cluster ids can + only take the values of 0 and 1. + + The HOST processor emulates the TARGET processor by + trapping the accesses to differing processor features + into the HYP mode. Most of the microarchitectural + differences & registers that need to be virtualized are + handled in a generic (CPU Independent) layer of + code. Additionally, each processor exports functions to + setup, handle & optionally save/restore context of each + trap that the HSR recognises. These handlers are invoked + whenever the software runs + on that processor. + + 1. virt_setup.c + + 1. Generic function that initialises the required + traps. This is done once each on both the host + and target clusters if the trap handler needs + to obtain some information about the target + cluster to be able to work correctly e.g the + Cortex-A7 processor cluster needs to find out + the cache geometry of the Cortex-A15 + processor cluster to be able to handle cache + maintenance operations by set/way correctly.This + function further calls any setup function that + has been exported by the processor the code is + executing on. + + 2. virt_handle.c + + 1. Generic function that extends the hvc_entry() + routine to C Code. It calls the generic trap + handler (if registered) and then any trap + handlers exported by the processor on + which the trap has been invoked. + + 3. virt_context.c + + 1. Generic function that saves and restores traps + on the host cluster & then calls any + save/restore function that has been exported by + the processor the code is executing on. + + 4. cache_geom.c + + 1. Generic function that detects cache geometries + on the host and target clusters & then maps + cache maintenance operations by set/way from the + target to the host cache. + + 5. mem_trap.c + + 1. Generic function that sets up any memory traps + by editing the 2nd stage translation tables. + + 6. vgic_trap_handler.c + + 1. Generic function that handles trapped accesses + to the shared vGIC. + + 7. include/ + + Header files specific to the Virtualisor code. + + 8. cpus/ + + Placeholders for any traps that the Cortex-A7 or A15 processor + cluster might want to setup. No traps need to be setup + at the moment. + + 9. big-little/secure_world + + Since both Cortex-A7 & Cortex-A15 processors support ARM + TrustZone Security Extensions, there is certain context + that needs to be setup, saved & restored in the Secure + world. + + This context allows access to certain coprocessor and + peripheral registers to the Non-secure world. It also + configures the shared vGIC for use by the Non-secure + world. + + Execution shifts to the Secure world through the SMC + instruction which is a part of the ARM V7-ISA. + + 1. monmode_vectors.s + + 1. Implements the monitor mode vector table. It + contains the secure entry point [do_smc()] for + the SMC instruction alongwith rudimentary + support for other fault exceptions taken while + executing in the secure world. + + 2. Three types of SMC exceptions are expected (type + of exception is contained in r0): + + 1. SMC_SEC_INIT + + Called once after a power on reset to + initialise the Secure world stacks, + coherency, pagetables, to configure some + coprocessor and memory mapped peripheral + (Coherent interconnect & shared vGIC) + registers for use of these features by + the Non-secure world. + + 2. SMC_SEC_SAVE + + Called from ns_context.c to request the + secure world to save its context and bring + the corresponding core in the inbound + cluster out of reset so that it can start + restoring the saved state. + + 3. SMC_SEC_SHUTDOWN + + Called from handle_switchover.s to request + the secure world to flush the L1 and L2 caches + and power down the outbound cluster. + + Also implemented is a function to handle warm + resets on the inbound cluster. Bareminimal + context is initialised while the rest is restored + before control is passed to the Non-secure world + handler for restoring context [restore_context()] + in ns_context.c + + 2. secure_context.c + + Implements code to save and restore the secure world + context + + 3. secure_resets.c + + Implements code to power down the outbound cluster + and bring individual cores in the inbound cluster + out of reset. + + 4. ve_reset_handler.s + + Base of physical memory in the Versatile Express + memory map is at 0x80000000. The processors are + brought out of reset at 0x0 which points to Secure + RAM/Flash memory. This file implements a small stub + function that is placed at 0x0 so that execution + jumps to 0x80000000 after a cold reset and to the + warm_reset() handler in monmode_vectors.s + after a warm reset. + + The secure world code is built into a seperate ELF image + to maintain its distinction from the Virtualizer code + that executes in the Non-secure world. + + 10. big-little/bl.scf.template + + 1. Scatter file that is used to build the Non-secure + world code in the Virtualizer software. The + resultant image is bl.axf. + + 11. big-little/bl-sec.scf.template + + 1. Scatter file that is used to build the Secure world + code in the Virtualizer software. The resultant + image is bl_sec.axf. + + 12. acsr/ + + The secure world code is built into a seperate ELF image + to maintain its distinction from the Virtualizer code + that executes in the Non-secure world. + + 1. helpers.s + + Helper functions to access the CP15 coprocessor + space. + + 2. v7.s + + Contains routines to save and restore ARM processor + context. diff --git a/linaro/arm-virt-bl/docs/03-Linux-kernel-build.txt b/linaro/arm-virt-bl/docs/03-Linux-kernel-build.txt new file mode 100644 index 0000000..876cce3 --- /dev/null +++ b/linaro/arm-virt-bl/docs/03-Linux-kernel-build.txt @@ -0,0 +1,58 @@ +Building and installing a Linux kernel +====================================== + +A suitable Linux kernel image for use with the virtualizer +can be built as follows (GCC toolchain used for these steps is: +CodeSourcery Sourcery G++ Lite 2010.09 v4.5.1) + +$ tar -jxf arm-virtualizer-v2_2-160212.tar.bz2 +$ cd arm-virtualizer-v2_2-160212/bootwrapper +$ make clean +$ pushd /tmp +$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git arm-platforms.git +$ cd arm-platforms.git +$ git checkout -b ael-11.06 origin/ael-11.06 +$ yes | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress-new_defconfig +$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 +$ popd +$ cp $OLDPWD/arch/arm/boot/Image payload/kernel + +The virtualizer can now be built as usual by invoking: + +$ make clean && make + +.. in the top bootwrapper directory. + +This will result in a file called img.axf located at +arm-virtualizer-v2_2-160212/bootwrapper/img.axf. + +To launch the ARM FastModel with the virtualizer, first modify +arm-virtualizer-v2_2-160212/bootwrapper/big-little-MP<x>.mxscript +as usual to fill in paths to the model binary and the img.axf files. +The mxscript file is adequately commented to assist with this. + +In case of an MP1 model, we would use the big-little-MP1.mxscript file +and we would specify the path to the model in a manner similar to: + +string model = "/home/working_dir/RTSM_VE_Cortex-A15x1-A7x1"; + +Similarly, in case of an MP4 model, we would use the big-little-MP4.mxscript +and we would specify the path to the model in a manner similar to: + +string model = "/home/working_dir/models/RTSM_VE_Cortex-A15x4-A7x4"; + +The path to the img.axf file is specified using the app directive as +follows: + +string app = "arm-virtualizer-v2_2-160212/bootwrapper/img.axf"; + +The model can then be launched using: + +modeldebugger -s arm-virtualizer-v2_2-160212/bootwrapper/big-little-MP<x>.mxscript + +Where 'x' is the 1 or 4 respectively in the case of an MP1 model run or an +MP4 model run. + +This will result in the Linux kernel console messages appearing the ARM +FastModel UART emulation window. The virtualizer will switch execution +between the two clusters at ~12 million instruction intervals. diff --git a/linaro/arm-virt-bl/docs/04-Cache-hit-rate-howto.txt b/linaro/arm-virt-bl/docs/04-Cache-hit-rate-howto.txt new file mode 100644 index 0000000..27c83b4 --- /dev/null +++ b/linaro/arm-virt-bl/docs/04-Cache-hit-rate-howto.txt @@ -0,0 +1,198 @@ +Cache hit-rate HOWTO +==================== + +A Introduction + + The ARM Fast Models are accompanied with a trace infrastructure + referred to as the Model Trace Interface (MTI). The MTI trace + provides a mechanism to dynamically register to events from the + model. The GenericTrace.so MTI trace plugin provides a number of + trace events whose output can be logged in a simple text file. + The usage of this plugin is given in Section B. + + In this document we will consider how the GenericTrace.so plugin + can be used during a cluster switchover to calculate the number + of cache hits in the outbound cluster L2 cache originating from + the inbound cluster before the outbound L2 is flushed and the + cluster placed in reset. + +B Plugin Usage + + The GenericTrace plugin is loaded using the "--trace-plugin" + parameter in the command line to launch the model. + + A list of trace sources provided by the plugin can be listed as + follows: + + "RTSM_VE_Cortex-A15x1-A7x1 --trace-plugin GenericTrace.so + --parameter TRACE.GenericTrace.trace-sources= " + + A list of parameters supported by the Generic Trace plugin can + be listed as follows: + + "RTSM_VE_Cortex-A15x1-A7x1 --trace-plugin GenericTrace.so -l" + + Some of the interesting parameters are: + + TRACE.GenericTrace.trace-file: The trace file to write into. If + empty will print to console / STDOUT. + + TRACE.GenericTrace.perf-period: Print performance every N + instructions. Since the instruction count and the global counter + have the same value on the Fast Models, this parameter provides + a good approximation of time. + + TRACE.GenericTrace.flush: If set to true then the trace file will be + flushed after every event. + +C Plugin Trace sources + + The GenericTrace plugin provides events which allow each cluster + to trace snoop requests originating from a different cluster that + hit in its caches. For snoops originating from the Cortex-A7 cluster + that hit in the A15 cluster, the event is 'read_for_4_came_from_snoop' + & for the opposite case the event is 'read_for_3_came_from_snoop'. + The numbers '3' & '4' in the name of the trace sources are the ids + of the CCI slave interfaces from where the snoop originated. + + These trace sources are the per-cluster implementation of the + event id '0xA' "(Read data last handshake - data returned + from the cache rather than from downstream)" of the CCI PMU. + Please refer to the "Cache Coherent Interconnect (CCI-400) + Architecture Specification" for further details. + + The plugin also provides the ability to trace code execution through + a memory mapped "tube" interface. This interface defines a list of + registers which when written to in a particular sequence and the + 'sw_trace_event' trace source selected during model invocation will + print out the register values in the trace file. + + The "tube" interface defines: + + - Three LE 64 bit registers of arbitrary data that can be + written (and retain their values). + + - A tube-like char register which when written with '\0' + will generate an event with the current state of the + 64-bit registers and with the characters sent to the + device with a unique sequence_id. + + All of these registers are banked and write-only, the trace + event will also output the cluster id and the CPU id. ARM + FastModels implement 1 to 4 TUBE interfaces. Please refer to + Section E for supported interfaces in the current model + release. The memory map of these registers can be found in + big-little/include/misc.h. + + The 'write_trace' function in big-litte/lib/tube.c implements the + software sequence to program the tube interface. This function is + called at various points in switchover process. It prints out a + message which indicates that an event is about to start or has + completed alongwith the value of the global counter in one of the + 64 bit registers. To enable this functionality, the environment + variable "TUBE" needs to be defined to TRUE prior to code compilation. + +D Putting it all together + + The list of steps to use the above mentioned functionality is: + + 1. Build the Virtualizer code with "TUBE" support. On the + tcsh shell, this is as follows; + + $ setenv TUBE TRUE; make clean && make + + 2. Launch the model with the MTI trace plugin support and a + selection of the right trace sources using a suitable + MXScript file in the 'bootwrapper' directory. + + Once the switchover process starts, the trace file will contain output + that looks like this (not including the comments): + + . + . + . + . + // Lines beginning with "PERFORMANCE" are a result of the value of the + // "TRACE.GenericTrace.perf-period" parameter. This string is printed + // every <value> number of instructions (200 in this case) in the trace + // file. It indicates at what rate is the model executing instructions + // & the number of instructions executed thus far. + PERFORMANCE: 2.8 MIPS (Inst:67216767) + . + . + . + // Lines beginning with "sw_trace_event<x>" are a result of enabling + // "TUBE" support in the code and selecting the "sw_trace_event" source + // while invoking the model. The interpretation of this message is: + // + // <x> : indicates the "TUBE" interface number. + // sequence_id : a unique number assigned to each message + // cluster_and_cpu_id : in the format 0x<cluster id><cpu id>. Each id + // occupies 8 bits. + // data0 : first 64-bit register value. Programmed with + // the value of the global counter. + // data1 : second 64-bit register value. Not used. + // data2 : third 64-bit register value. Not used. + // message : String written to the TUBE register + sw_trace_event2: sequence_id=0x00000001 cluster_and_cpu_id=0x0000 data0=0x000000000401a3dc data1=0x0000000000000000 data2=0x0000000000000000 message="Secure Coherency Enable Start":30 + . + . + . + PERFORMANCE: 0.2 MIPS (Inst:67217079) + sw_trace_event2: sequence_id=0x00000002 cluster_and_cpu_id=0x0000 data0=0x000000000401a581 data1=0x0000000000000000 data2=0x0000000000000000 message="Secure Coherency Enable End":28 + PERFORMANCE: 0.9 MIPS (Inst:67217301) + PERFORMANCE: 5.8 MIPS (Inst:67217511) + . + . + . + // Lines beginning with "read_for_<x>_came_from_snoop" are a result of + // enabling the event sources for monitoring the cache hits resulting + // from snoops originating from master interface <x> on the CCI. + // The following line indicates that a snoop from the Cortex-A7 cluster + // hit in the caches of the A15 cluster. It also prints the cache line + // address and whether the access was Secure or Non-secure. + read_for_4_came_from_snoop: Bus address=0x000000008ff02440 Is non secure=N + read_for_4_came_from_snoop: Bus address=0x000000008ff02440 Is non secure=N + read_for_4_came_from_snoop: Bus address=0x000000008ff02240 Is non secure=N + read_for_4_came_from_snoop: Bus address=0x000000008ff02240 Is non secure=N + read_for_4_came_from_snoop: Bus address=0x000000008ff012c0 Is non secure=N + PERFORMANCE: 0.0 MIPS (Inst:135292834) + sw_trace_event: sequence_id=0x00000010 cluster_and_cpu_id=0x0000 data0=0x000000000810672e data1=0x0000000000000000 data2=0x0000000000000000 message="L2 Flush Begin":15 + PERFORMANCE: 5.5 MIPS (Inst:135293056) + PERFORMANCE: 7.2 MIPS (Inst:135293374) + PERFORMANCE: 7.4 MIPS (Inst:135293587) + PERFORMANCE: 12.4 MIPS (Inst:135293800) + PERFORMANCE: 10.0 MIPS (Inst:135294118) + read_for_4_came_from_snoop: Bus address=0x0000000080054a80 Is non secure=Y + read_for_4_came_from_snoop: Bus address=0x0000000080054a80 Is non secure=Y + read_for_4_came_from_snoop: Bus address=0x0000000080054ac0 Is non secure=Y + read_for_4_came_from_snoop: Bus address=0x0000000080054ac0 Is non secure=Y + read_for_4_came_from_snoop: Bus address=0x0000000080074c80 Is non secure=Y + PERFORMANCE: 0.5 MIPS (Inst:135294331) + . + . + . + . + PERFORMANCE: 10.5 MIPS (Inst:135541612) + PERFORMANCE: 3.3 MIPS (Inst:135541929) + sw_trace_event: sequence_id=0x00000011 cluster_and_cpu_id=0x0000 data0=0x0000000008143442 data1=0x0000000000000000 data2=0x0000000000000000 message="L2 Flush End":13 + . + . + . + . + + Post-processing scripts can be developed which count the number of + 'read_for_<x>_came_from_snoop' events between two 'sw_trace_event<x>' + events. In the above example, the result will be the number of snoop + hits in the A15 caches while they were being flushed. In addition, + the "PERFORMANCE" strings can be used to determine the cache hit rate. + In this case, they indicate the number of hits in the last 200 + instructions. Repeated iterations can be done where each iteration + changes the point of time when the L2 cache is flushed during a + switchover. By monitoring its effect on the cache hit rate, a suitable + time can be determined to power down the outbound L2 cache. + +E Status of "TUBE" support + + The Real-Time System Model v7.0.1 (RTSM_VE_Cortex_A15x1_A7x1 and + RTSM_VE_Cortex_A15x4_A7x4) implements 'tube' interfaces TUB0-3. diff --git a/linaro/arm-virt-bl/docs/05-FAQ.txt b/linaro/arm-virt-bl/docs/05-FAQ.txt new file mode 100644 index 0000000..f054a6d --- /dev/null +++ b/linaro/arm-virt-bl/docs/05-FAQ.txt @@ -0,0 +1,20 @@ +Frequently asked questions +========================== + +Q1. What is the per-core context size that is switched between + clusters? + +A1: + + Per-CPU context: + + CP15 and VFP context: 768 bytes + vGIC Virtual CPU interface (payload view) context: 128 bytes + vGIC Virtual CPU interface (HYP mode view) context: 280 bytes + vGIC Distributor context (SGIs & PPIs): 128 bytes + Virt. Ext. Registers: 40 bytes + + Global context: + + vGIC Distributor context (SPIs): 2048 bytes + 2nd stage translation trap context: 40 bytes diff --git a/linaro/arm-virt-bl/docs/06-Optional-rootfs-build.txt b/linaro/arm-virt-bl/docs/06-Optional-rootfs-build.txt new file mode 100644 index 0000000..6dd9d62 --- /dev/null +++ b/linaro/arm-virt-bl/docs/06-Optional-rootfs-build.txt @@ -0,0 +1,122 @@ +Optional Root filesystem build and use instructions +=================================================== + +A Introduction + + This note describes ways to build Linux user-land + filesystems of varying complexity for use with the + virtualizer. Note that there are several ways to create + filesystems and this note doesn't cover all possibilities. + + The default virtualizer release contains an empty filesystem + stub located at: + + arm-virtualizer-v2_2-160212/bootwrapper/payload/fsimg + + A build using this stub doesn't contain a functional + filesytem that the Linux kernel image can use. fsimg can be + replaced with a suitable filesystem image but with the + following constraints: + + 1. Compressed or uncompressed cpio archives are supported. + + 2. The image size is limited to ~200 MB. + + The size restriction implies that only very 'lean' + filesystems such as busybox <http://www.busybox.net/> may be + used. While busybox presents a minimal but robust command + line environment, quite often a more conventional desktop + like environment with window management on top of an X + server is required in order to run web browsers etc. + + In this note, we illustrate a method to use a larger (~2GB) filesystem image + that can be used with the ARM FastModels MMC emulation. Note that the MMC + emulations only supports images that are just under 2GB in size. + + Note that if the MMC route is used, the bootwrapper/payload/fsimg filesystem + image will be suppressed and ignored. + + Locating a root filesystem on the MMC emulation allows the Linux kernel to + access and use this filesystem. This is facilitated by indicating the + filesystem location to the kernel via the kernel command-line arguments by + appending 'root=/dev/mmcblk0' (for a single partition MMC image) to the + argument list. + + Note that when using this technique, the fsimg file is ignored. + +B Building and installing a Linux kernel + + A suitable Linux kernel image for use with the virtualizer + can be built as follows: + + $ tar -jxf arm-virtualizer-v2_2-160212.tar.bz2 + $ cd arm-virtualizer-v2_2-160212/bootwrapper + $ make clean + $ pushd /tmp + $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/maz/ael-kernel.git ael-kernel.git + $ cd ael-kernel.git + $ git checkout -b ael-11.06 origin/ael-11.06 + $ yes | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress-new_defconfig + $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 + $ popd + $ cp $OLDPWD/arch/arm/boot/Image payload/kernel + + Note that the using the vexpress-new_defconfig configuration + ensures that the kernel is built with MMC support. + +C Building a suitable root filesystem + + A suitable root filesystem can be built using Ubuntu Linux's rootstock utility + <https://wiki.ubuntu.com/ARM/RootfsFromScratch> as follows: + + $ sudo apt-get install rootstock + $ sudo rootstock --fqdn ubuntu --login ubuntu --password ubuntu --imagesize 2040M --seed lxde,gdm --notarball + $ mv qemu-armel-*.img mmc.img + + Note that the complete filesystem build will take ~30 + minutes. On boot, the username and password is 'ubuntu'. + + The rootstock invocation above will produce a rootfilesystem containing an + LXDE desktop <http://lxde.org/> that has a firefox browser. + +D Modifying the kernel command line to support the MMC image. + + The virtualizer build system and the mxscripts that are used for launching + the ARM FastModel require modifications to support the MMC image. + + The build system modification is to change the Linux kernel command line + arguments to make the kernel aware of the location of the root filesystem. + The command line should contain the string 'root=/dev/mmcblk0'. + + To make this modification, edit the file bootwrapper/Makefile and change the + BOOTARGS specification on line 42 from: + + BOOTARGS=mem=255M console=ttyAMA0,115200 migration_cost=500 + cachepolicy=writealloc + + to + + BOOTARGS=root=/dev/mmcblk0 mem=255M console=ttyAMA0,115200 + migration_cost=500 cachepolicy=writealloc + + The ARM FastModel mxscript modification is to get the FastModel to use the + mmc.img file created in step C above with the MMC emulation. + + To make this modification uncomment the 'string mmcimage=' line (line 42) + and provide the complete path to the mmc.img file generated in step C above. + +E Building the virtualizer + + $ cd bootwrapper + $ make clean && make + +F Launching the ARM FastModel + + $ modeldebugger -s big-little-MP<x>.mxscript + + .. where x is 1 or 4 as the case may be (MP1 build or MP4 + build). + +G Known limitations + + None. diff --git a/linaro/arm-virt-bl/scripts/Makefile b/linaro/arm-virt-bl/scripts/Makefile new file mode 100644 index 0000000..0887cc4 --- /dev/null +++ b/linaro/arm-virt-bl/scripts/Makefile @@ -0,0 +1,9 @@ +CFLAGS = -g -O -Wall + +TARGETS = loadmap + +all: $(TARGETS) + +.PHONY: clean +clean: + rm -f $(TARGETS) diff --git a/linaro/arm-virt-bl/scripts/armasm2gas.pl b/linaro/arm-virt-bl/scripts/armasm2gas.pl new file mode 100755 index 0000000..783716a --- /dev/null +++ b/linaro/arm-virt-bl/scripts/armasm2gas.pl @@ -0,0 +1,156 @@ +#!/usr/bin/env perl + +# This script converts RVCT assembler files on stdin and the command line, +# writing the GAS equivalent to stdout. +# +# This is a quick-and-dirty hack, only converting those things that are +# needed to get the switcher to build. Support for RVCT features is +# not fully correct or complete. + +my $in_macro_header = 0; +my $in_macro = 0; + +while (<>) { + unless (/^(\w+)?(\s+(\w+)(\s+([^";]*("[^"]*")?)*)?)?(\s*;(.*))?\s*\n/) { + print; + next; + } + + my ($label, $mnemonic, $args, $comment) = ($1, $3, $4, $7); + my $labeldecl; + + $labeldecl = "$label:" if defined $label; + + $mnemonic = lc $mnemonic; + # To lower-case everything in $args would be painful, since we would + # need to distinguish labels, strings etc. from register names etc. + # For now, don't bother. + + $comment =~ s/;/@/; + + # Convert local label references, unless args looks like it contains + # string literals, in which case those references might be part of a + # string instead. + $args =~ s/%([bf])t?(\d+)/$2\l$1/g unless $args =~ /"/; + + # Likewise, convert idiosyncratic operators: + $args =~ s/:OR:/|/gi unless $args =~ /"/; + + # Convert macro argument declarations: + if ($in_macro_header) { + die "Can't handle macro label arguments" if defined $label; + + $args =~ s/\$//g; + $in_macro_header = 0; + $in_macro = 1; + + print "\t.macro\t$mnemonic $args\n"; + next; + } + + $args =~ s/\$/\\/g if $in_macro; + + $mnemonic = '.globl' if $mnemonic eq 'export'; + $mnemonic = '.long' if $mnemonic eq 'dcd'; + $mnemonic = '.space' if $mnemonic eq 'space'; + if ($mnemonic eq 'incbin') { + $args =~ s/\s*(\S+)\s*/"$1"/; + + print "$labeldecl\t.incbin\t$args$comment\n"; + next; + } + if ($mnemonic eq 'macro') { + $in_macro_header = 1; + print "$labeldecl$comment\n"; + next; + } + do { print "$labeldecl$comment\n"; next } if $mnemonic eq 'import'; + do { print "$labeldecl$comment\n"; next } if $mnemonic eq 'entry'; + do { print "$labeldecl$comment\n"; next } if $mnemonic eq 'preserve8'; + do { print "$labeldecl\t.ltorg$comment\n"; next } if $mnemonic eq 'ltorg'; + if ($mnemonic eq 'mend') { + $in_macro = 0; + $in_macro_header = 0; + print "$labeldecl\t.endm$comment\n"; + next; + } + if ($mnemonic eq 'equ') { + print "\t.equ\t$label,$args$comment\n"; + next; + } + if ($mnemonic eq 'function') { + print "$labeldecl; .type $label, %function$comment\n"; + next; + } + do { print "$labeldecl$comment\n"; next } if $mnemonic eq 'endfunc'; + if ($mnemonic eq 'align') { + my $log2 = 0; + my $arg = $args; + + die "Garbage ALIGN args $args" unless $arg =~ s/\s*(\d+)?(\s*)/$1/; + # handle implicit align + $arg = 4 if $1 eq ''; + + $log2 = int (log ($arg) / log (2) + .5); + die "Invalid ALIGNment $arg" unless 1 << $log2 == $arg; + + print "$labeldecl\t.align\t$log2$2$comment\n"; + next; + } + if ($mnemonic eq 'area') { + $args =~ s/^([^,]+)//; # Try to extract section name + my $name = $1; + $name =~ s/^\s*//; + $name =~ s/\s*$//; # Delete leading/trailing whitespace + $name =~ s/\|//g; # Delete (probably unnecessary) quoting + $name ne '' or die "Missing section name in AREA directive"; + + # Guess appropriate GAS-style section flags + my $flags = 'a'; + $flags .= 'x' if $args =~ s/,\s*CODE\s*//; + $flags .= 'w' if $args =~ s/,\s*DATA\s*//; + $flags =~ s/w// if $args =~ s/,\s*READONLY\s*//; + $flags .= 'w' if $args =~ s/,\s*READWRITE\s*//; + + # Handle alignment specification, if present. + # GAS doesn't support this in .section, so we need to emit + # an extra directive in this case. + my $align = ''; + $align = "; .align $1" if $args =~ s/,\s*ALIGN\s*=\s*(\d+)\s*//; + + my $nobits = ''; + $nobits = ', %nobits' if $args =~ s/,\s*NOINIT\s*//; + + print "$labeldecl\t.section\t$name, \"$flags\"$nobits$align$comment\n"; + next; + } + if ($mnemonic eq 'dcb') { + # RVCT DCB can handle a list of strings and byte values, + # but GAS has separate directives. + # Here, we pick off the arguments one by one and emit + # appropriate GAS directives. + + print "$labeldecl\t"; + + $args = ",$args"; + + { + if ($args =~ s/^,\s*("[^"]*")\s*//) { + print ".ascii $1;"; + redo; + } + if ($args =~ s/^,\s*(\S+)\s*//) { + print ".byte $1;"; + redo; + } + } + print "\n"; + + die "Garbage DCB arguments: $args" if $args =~ /\S/; + + next; + } + do { undef $mnemonic; undef $args } if $mnemonic eq 'end'; + + print $labeldecl, "\t", $mnemonic, $args, $comment, "\n"; +} diff --git a/linaro/arm-virt-bl/scripts/loadmap.c b/linaro/arm-virt-bl/scripts/loadmap.c new file mode 100644 index 0000000..6b73f99 --- /dev/null +++ b/linaro/arm-virt-bl/scripts/loadmap.c @@ -0,0 +1,861 @@ +#define _GNU_SOURCE + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <stdarg.h> +#include <string.h> +#include <elf.h> +#include <limits.h> +#include <endian.h> + +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/stat.h> + +#define FRAG_INITIAL_SIZE 0x1000 + +#define TOOLS_GNU 'G' +#define TOOLS_RVCT 'R' +#define KIND_ASM 's' +#define KIND_LINKER_SCRIPT 'k' + +#define lengthof(a) (sizeof (a) / sizeof *(a)) + +struct personality_struct { + int tools; + int kind; + void (*init)(void); + void (*do_phdr)(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index); + void (*finish)(void); +}; + +static void init_gnu_asm(void); +static void init_rvct_asm(void); +static void init_gnu_lds(void); +static void init_rvct_scf(void); +static void do_phdr_gnu_asm(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index); +static void do_phdr_rvct_asm(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index); +static void do_phdr_gnu_lds(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index); +static void do_phdr_rvct_scf(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index); +static void finish_gnu_asm(void); +static void finish_rvct_asm(void); +static void finish_gnu_lds(void); +static void finish_rvct_scf(void); + +static const struct personality_struct personalities[] = { + { TOOLS_GNU, KIND_ASM, + init_gnu_asm, do_phdr_gnu_asm, finish_gnu_asm }, + { TOOLS_GNU, KIND_LINKER_SCRIPT, + init_gnu_lds, do_phdr_gnu_lds, finish_gnu_lds }, + { TOOLS_RVCT, KIND_ASM, + init_rvct_asm, do_phdr_rvct_asm, finish_rvct_asm }, + { TOOLS_RVCT, KIND_LINKER_SCRIPT, + init_rvct_scf, do_phdr_rvct_scf, finish_rvct_scf }, +}; + +static int opt_entry_point_set = 0; +static Elf32_Word opt_entry_point; +static int opt_load_address_set = 0; +static Elf32_Word opt_load_address; +static int opt_binary = 0; +static int opt_entry_thumb = 0; +static FILE *opt_input_file; +static char *opt_program_name; +static char bin_template[PATH_MAX]; /* section dump filename template */ +static char path_buf[PATH_MAX]; +static char opt_basename[PATH_MAX] = ""; +static int opt_toolchain = TOOLS_GNU; +static int opt_output_kind = KIND_ASM; +static struct personality_struct const *personality = NULL; + +struct frag +{ + char *buf; + size_t len; + size_t size; + size_t next_size; +}; + +static struct frag lfr; /* load region table or linker script built here */ +static struct frag zfr; /* zero-initialised region table built here */ +static struct frag binfr; /* binary data inclusions built here */ + +static int has_load = 0; +static int has_zi = 0; + +static void _die(unsigned lineno, char const *message) +{ + fprintf(stderr, "%s: Died at %s:%d: ", opt_program_name, __FILE__, lineno); + fputs(message, stderr); + exit(EXIT_FAILURE); +} + +#define die(message) _die(__LINE__, message) + +static void warn(char const *message) +{ + fprintf(stderr, "%s: Warning: %s", opt_program_name, message); +} + +/* + * Only use this function to grow a block. + * Spurious failures may occur if you try to shrink a block using this + * function. + */ +static void *xrealloc(void *block, size_t size) +{ + void *result; + + result = realloc(block, size); + if (!result) die("Out of memory\n"); + + return result; +} + +static void frag_init(struct frag *f) +{ + f->buf = NULL; + f->len = f->size = 0; + f->next_size = FRAG_INITIAL_SIZE; +} + +/* + * Grow the fragment by an arbitrary (hopefully sensible) amount. + * Use this if you know the frag needs to be bigger, but you don't + * know exactly how big you want it yet. + */ +static void frag_grow(struct frag *f) +{ + f->buf = xrealloc(f->buf, f->next_size); + f->size = f->next_size; + f->next_size *= 2; +} + +/* Use this to grow the fragment until it is at least size bytes in size */ +static void frag_ensure(struct frag *f, size_t size) +{ + while (f->size < size) + frag_grow(f); +} + +static void frag_shrink(struct frag *f, size_t size) +{ + void *result; + + if (f->size <= size) + return; + + result = realloc(f->buf, size); + if (result) + f->buf = result; + +} + +/* + * Ensure that size bytes can be appended at p. + * p should be NULL if the frag has no memory allocated to it yet, + * or if you want to append and the and of the last append made + * be frag_stpcpy or frag_pprintf. + * + * The pointer to append to is returned. It may be different + * from p, since realloc may move the frag's buffer. + */ +static char *frag_ensure_append(struct frag *f, char *p, size_t size) +{ + size_t offset; + + if (p) + offset = f->buf ? p - f->buf : 0; + else + offset = f->len; + + frag_ensure(f, offset + size); + + return f->buf + offset; +} + +/* + * Copy q to p in fragment f, growing f as needed. + * A pointer to the end of the resulting string is returned; + * This is most useful if p pointed to the end of the string in + * f to begin with: in that case, this function appends q to + * the string in f, returning the start pointer for subsequent + * appends. + */ +static char *frag_stpcpy(struct frag *f, char *p, char const *q) +{ + size_t len; + char *result; + + len = strlen(q); + + result = strcpy(frag_ensure_append(f, p, len + 1), q) + len; + f->len = result - f->buf; + + return result; +} + +/* + * Append a formatted string to the frag f, printf-style. + * The frag grows as needed. + * A pointer to the end of the resulting frag is returned + */ +static char *frag_pprintf(struct frag *f, char *p, char const *format, ...) +{ + va_list vl; + int n; + size_t offset; + + if (p) + offset = f->buf ? p - f->buf : 0; + else + offset = f->len; + + /* Ensure that at least the terminating NUL can be accomodated: */ + if (f->size < 1 + offset) + frag_grow(f); + + va_start(vl, format); + + while (1) { + n = vsnprintf(f->buf + offset, f->size - offset, format, vl); + if (n < 0) + return NULL; + + if ((unsigned)n < f->size - offset) + break; + + frag_grow(f); + } + + va_end(vl); + + f->len = offset + n; + + return f->buf + f->len; +} + +/* + * Read the whole file f into memory. + * Aborts on error; otherwise returns a non-NULL pointer to the file + * data. If result_size is non-NULL, the number of bytes of data + * read is stored to it. + */ +static void *fslurp(FILE *f, size_t *size) +{ + struct frag fr; + size_t total = 0; + + frag_init(&fr); + + do { + size_t nread; + + frag_grow(&fr); + + nread = fread(fr.buf + total, 1, fr.size - total, f); + total += nread; + } while (!(total < fr.size)); + + if (ferror(f)) + die("I/O error\n"); + + frag_shrink(&fr, total); + + if (size) + *size = total; + + return fr.buf; +} + +static int is_elf(Elf32_Ehdr *eh) +{ + if (memcmp(eh->e_ident, ELFMAG, SELFMAG)) + return 0; /* not an ELF file */ + + if (eh->e_ident[EI_CLASS] != ELFCLASS32) + die ("Only 32-bit ELF files are supported.\n"); + if (eh->e_ident[EI_DATA] != ELFDATA2LSB || + __BYTE_ORDER != __LITTLE_ENDIAN) + die ("Can't handle big-endian or foreign-endian ELF files.\n"); + + if (eh->e_type != ET_EXEC) + die ("Can't handle relocatable ELF images.\n"); + + if (!eh->e_phoff) + die ("ELF program header table missing.\n"); + + if (eh->e_phentsize != sizeof (Elf32_Phdr)) + die ("Unexpected ELF program header table entry size.\n"); + + /* ELF file looks OK */ + return 1; +} + +static char const *pf_to_section_basename(int phdr_flags) +{ + if (phdr_flags & PF_X) return ".text"; + if (phdr_flags & PF_W) return ".data"; + /* otherwise */ return ".rodata"; +} + +static void init_rvct_asm(void) +{ + frag_init(&lfr); + frag_stpcpy(&lfr, NULL, "\tAREA\t|.rodata.loadtab|, DATA, READONLY, ALIGN=2\n\n"); + + frag_init(&zfr); + frag_stpcpy(&zfr, NULL, "\tAREA\t|.rodata.zitab|, DATA, READONLY, ALIGN=2\n\n"); + + frag_init(&binfr); +} + +static void do_phdr_rvct_asm(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index) +{ + Elf32_Phdr *p = &phdrs[index]; + + if (p->p_type != PT_LOAD) + return; /* Ignore everything except loadable segments. */ + + if (p->p_filesz) { + int fd; + FILE *f = NULL; + + do { + snprintf(path_buf, sizeof path_buf, bin_template, rand()); + fd = open(path_buf, O_WRONLY | O_CREAT | O_EXCL, + S_IRWXU | S_IRWXG | S_IRWXO); + } while(fd == EEXIST); + + if (fd == -1 || !(f = fdopen(fd, "wb"))) + die("Could not create temporary file.\n"); + + fwrite ((char *)eh + p->p_offset, 1, p->p_filesz, f); + fclose(f); + + frag_pprintf(&binfr, NULL, + "\tAREA\t|%s.load.%s.%u|, %s, %s\n\n" + "__load_%s_%u_base\n" + "\tINCBIN\t%s\n" + "__load_%s_%u_size\tEQU\t. - __load_%s_%u_base\n\n", + pf_to_section_basename(p->p_flags), + opt_basename, index, + p->p_flags & PF_X ? "CODE" : "DATA", + p->p_flags & PF_W ? "READWRITE" : "READONLY", + opt_basename, index, + path_buf, + opt_basename, index, + opt_basename, index); + + frag_pprintf(&lfr, NULL, + "\tDCD\t__load_%s_%u_base\n" + "\tDCD\t0x%08x\n" + "\tDCD\t__load_%s_%u_size\n\n", + opt_basename, index, + p->p_vaddr, + opt_basename, index); + + has_load = 1; + } + + if (p->p_filesz < p->p_memsz) { + frag_pprintf(&binfr, NULL, + "\tAREA\t|.bss.load.%s.%u|, DATA, READWRITE, NOINIT\n\n" + "__bss_%s_%u_base\n" + "\tSPACE\t%u\n" + "__bss_%s_%u_size\tEQU\t. - __bss_%s_%u_base\n\n", + opt_basename, index, + opt_basename, index, + p->p_memsz - p->p_filesz, + opt_basename, index, + opt_basename, index); + + frag_pprintf(&zfr, NULL, + "\tDCD\t0x%08x\n" + "\tDCD\t0x%08x\n\n", + p->p_vaddr + p->p_filesz, p->p_memsz - p->p_filesz); + + has_zi = 1; + } +} + +static void finish_rvct_asm(void) +{ + fputs(binfr.buf, stdout); + if (has_load) + fputs(lfr.buf, stdout); + if (has_zi) + fputs(zfr.buf, stdout); + + printf( + "\tEXPORT\t__entry_%s\n" + "__entry_%s\tEQU\t0x%08x\n" + "\n", + + opt_basename, + opt_basename, opt_entry_point + ); + + puts("\tEND"); +} + +static void init_gnu_asm(void) +{ + frag_init(&lfr); + frag_stpcpy(&lfr, NULL, ".section .rodata.loadtab, \"a\"\n.align\n\n"); + + frag_init(&zfr); + frag_stpcpy(&zfr, NULL, ".section .rodata.zitab, \"a\"\n.align\n\n"); + + frag_init(&binfr); +} + +static void do_phdr_gnu_asm(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index) +{ + Elf32_Phdr *p = &phdrs[index]; + + if (p->p_type != PT_LOAD) + return; /* Ignore everything except loadable segments. */ + + if (p->p_filesz) { + int fd; + FILE *f = NULL; + + do { + snprintf(path_buf, sizeof path_buf, bin_template, rand()); + fd = open(path_buf, O_WRONLY | O_CREAT | O_EXCL, + S_IRWXU | S_IRWXG | S_IRWXO); + } while(fd == EEXIST); + + if (fd == -1 || !(f = fdopen(fd, "wb"))) + die("Could not create temporary file.\n"); + + fwrite ((char *)eh + p->p_offset, 1, p->p_filesz, f); + fclose(f); + + frag_pprintf(&binfr, NULL, + ".section %s.load.%s.%u, \"a%s%s\"\n\n" + "__load_%s_%u_base:\n" + "\t.incbin\t\"%s\"\n" + ".equ __load_%s_%u_size, . - __load_%s_%u_base\n\n", + pf_to_section_basename(p->p_flags), + opt_basename, index, + p->p_flags & PF_X ? "x" : "", + p->p_flags & PF_W ? "w" : "", + opt_basename, index, + path_buf, + opt_basename, index, + opt_basename, index); + + frag_pprintf(&lfr, NULL, + "\t.long\t__load_%s_%u_base\n" + "\t.long\t0x%08x\n" + "\t.long\t__load_%s_%u_size\n\n", + opt_basename, index, + p->p_vaddr, + opt_basename, index); + + has_load = 1; + } + + if (p->p_filesz < p->p_memsz) { + frag_pprintf(&binfr, NULL, + ".section .bss.load.%s.%u, \"aw\", %%nobits\n\n" + "__bss_%s_%u_base:\n" + "\t.space\t%u\n" + ".equ __bss_%s_%u_size, . - __bss_%s_%u_base\n\n", + opt_basename, index, + opt_basename, index, + p->p_memsz - p->p_filesz, + opt_basename, index, + opt_basename, index); + + frag_pprintf(&zfr, NULL, + "\t.long\t0x%08x\n" + "\t.long\t0x%08x\n\n", + p->p_vaddr + p->p_filesz, p->p_memsz - p->p_filesz); + + has_zi = 1; + } +} + +static void finish_gnu_asm(void) +{ + fputs(binfr.buf, stdout); + if (has_load) + fputs(lfr.buf, stdout); + if (has_zi) + fputs(zfr.buf, stdout); + + printf( + ".globl __entry_%s\n" + ".equ __entry_%s, 0x%08x\n", + + opt_basename, + opt_basename, opt_entry_point + ); +} + +static void init_rvct_scf(void) +{ + /* Only lfr used for linker scripts: */ + frag_init(&lfr); +} + +static void do_phdr_rvct_scf(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index) +{ + Elf32_Phdr *p = &phdrs[index]; + + if (p->p_type != PT_LOAD) + return; /* Ignore everything except loadable segments. */ + + if (p->p_filesz) + frag_pprintf(&lfr, NULL, + "%s.load.%s.%u 0x%08x 0x%08x\n" + "{\n" + "\t%s.load.%s.%u 0x%08x 0x%08x\n" + "\t{\n" + "\t\t*(%s.load.%s.%u)\n" + "\t}\n" + "}\n\n", + + pf_to_section_basename(p->p_flags), + opt_basename, index, + p->p_vaddr, p->p_filesz, + pf_to_section_basename(p->p_flags), + opt_basename, index, + p->p_vaddr, p->p_filesz, + pf_to_section_basename(p->p_flags), + opt_basename, index); + + if (p->p_filesz < p->p_memsz) + frag_pprintf(&lfr, NULL, + ".bss.load.%s.%u 0x%08x 0x%08x\n" + "{\n" + "\t.bss.load.%s.%u 0x%08x 0x%08x\n" + "\t{\n" + "\t\t*(.bss.load.%s.%u)\n" + "\t}\n" + "}\n\n", + + opt_basename, index, + p->p_vaddr + p->p_filesz, + p->p_memsz - p->p_filesz, + opt_basename, index, + p->p_vaddr + p->p_filesz, + p->p_memsz - p->p_filesz, + opt_basename, index); +} + +static void finish_rvct_scf(void) +{ + fputs(lfr.buf, stdout); +} + +static void init_gnu_lds(void) +{ + /* Only lfr used for linker scripts: */ + frag_init(&lfr); +} + +static void do_phdr_gnu_lds(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index) +{ + Elf32_Phdr *p = &phdrs[index]; + + if (p->p_type != PT_LOAD) + return; /* Ignore everything except loadable segments. */ + + if (p->p_filesz) + frag_pprintf(&lfr, NULL, + "\t%s.load.%s.%u 0x%08x : {\n" + "\t\t*(%s.load.%s.%u)\n" + "\t}\n\n", + pf_to_section_basename(p->p_flags), + opt_basename, index, + p->p_vaddr, + pf_to_section_basename(p->p_flags), + opt_basename, index); + + if (p->p_filesz < p->p_memsz) + frag_pprintf(&lfr, NULL, + "\t.bss.load.%s.%u 0x%08x : {\n" + "\t\t*(.bss.load.%s.%u)\n" + "\t}\n\n", + opt_basename, index, + p->p_vaddr + p->p_filesz, + opt_basename, index); +} + +static void finish_gnu_lds(void) +{ + fputs(lfr.buf, stdout); +} + +static void init(void) +{ + personality->init(); +} + +static void do_phdr(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned index) +{ + personality->do_phdr(eh, phdrs, index); +} + +static void finish(void) +{ + personality->finish(); +} + +static void do_phdrs(Elf32_Ehdr *eh, Elf32_Phdr *phdrs, unsigned count) +{ + unsigned i; + + for (i = 0; i < count; i++) + do_phdr(eh, phdrs, i); +} + +static void do_elf(void *data) +{ + Elf32_Ehdr *eh = data; + + if (opt_load_address_set) + die("Cannot override ELF image load address.\n"); + + if (!opt_entry_point_set) + opt_entry_point = eh->e_entry; + + do_phdrs(eh, (Elf32_Phdr *)((char *)eh + eh->e_phoff), eh->e_phnum); +} + +/* + * For binary files, we create a fake program header describing the whole + * file, and then process it using do_phdrs. + */ +static void do_binary(void *data, size_t size) +{ + Elf32_Phdr phdr; + + phdr.p_type = PT_LOAD; + phdr.p_offset = 0; + if (!opt_load_address_set) + die("Explicit load address required for binary images.\n"); + phdr.p_vaddr = opt_load_address; + phdr.p_filesz = phdr.p_memsz = size; + phdr.p_flags = PF_R | PF_W | PF_X; + + do_phdrs(data, &phdr, 1); +} + +static void do_file(void *data, size_t size) +{ + if (!opt_binary && !is_elf(data)) { + opt_binary = 1; + warn("assuming binary file.\n"); + } + + if (opt_binary) + do_binary(data, size); + else + do_elf(data); +} + +static void die_usage(void) +{ + fprintf(stderr, + "Usage: %s [-GRskbt] [-l <load address>] [-e <entry point>] [-n <name>] ]<image>\n", + opt_program_name); + + fprintf(stderr, +"\nOutput selection:\n" +" -G: Generate output suitable for GNU binutils (default)\n" +" -R: Generate output suitable for ARM RVCT tools\n" +" -s: Generate assembler source to embed loadable image segments (default)\n" +" Data will be placed in sections .text.load.*, .rodata.load.* etc.\n" +" as appropriate for the section attributes.\n" +"\n" +" Tables for run-time loading is placed in the .rodata.loadtab and\n" +" .rodata.zitab sections. These can be discarded at link time if\n" +" you do not plan to do run-time loading. However, you will usually\n" +" want to retain and .rodata.zitab to zero-initialise .bss data if\n" +" the target ELF loader cannot be relied upon to do it, unless you are\n" +" sure the loaded code doesn't require uninitialised data to be zero-\n" +" initialised.\n" +"\n" +" -k: Generate linker script fragment describing image load map\n" +" Normally, you only want this if you want to place the loaded image\n" +" sections directly in a combined image. If you plan to use a run-\n" +" time loader instead, you should place the loaded sections in the link\n" +" map yourself using wildcards to match the generated section names\n" +" You can then use the tables emitted in .rodata.loadtab and\n" +" .rodata.zitab to perform run-time loading.\n" +"\n" +" For GNU ld [-G], a list of output section descriptions is generated,\n" +" suitable for pasting inside the SECTIONS { } command.\n" +"\n" +" For RVCT armlink [-R], a list of root region descriptions is generated,\n" +" suitable for pasting into a scatter file at the top level.\n" +"\n" +"\nImage options:\n" +" -t: Enter image in Thumb state (default is ARM; not meaningful for ELF)\n" +" -b: Treat <image> is a binary file instead of ELF (default is to guess)\n" +" -l <load address>: Load image to the <load address> (not meaningful for ELF)\n" +" -e <entry point>: Enter image at <entry point> (not meaningful for ELF;\n" +" default is the image start address for binary images)\n" +"\nOutput options:\n" +" -n <name>: base name for sections and labels describing the input (default is\n" +" the object name minus any path or extension\n" +"\n"); + + die("Invalid argument(s).\n"); +} + +static int is_asmchar(int c) +{ + return (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '_' || + c == '.'; +} + +static void parse_args(int argc, char **argv) +{ + char *p; + char *q; + unsigned i; + + opt_program_name = argv[0]; + + while (1) switch (getopt(argc, argv, "e:l:n:GRkstb")) { + case 'e': + opt_entry_point_set = 1; + opt_entry_point = strtoul(optarg, NULL, 0); + break; + case 'l': + opt_load_address_set = 1; + opt_load_address = strtoul(optarg, NULL, 0); + break; + case 'n': + strncpy(opt_basename, optarg, sizeof opt_basename); + break; + case 'G': + opt_toolchain = TOOLS_GNU; + break; + case 'R': + opt_toolchain = TOOLS_RVCT; + break; + case 'k': + opt_output_kind = KIND_LINKER_SCRIPT; + break; + case 's': + opt_output_kind = KIND_ASM; + break; + case 't': + opt_entry_thumb = 1; + break; + case 'b': + opt_binary = 1; + break; + case '?': + die_usage(); + case -1: + /* + * There must be a single non-option argument, which must be + * the filename of the input image: + */ + if (optind + 1 != argc) + die_usage(); + + opt_input_file = fopen(argv[optind], "rb"); + if (!(opt_input_file)) die("Cannot open input file.\n"); + + /* If no base name was specified, generate a suitable name: */ + if (!*opt_basename) { + /* + * If the image name ends with a non-empty string + * following a path, keep only that trailing + * string: + */ + p = strrchr(argv[optind], '/'); + if (p) { + if (p[1]) + ++p; + else + p = NULL; + } + + strncpy(opt_basename, p ? p : argv[optind], + sizeof opt_basename); + + /* + * Remove special characters not allowed by the + * assembler / object format, and chop off any trailing + * extension, unless the resulting string would be + * empty: + */ + for (p = opt_basename; *p; p++) { + if (*p == '.' && p != opt_basename) { + *p = '\0'; + break; + } else if (!(is_asmchar(*p))) + *p = '_'; + } + } + + goto args_done; + } + +args_done: + if (opt_entry_thumb && opt_entry_point_set) opt_entry_point |= 1; + + /* + * Generate format template for temporary files into which to + * dump the loadable segment contents of the input image. + * The base pathname for these files is that of the input image, + */ + p = strrchr(argv[optind], '/'); + p = p ? p + 1 : argv[optind]; /* p = the name with the path removed */ + q = strrchr(p, '.'); + + if (q && q != p) *q = '\0'; + snprintf(bin_template, sizeof bin_template, "%s-%%d.bin", argv[optind]); + + for (i = 0; i < lengthof(personalities); i++) { + if (personalities[i].tools == opt_toolchain && + personalities[i].kind == opt_output_kind) { + personality = &personalities[i]; + return; + } + } + + die ("Unsupported configuration\n"); +} + +/* + * We consciously don't try to be robust against corrupt or invalid ELF + * files. If an out-of-range memory access happens, we'll segfault. + */ +int main(int argc, char **argv) +{ + size_t input_size; + char *data; + + parse_args(argc, argv); + + data = fslurp(opt_input_file, &input_size); + + srand(time(NULL) ^ getpid()); + init(); + + do_file(data, input_size); + /* data memory leaked, but we're about to quit, so it doesn't matter */ + + finish(); + + if (fclose(stdout)) + die("I/O error"); + + return EXIT_SUCCESS; +} |