diff options
author | Dave Martin <dave.martin@linaro.org> | 2011-12-16 11:41:59 +0000 |
---|---|---|
committer | Dave Martin <dave.martin@linaro.org> | 2011-12-16 11:41:59 +0000 |
commit | 9945995974f51e86ff8a5e3162c47e1019ce9a08 (patch) | |
tree | 254d310b4a81e31f5ea2ab914b3cb9e643bf64a6 |
arm-virtualizer: Initial import of v2.1 releasearm_v2.1
From Release_Notes.txt:
ARM Virtualizer software release v2.1
This software release is a v2.1 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
Kingfisher Real-Time System Model (RTSM VE Cortex-A15 KF CCI
version 6.2 Beta).
93 files changed, 15705 insertions, 0 deletions
@@ -0,0 +1 @@ +Release_Notes.txt
\ No newline at end of file @@ -0,0 +1 @@ +Release_Notes.txt
\ No newline at end of file diff --git a/Release_Notes.txt b/Release_Notes.txt new file mode 100644 index 0000000..b4ab788 --- /dev/null +++ b/Release_Notes.txt @@ -0,0 +1,237 @@ +Release notes +============= + +1. Preface + + a. Proprietary notice + + Copyright (c) 2011, 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-11, 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.1 + + 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.1 + + b. ARM Virtualizer software release v2.1 + + This software release is a v2.1 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 + Kingfisher Real-Time System Model (RTSM VE Cortex-A15 KF CCI + version 6.2 Beta). + + This model may be obtained from ARM by separate arrangement. + + c. Deliverables + + This release 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]. + + - Source code for the ARM Virtualizer software. + + - 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 + + 1. Code optimizations have been done to lower the number of cycles + taken to switch payload software execution between the two clusters. + An internal cycle accurate emulation platform was used to perform + the optimizations. It is not possible to undertake the same activity + on the ARM FastModels. The changes mostly center around: + + a. Replacement & rework of C code by assembler routines for + initialising the Secure Monitor and HYP mode environment after a + warm reset. + + b. Context of the vGIC shared distributor interface is not saved any + longer. Since the interface maintains its state across a switch, + changes are made to it directly while restoring context on the + inbound cluster. + + c. MMU is enabled as soon as possible after a warm reset to minimize + strongly ordered accesses. + + d. Barrier instructions are being used more optimally. + + e. The copy_words() routine which was used to save and restore the vGIC + context using word sized loads and stores has been replaced by the + memcpy() library routine. Depending upon the number of bytes that + need to be transferred, it chooses an optimal way of saving and + restoring context. + + 2. The variant field of the KFS_ID register is used to distinguish + between the FastModels and other platform types. + + 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 snoop hit rate calculation support depends on per-CPU tube + constructs. These are currently only present in internal development + versions of the ARM FastModels. A forthcoming release of the ARM + FastModels will incorporate this functionality. For the moment, + attempts to write to non-existent tubes will be treated as a no-op. + (See docs/04-Cache-hit-rate-howto.txt for details). + + 4. This release provides instructions to build and run + large filesystems with the Virtualizer. The use of + large filesystems with the current FastModels + release (RTSM VE Cortex-A15 KF CCI version + 6.2 Beta) is known to be unstable. + + g. Issues resolved since last release + + 1. Bug fixes + + 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. + + h. Test cases and results + + 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 RealView Development Suite version 4.1 [Build 514]. + + 2. Kingfisher Real-Time System Model (RTSM VE Cortex-A15 KF CCI + version 6.2 Beta). + + b. Operating systems + + 1. Ubuntu 10.10. + + 2. Red Hat Enterprise Linux WS release 4 (Nahant Update 4). + diff --git a/acsr/c_helpers.c b/acsr/c_helpers.c new file mode 100644 index 0000000..ac181d8 --- /dev/null +++ b/acsr/c_helpers.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011, 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/acsr/helpers.h b/acsr/helpers.h new file mode 100644 index 0000000..2d8b06f --- /dev/null +++ b/acsr/helpers.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2011, 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/acsr/helpers.s b/acsr/helpers.s new file mode 100644 index 0000000..99bb2a6 --- /dev/null +++ b/acsr/helpers.s @@ -0,0 +1,1065 @@ + ; + ; Copyright (c) 2011, 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 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/acsr/v7.s b/acsr/v7.s new file mode 100644 index 0000000..ffd1b06 --- /dev/null +++ b/acsr/v7.s @@ -0,0 +1,646 @@ + ; + ; Copyright (c) 2011, 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 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 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/acsr/v7_c.c b/acsr/v7_c.c new file mode 100644 index 0000000..9f8cc11 --- /dev/null +++ b/acsr/v7_c.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2011, 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/big-little/Makefile b/big-little/Makefile new file mode 100755 index 0000000..7800148 --- /dev/null +++ b/big-little/Makefile @@ -0,0 +1,227 @@ +# +# Copyright (c) 2011, 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 + +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 + +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 + +SECURE_OBJS += secure_context.o monmode_vectors.o flat_pagetable.o virt_helpers.o virt_events.o \ + secure_resets.o bakery.o tube.o helpers.o + +SECURE_ASFLAGS = --apcs /inter --cpu=Eagle --keep --fpu=none --pd "FM_BETA SETL {$(FM_BETA)}" + +SECURE_CFLAGS = -Iinclude -I. -Isecure_world -I../acsr --cpu=Eagle --fpu=none -O2 \ + -DHOST_CLUSTER=$(HOST_CLUSTER) -DSWITCHER=$(SWITCHER) \ + -DFLUSH_OB_L2=$(FLUSH_OB_L2) -DTUBE=$(TUBE) -DFLUSH_L2_FIX=$(FLUSH_L2_FIX) -DFM_BETA=$(FM_BETA) + +SECURE_LDFLAGS = --verbose --map --fpu=none --symbols --noremove --datacompressor=off \ + --entry $(SECURE_ENTRY_POINT) --scatter $(SECURE_MAPFILE) --predefine="-DFM_BETA=$(FM_BETA)" + +SWITCHER_ASFLAGS += --pd "ASYNC_SWITCH SETL {$(ASYNC)}" \ + --pd "RAND_ASYNC SETL {$(RAND_ASYNC)}" \ + --pd "HOST_CLUSTER SETA $(HOST_CLUSTER)" \ + --pd "USE_HYP_TIMERS SETL {$(HYP_TIMERS)}" \ + --pd "SWITCHER SETL {$(SWITCHER)}" + +SWITCHER_CFLAGS += -DASYNC_SWITCH=$(ASYNC) \ + -DRAND_ASYNC=$(RAND_ASYNC) \ + -DHOST_CLUSTER=$(HOST_CLUSTER) \ + -DUSE_HYP_TIMERS=$(HYP_TIMERS) \ + -DFLUSH_OB_L2=$(FLUSH_OB_L2) \ + -DTUBE=$(TUBE) \ + -DFLUSH_L2_FIX=$(FLUSH_L2_FIX) \ + -DSWITCHER=$(SWITCHER) +endif + +############################################################################################################### +# Virtualisor defines +CMOP_DEBUG ?= FALSE +VIRTUALISOR_CFLAGS += -DCMOP_DEBUG=$(CMOP_DEBUG) +VIRTUALISOR_ASFLAGS += --pd "CMOP_DEBUG SETL {$(CMOP_DEBUG)}" + +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 += cci.o + +ASFLAGS = --apcs /inter --cpu=Eagle --keep --fpu=none \ + $(SWITCHER_ASFLAGS) \ + $(VIRTUALISOR_ASFLAGS) + +CFLAGS = -Iinclude -I. -Ivirtualisor/include -Ivirtualisor/cpus/a7/include \ + -Ivirtualisor/cpus/a15/include -I../acsr \ + --cpu=Eagle --fpu=none -O2 $(SWITCHER_CFLAGS) $(VIRTUALISOR_CFLAGS) + +ifdef DEBUG +CFLAGS += -g -O0 +ASFLAGS += -g +SECURE_CFLAGS += -g -O0 +SECURE_ASFLAGS += -g +endif + +LDFLAGS = --verbose --map --fpu=none --symbols --noremove --datacompressor=off --entry $(ENTRY_POINT) --scatter $(MAPFILE) +OBJS += $(SWITCHER_OBJS) $(VIRTUALISOR_OBJS) $(SVGIC_OBJS) +ENTRY_POINT = bl_setup +LISTFILE = bl_syms.txt +SECURE_LISTFILE = bl_sec_syms.txt +MAPFILE = bl.scf +SECURE_MAPFILE = bl-sec.scf + +CC = armcc +AS = armasm +AR = armar +LD = armlink + + +ifeq ($(FM_BETA), FALSE) +all: bl.axf bl_sec.axf wboot.bin +else +all: bl.axf bl_sec.axf +endif + +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 $(LISTFILE) + $(Q)rm -f $(SECURE_LISTFILE) + +dump: + @echo " OBJDUMP" + fromelf --text -c bl.axf > bl.dump + fromelf --text -c bl_sec.axf > bl_sec.dump + +%.o: %.s + @echo " AS $<" + $(Q)$(AS) $(ASFLAGS) $< -o $@ + +%.o: %.c + @echo " CC $<" + $(Q)$(CC) $(CFLAGS) -c $< -o $@ + +bl.axf: $(OBJS) + $(Q)cat $(MAPFILE).template > $(MAPFILE) + $(Q)sed -i -e "s/HIBASE/${HIBASE}/g" $(MAPFILE) + @echo " LD $@" + $(Q)$(LD) $(LDFLAGS) --symdefs=bl_symdef.o $(OBJS) -o $@ > $(LISTFILE) + +ifeq ($(FM_BETA), FALSE) +wboot.axf: ve_reset_handler.o + @echo " LD $@" + $(Q)$(LD) --ro-base=0x0 $< -o $@ > $(LISTFILE) + +wboot.bin: wboot.axf + @echo " BIN $@" + $(Q)fromelf --bin $< --output $@ +else +SECURE_OBJS += ve_reset_handler.o +wboot.bin: +endif + +bl.ar: $(OBJS) + @echo " AR $@" + $(Q)$(AR) -r $@ $(OBJS) + +%.bin: %.axf + fromelf --bin $< --output $@ + +ve_reset_handler.o: ve_reset_handler.s + @echo " AS $<" + $(Q)$(AS) $(SECURE_ASFLAGS) $< -o $@ + +secure_resets.o: secure_resets.c + @echo " CC $<" + $(Q)$(CC) $(SECURE_CFLAGS) -c $< -o $@ + +monmode_vectors.o: monmode_vectors.s + @echo " AS $<" + $(Q)$(AS) $(SECURE_ASFLAGS) $< -o $@ + +flat_pagetable.o: flat_pagetable.s + @echo " AS $<" + $(Q)$(AS) $(SECURE_ASFLAGS) $< -o $@ + +secure_context.o: secure_context.c + @echo " CC $<" + $(Q)$(CC) $(SECURE_CFLAGS) -c $< -o $@ + +bl_sec.axf: $(SECURE_OBJS) + $(Q)cat $(SECURE_MAPFILE).template > $(SECURE_MAPFILE) + $(Q)sed -i -e "s/HIBASE/${HIBASE}/g" $(SECURE_MAPFILE) + $(Q)$(LD) $(SECURE_LDFLAGS) --symdefs=bl_sec_symdef.o $(SECURE_OBJS) -o $@ > $(SECURE_LISTFILE) + +bl_sec.ar: $(SECURE_OBJS) + $(Q)$(AR) -r $@ $(SECURE_OBJS) + + diff --git a/big-little/bl-sec.scf.template b/big-little/bl-sec.scf.template new file mode 100644 index 0000000..47aaec4 --- /dev/null +++ b/big-little/bl-sec.scf.template @@ -0,0 +1,53 @@ +#! armcc -E + ; + ; Copyright (c) 2011, 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. + ; + +#define TRUE 1 +#define FALSE 0 + +#if FM_BETA +JUMP_LOAD 0x0 0x100 +{ + JUMP_EXEC 0x0 0x100 + { + ve_reset_handler.o (+RO, +RW, +ZI) + } +} +#endif + +LOAD_REGION1 HIBASE00000 NOCOMPRESS ALIGN 4096 65536 +{ + BL_SEC_DV_PAGE +0x0 ALIGN 4096 4096 + { + *(BL_SEC_DV_PAGE) + } + + SEC_CODE HIBASE01000 FIXED + { + *(+RO) + } + + SEC_DATA +0x0 + { + *(+ZI,+RW) + } +} diff --git a/big-little/bl.scf.template b/big-little/bl.scf.template new file mode 100644 index 0000000..c764526 --- /dev/null +++ b/big-little/bl.scf.template @@ -0,0 +1,37 @@ + ; + ; Copyright (c) 2011, 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. + ; + +LOAD_REGION1 HIBASE0D000 NOCOMPRESS ALIGN 4096 65536 +{ + BL_DV_PAGE +0x0 ALIGN 4096 4096 + { + *(BL_DV_PAGE) + } + BL_CODE HIBASE0E000 FIXED + { + *(+RO) + } + BL_DATA +0x0 + { + *(+ZI,+RW) + } +} diff --git a/big-little/common/cci.c b/big-little/common/cci.c new file mode 100644 index 0000000..8bf4b5f --- /dev/null +++ b/big-little/common/cci.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011, 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/big-little/common/hyp_setup.c b/big-little/common/hyp_setup.c new file mode 100644 index 0000000..d65aafc --- /dev/null +++ b/big-little/common/hyp_setup.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 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" + +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); +extern unsigned async_switchover; + +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_switchover && 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/big-little/common/hyp_vectors.s b/big-little/common/hyp_vectors.s new file mode 100644 index 0000000..59d1b66 --- /dev/null +++ b/big-little/common/hyp_vectors.s @@ -0,0 +1,399 @@ + ; + ; Copyright (c) 2011, 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 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 = {FALSE} + 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 {FALSE} +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 {FALSE} +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 {FALSE} + 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 {FALSE} + 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 {FALSE} + 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 = {FALSE} + 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/big-little/common/pagetable_setup.c b/big-little/common/pagetable_setup.c new file mode 100644 index 0000000..132ad73 --- /dev/null +++ b/big-little/common/pagetable_setup.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2011, 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" + +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 contigously 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 contigous 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 Add4KMapping(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]; + 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)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; +} + +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)&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 & anyything 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; + Add4KMapping(&l3_desc, LEVEL1, (unsigned long long *)hyp_l1_pagetable); + + return; +} + +void EnableHypModePageTables(void) +{ + /* Update the HTTBR */ + write_httbr((unsigned long 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; + + } + + /* Map 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; + Add4KMapping(&l3_desc, LEVEL2, + (unsigned long long *)stage2_l2_pagetable); + + /* + * Create a mapping for a device page to be used + * for Locks, Events & anyything 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; + Add4KMapping(&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)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/big-little/common/vgic_handle.c b/big-little/common/vgic_handle.c new file mode 100644 index 0000000..4a7ded1 --- /dev/null +++ b/big-little/common/vgic_handle.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2011, 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 + */ +unsigned async_switchover = ASYNC_SWITCH; + +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_switchover && 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_switchover && 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/big-little/common/vgic_setup.c b/big-little/common/vgic_setup.c new file mode 100644 index 0000000..b72359e --- /dev/null +++ b/big-little/common/vgic_setup.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 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/big-little/common/vgiclib.c b/big-little/common/vgiclib.c new file mode 100644 index 0000000..838fc06 --- /dev/null +++ b/big-little/common/vgiclib.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2011, 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/big-little/include/arm.h b/big-little/include/arm.h new file mode 100644 index 0000000..7db58ce --- /dev/null +++ b/big-little/include/arm.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, 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/big-little/include/bakery.h b/big-little/include/bakery.h new file mode 100644 index 0000000..e8b9ecc --- /dev/null +++ b/big-little/include/bakery.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011, 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/big-little/include/bl.h b/big-little/include/bl.h new file mode 100644 index 0000000..700afa2 --- /dev/null +++ b/big-little/include/bl.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011, 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/big-little/include/context.h b/big-little/include/context.h new file mode 100644 index 0000000..17656a8 --- /dev/null +++ b/big-little/include/context.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011, 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/big-little/include/events.h b/big-little/include/events.h new file mode 100644 index 0000000..d6523e3 --- /dev/null +++ b/big-little/include/events.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 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/big-little/include/gic_registers.h b/big-little/include/gic_registers.h new file mode 100644 index 0000000..92ff5c0 --- /dev/null +++ b/big-little/include/gic_registers.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011, 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/big-little/include/handler.h b/big-little/include/handler.h new file mode 100644 index 0000000..747b31c --- /dev/null +++ b/big-little/include/handler.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011, 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/big-little/include/hvc.h b/big-little/include/hvc.h new file mode 100644 index 0000000..1f71271 --- /dev/null +++ b/big-little/include/hvc.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, 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/big-little/include/hyp_types.h b/big-little/include/hyp_types.h new file mode 100644 index 0000000..123242c --- /dev/null +++ b/big-little/include/hyp_types.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, 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/big-little/include/hyp_vmmap.h b/big-little/include/hyp_vmmap.h new file mode 100644 index 0000000..ef3eeb6 --- /dev/null +++ b/big-little/include/hyp_vmmap.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011, 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/big-little/include/int_master.h b/big-little/include/int_master.h new file mode 100644 index 0000000..ec3b1b7 --- /dev/null +++ b/big-little/include/int_master.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011, 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/big-little/include/misc.h b/big-little/include/misc.h new file mode 100644 index 0000000..c154ced --- /dev/null +++ b/big-little/include/misc.h @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2011, 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); +extern unsigned BL_DV_PAGE$$Base; +extern unsigned BL_SEC_DV_PAGE$$Base; +extern unsigned host_cluster; +extern unsigned switcher; + +#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/big-little/include/traps.h b/big-little/include/traps.h new file mode 100644 index 0000000..323ba42 --- /dev/null +++ b/big-little/include/traps.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011, 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/big-little/include/vgiclib.h b/big-little/include/vgiclib.h new file mode 100644 index 0000000..869a8df --- /dev/null +++ b/big-little/include/vgiclib.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, 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/big-little/include/virt_helpers.h b/big-little/include/virt_helpers.h new file mode 100644 index 0000000..34e4d1c --- /dev/null +++ b/big-little/include/virt_helpers.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011, 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/big-little/lib/bakery.c b/big-little/lib/bakery.c new file mode 100644 index 0000000..bd2547f --- /dev/null +++ b/big-little/lib/bakery.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, 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/big-little/lib/tube.c b/big-little/lib/tube.c new file mode 100644 index 0000000..2fd6486 --- /dev/null +++ b/big-little/lib/tube.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, 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/big-little/lib/uart.c b/big-little/lib/uart.c new file mode 100644 index 0000000..2d4486a --- /dev/null +++ b/big-little/lib/uart.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011, 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. + * Implements fputc() so you can use printf() in your code. + */ + +#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 + +static unsigned uart_base = NULL; + +#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(); +} + +typedef struct __FILE +{ + int dummy; +} FILE; + +FILE __stdout; + +int fputc(int c, FILE *f) +{ + output_char(c); + return c; +} diff --git a/big-little/lib/virt_events.c b/big-little/lib/virt_events.c new file mode 100644 index 0000000..b842324 --- /dev/null +++ b/big-little/lib/virt_events.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2011, 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" + +/* + * 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/big-little/lib/virt_helpers.s b/big-little/lib/virt_helpers.s new file mode 100644 index 0000000..0306e06 --- /dev/null +++ b/big-little/lib/virt_helpers.s @@ -0,0 +1,442 @@ + ; + ; Copyright (c) 2011, 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/big-little/secure_world/events.c b/big-little/secure_world/events.c new file mode 100644 index 0000000..d5c5e54 --- /dev/null +++ b/big-little/secure_world/events.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 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/big-little/secure_world/flat_pagetable.s b/big-little/secure_world/flat_pagetable.s new file mode 100644 index 0000000..38762e9 --- /dev/null +++ b/big-little/secure_world/flat_pagetable.s @@ -0,0 +1,119 @@ + ; + ; Copyright (c) 2011, 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 PageTable, DATA, READONLY, ALIGN=14 + EXPORT flat_pagetables + GBLL CONFIG_SMP_CPU3_AMP +CONFIG_SMP_CPU3_AMP SETL {FALSE} + +; 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 + 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 + + END + diff --git a/big-little/secure_world/monmode_vectors.s b/big-little/secure_world/monmode_vectors.s new file mode 100644 index 0000000..14a416f --- /dev/null +++ b/big-little/secure_world/monmode_vectors.s @@ -0,0 +1,391 @@ + ; + ; Copyright (c) 2011, 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 |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 + MOV $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 + ; ---------------------------------------------------- + MOV 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 + CMP r1, #0 + BNE cci_snoop_status + MOV r3, #3 + CMP r2, #0 + BEQ a15_snoops + MOV r5, #0x5000 + STR r3, [r4, r5] + B cci_snoop_status +a15_snoops + MOV r5, #0x4000 + STR r3, [r4, r5] +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 stacks, DATA, ALIGN=6 +secure_stacks SPACE MAX_CLUSTERS*MAX_CPUS*STACK_SIZE + END diff --git a/big-little/secure_world/secure_context.c b/big-little/secure_world/secure_context.c new file mode 100644 index 0000000..ff864f1 --- /dev/null +++ b/big-little/secure_world/secure_context.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2011, 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("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/big-little/secure_world/secure_resets.c b/big-little/secure_world/secure_resets.c new file mode 100644 index 0000000..cb732ba --- /dev/null +++ b/big-little/secure_world/secure_resets.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2011, 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("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 + */ +unsigned event[MAX_CORES][MAX_SEC_EVENTS] +__attribute__ ((section("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("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("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/big-little/secure_world/secure_world.h b/big-little/secure_world/secure_world.h new file mode 100644 index 0000000..9d6db42 --- /dev/null +++ b/big-little/secure_world/secure_world.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011, 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/big-little/secure_world/ve_reset_handler.s b/big-little/secure_world/ve_reset_handler.s new file mode 100644 index 0000000..1a5b6a1 --- /dev/null +++ b/big-little/secure_world/ve_reset_handler.s @@ -0,0 +1,58 @@ + ; + ; Copyright (c) 2011, 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 test, CODE + + ENTRY + + [ 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 + + | + + 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 + + ] + + END + diff --git a/big-little/switcher/context/gic.c b/big-little/switcher/context/gic.c new file mode 100644 index 0000000..4195346 --- /dev/null +++ b/big-little/switcher/context/gic.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2011, 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; + +/* + * 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; + memcpy((void *) pointer, (const void *) id->priority, 8 << 2); + pointer += 8; + memcpy((void *) pointer, (const void *) id->target, 8 << 2); + 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; + memcpy((void *) pointer, (const void *) id->sgi_set_pending, 4 << 2); + pointer += 8; + + /* + * Clear the pending SGIs on this cpuif so that they don't + * interfere with the wfi later on. + */ + memcpy((void *) id->sgi_clr_pending, (const void *) ptr, 4 << 2); + + 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) { + memcpy((void *) pointer, (const void *) (id->target + 8), (num_spis / 4) << 2); + 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; + + memcpy((void *) id->priority, (const void *) pointer, 8 << 2); + pointer += 8; + memcpy((void *) id->target, (const void *) pointer, 8 << 2); + 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]); + } + } + + memcpy((void *) id->sgi_set_pending, (const void *) pointer, 4 << 2); + 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) { + + memcpy((void *) pointer, (const void *) (id->target + 8), (num_spis / 4) << 2); + + 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]); + } + } + + memcpy((void *) (id->target + 8), (const void *) pointer, (num_spis / 4) << 2); + } + + return; +} diff --git a/big-little/switcher/context/ns_context.c b/big-little/switcher/context/ns_context.c new file mode 100644 index 0000000..891f5bb --- /dev/null +++ b/big-little/switcher/context/ns_context.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2011, 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" + +extern void gic_enable_int(unsigned); +extern void SetupVGIC(unsigned); +extern unsigned async_switchover; +extern unsigned hyp_timer_trigger; + +/* Bakery locks to serialize access to the tube. */ +static bakery_t lock_tube0 __attribute__ ((section("BL_DV_PAGE"))) = { 0 }; +static bakery_t lock_tube1 __attribute__ ((section("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(!hyp_timer_trigger) { + 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_switchover && cpu_id == first_cpu) + enable_trigger(read_cntfrq()); + + return; +} diff --git a/big-little/switcher/context/sh_vgic.c b/big-little/switcher/context/sh_vgic.c new file mode 100644 index 0000000..a13f862 --- /dev/null +++ b/big-little/switcher/context/sh_vgic.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2011, 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 = __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 = __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 = __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/big-little/switcher/trigger/async_switchover.c b/big-little/switcher/trigger/async_switchover.c new file mode 100644 index 0000000..056c8a1 --- /dev/null +++ b/big-little/switcher/trigger/async_switchover.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2011, 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" +#include "stdlib.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); +extern int __rand_r(struct _rand_state *); +/* + * 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 */ +static unsigned rand_async_switches = RAND_ASYNC; +/* Use HYP timer for async switches */ +unsigned hyp_timer_trigger = USE_HYP_TIMERS; + +/* + * 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 (hyp_timer_trigger == FALSE) { + /* + * 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 (hyp_timer_trigger) + 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 (hyp_timer_trigger) + 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. + */ + static unsigned int rand_no = 0xdeadbeef; + static struct _rand_state buffer; + + /* + * Nothing needs to be done if physical local timers + * are being used for doing a switchover. + */ + if (hyp_timer_trigger == TRUE) { + if (rand_async_switches) { + _srand_r(&buffer, rand_no); + rand_no = (unsigned) _rand_r(&buffer); + } + + /* Enable timer and unmask interrupt */ + write_cnthp_ctl(ctl); + + if (rand_async_switches) { + 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/big-little/switcher/trigger/handle_switchover.s b/big-little/switcher/trigger/handle_switchover.s new file mode 100644 index 0000000..d18ba21 --- /dev/null +++ b/big-little/switcher/trigger/handle_switchover.s @@ -0,0 +1,61 @@ + ; + ; Copyright (c) 2011, 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 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/big-little/switcher/trigger/sync_switchover.c b/big-little/switcher/trigger/sync_switchover.c new file mode 100644 index 0000000..ad257bc --- /dev/null +++ b/big-little/switcher/trigger/sync_switchover.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011, 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/big-little/virtualisor/cache_geom.c b/big-little/virtualisor/cache_geom.c new file mode 100644 index 0000000..4138eeb --- /dev/null +++ b/big-little/virtualisor/cache_geom.c @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2011, 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" + +unsigned cmop_debug = CMOP_DEBUG; +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 >> __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/big-little/virtualisor/cpus/a15/a15.c b/big-little/virtualisor/cpus/a15/a15.c new file mode 100644 index 0000000..92bebac --- /dev/null +++ b/big-little/virtualisor/cpus/a15/a15.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011, 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" + +/* 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("virt_desc_section"))) = { + A15, + {0}, + a15_trap_setup, + a15_trap_handle, + a15_trap_save, + a15_trap_restore, +}; diff --git a/big-little/virtualisor/cpus/a15/include/a15.h b/big-little/virtualisor/cpus/a15/include/a15.h new file mode 100644 index 0000000..554e401 --- /dev/null +++ b/big-little/virtualisor/cpus/a15/include/a15.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011, 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/big-little/virtualisor/cpus/a7/a7.c b/big-little/virtualisor/cpus/a7/a7.c new file mode 100644 index 0000000..9c3cef5 --- /dev/null +++ b/big-little/virtualisor/cpus/a7/a7.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011, 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" + +/* 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("virt_desc_section"))) = { + A7, + {0}, + a7_trap_setup, + a7_trap_handle, + a7_trap_save, + a7_trap_restore, +}; diff --git a/big-little/virtualisor/cpus/a7/include/a7.h b/big-little/virtualisor/cpus/a7/include/a7.h new file mode 100644 index 0000000..5e2b62f --- /dev/null +++ b/big-little/virtualisor/cpus/a7/include/a7.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011, 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/big-little/virtualisor/include/cache_geom.h b/big-little/virtualisor/include/cache_geom.h new file mode 100644 index 0000000..642e0e9 --- /dev/null +++ b/big-little/virtualisor/include/cache_geom.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 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 << __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 ccselr; + /* 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/big-little/virtualisor/include/mem_trap.h b/big-little/virtualisor/include/mem_trap.h new file mode 100644 index 0000000..4c4a200 --- /dev/null +++ b/big-little/virtualisor/include/mem_trap.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011, 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 *); +extern mem_trap_data s2_trap_section$$Base; +extern unsigned s2_trap_section$$Length; + +#endif /* __MEM_TRAP_H__ */ diff --git a/big-little/virtualisor/include/virtualisor.h b/big-little/virtualisor/include/virtualisor.h new file mode 100644 index 0000000..c3bf2c1 --- /dev/null +++ b/big-little/virtualisor/include/virtualisor.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, 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); +extern virt_descriptor virt_desc_section$$Base; +extern unsigned virt_desc_section$$Length; +extern unsigned host_cluster; +extern unsigned switcher; + +#endif /* __VIRTUALISOR_H__ */ diff --git a/big-little/virtualisor/mem_trap.c b/big-little/virtualisor/mem_trap.c new file mode 100644 index 0000000..a3a2de8 --- /dev/null +++ b/big-little/virtualisor/mem_trap.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011, 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/big-little/virtualisor/vgic_trap_handler.c b/big-little/virtualisor/vgic_trap_handler.c new file mode 100644 index 0000000..77ac14c --- /dev/null +++ b/big-little/virtualisor/vgic_trap_handler.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 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/big-little/virtualisor/virt_context.c b/big-little/virtualisor/virt_context.c new file mode 100644 index 0000000..80a79b2 --- /dev/null +++ b/big-little/virtualisor/virt_context.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2011, 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" +extern virt_reg_data host_virt_regs[]; +extern reg_trap_data host_trap_regs[]; +extern unsigned cmop_debug; +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 = (unsigned)&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 = (unsigned)&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 = (unsigned)&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 = (unsigned)&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/big-little/virtualisor/virt_handle.c b/big-little/virtualisor/virt_handle.c new file mode 100644 index 0000000..2cfb2cc --- /dev/null +++ b/big-little/virtualisor/virt_handle.c @@ -0,0 +1,589 @@ +/* + * Copyright (c) 2011, 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" + +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]. + ccselr)]; + 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]. + ccselr = regs->r[Rt]; + else + regs->r[Rt] = + target_cache_geometry[cpu_id]. + ccselr; + 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], + dccsw, + &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 = (unsigned)&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/big-little/virtualisor/virt_setup.c b/big-little/virtualisor/virt_setup.c new file mode 100644 index 0000000..c2dd75e --- /dev/null +++ b/big-little/virtualisor/virt_setup.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2011, 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" + +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("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 = (unsigned)&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/bootwrapper/Makefile b/bootwrapper/Makefile new file mode 100755 index 0000000..addcdae --- /dev/null +++ b/bootwrapper/Makefile @@ -0,0 +1,138 @@ +# +# Copyright (c) 2011, 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 + +VE?=TRUE +T2?=FALSE +L2_POLICY?=WF +LOBASE?=0x800 +KERNADDR?=$(LOBASE)08000 +# 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 "$(BA)" "" +BOOTARGS=mem=255M console=ttyAMA0,115200 migration_cost=500 cachepolicy=writealloc +BA=$(BOOTARGS) +else +BOOTARGS=$(BA) +endif + +V7_ASFLAGS=--apcs /inter --cpu=Eagle --keep \ + --pd "BOOTARGS SETS \"$(BOOTARGS)\"" \ + --pd "L2_POLICY SETS \"$(L2_POLICY)\"" \ + --pd "VE SETL {$(VE)}" \ + --pd "HIBASE SETS \"$(HIBASE)\"" + +CFLAGS:=--cpu=Eagle -O2 \ + -DT2=$(T2) \ + -DSETUPMMU=$(SETUPMMU) \ + -DHIBASE=$(HIBASE) \ + -DVE=$(VE) \ + -DVECTBASE=$(VECTBASE) + +ifdef DEBUG +CFLAGS += -g -O0 +ASFLAGS += -g +V7_ASFLAGS += -g +endif + +OBJS= boot.o bootargs.o c_start.o helpers.o kernel.o filesystem.o uart.o vectors.o bl_sec.o bl.o + +.PHONY: all +all: img.axf + +.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 $(OBJS) img.axf *.map bl.S bl_sec.S + make -C big-little clean + +# Extra dependencies +boot.o: emubuild.s +helpers.o : emubuild.s + +%.o: %.S + @echo " AS $<" + $(Q)armasm $(V7_ASFLAGS) -o $@ $< + +%.o: %.c + @echo " CC $<" + $(Q)armcc $(CFLAGS) -o $@ -c $< + +bl.S: + make -C big-little bl.axf + @echo " MAP" + $(Q)./makemap big-little/bl.axf bl + +bl.o: bl.S + @echo " AS $<" + $(Q)armasm $(V7_ASFLAGS) -o $@ $< + +bl_sec.S: + make -C big-little bl_sec.axf wboot.bin + @echo " MAP" + $(Q)./makemap big-little/bl_sec.axf bl_sec + +bl_sec.o: bl_sec.S + @echo " AS $<" + $(Q)armasm $(V7_ASFLAGS) -o $@ $< + +img.axf: $(OBJS) + $(Q)cat boot.map.template > boot.map + $(Q)cat bl_sec.map >> boot.map + $(Q)cat bl.map >> boot.map + $(Q)sed -i \ + -e "s/KERNADDRBA/$(shell perl -e "printf('0x%08X',$(KERNADDR)-0x7f00)")/g" \ + -e "s/FSADDR/${FSADDR}/g" \ + -e "s/HIBASE/${HIBASE}/g" \ + -e "s/KERNADDR/${KERNADDR}/g" \ + -e "s/VECTBASE/${VECTBASE}/g" \ + boot.map + @echo " LD $@" + $(Q)armlink --entry $(VECTBASE)00000 -o $@ --scatter boot.map $(OBJS) + diff --git a/bootwrapper/acsr b/bootwrapper/acsr new file mode 120000 index 0000000..87fe232 --- /dev/null +++ b/bootwrapper/acsr @@ -0,0 +1 @@ +../acsr
\ No newline at end of file diff --git a/bootwrapper/big-little b/bootwrapper/big-little new file mode 120000 index 0000000..a482b29 --- /dev/null +++ b/bootwrapper/big-little @@ -0,0 +1 @@ +../big-little
\ No newline at end of file diff --git a/bootwrapper/big-little-mp1.mxscript b/bootwrapper/big-little-mp1.mxscript new file mode 100755 index 0000000..b007e3d --- /dev/null +++ b/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/bootwrapper/big-little-mp4.mxscript b/bootwrapper/big-little-mp4.mxscript new file mode 100755 index 0000000..96bc6bf --- /dev/null +++ b/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/bootwrapper/bl-mp1-fm-eac.mxscript b/bootwrapper/bl-mp1-fm-eac.mxscript new file mode 100755 index 0000000..7a7912e --- /dev/null +++ b/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/bootwrapper/bl-mp4-fm-eac.mxscript b/bootwrapper/bl-mp4-fm-eac.mxscript new file mode 100755 index 0000000..6099351 --- /dev/null +++ b/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/bootwrapper/boot.S b/bootwrapper/boot.S new file mode 100644 index 0000000..6afbf34 --- /dev/null +++ b/bootwrapper/boot.S @@ -0,0 +1,199 @@ + ; + ; Copyright (c) 2011, 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 |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/bootwrapper/boot.map.template b/bootwrapper/boot.map.template new file mode 100644 index 0000000..7267c4b --- /dev/null +++ b/bootwrapper/boot.map.template @@ -0,0 +1,65 @@ + ; + ; Copyright (c) 2011, 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. + ; + + +VECTORS VECTBASE00000 0x100 +{ + VECTORSEXEC VECTBASE00000 0x100 + { + vectors.o (+RO,+RW,+ZI) + } +} + +BOOTARGS KERNADDRBA 0x4000 +{ + BOOTARGS 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 HIBASEE0000 0x00018000 +{ + HIGHCODEALL +0 + { + *.o (*) + } +} + diff --git a/bootwrapper/bootargs.S b/bootwrapper/bootargs.S new file mode 100644 index 0000000..3c57492 --- /dev/null +++ b/bootwrapper/bootargs.S @@ -0,0 +1,73 @@ + ; + ; Copyright (c) 2011, 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 | bootargs|, CODE, ALIGN=8 + PRESERVE8 + + EXPORT bootargs + EXPORT param_biosep + IMPORT |filesystem$$Base| + IMPORT |filesystem$$Length| + INCLUDE emubuild.s + + GBLS args + IF L2_POLICY != "NC" +args SETS BOOTARGS :CC: " l2=alreadyon" + ELSE +args SETS BOOTARGS :CC: " nol2x0" + ENDIF + + +; ============================================================================== +; 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 + DCD ( :LEN:args +2+3)/4+7 ; Size in words + 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 |filesystem$$Base| + DCD |filesystem$$Length| + DCD 0x00000000 ; Size = 0 words + DCD 0x00000000 ; ATAG_NONE - end of list + ALIGN 4 + + END diff --git a/bootwrapper/bootwrapper.h b/bootwrapper/bootwrapper.h new file mode 100644 index 0000000..7d44493 --- /dev/null +++ b/bootwrapper/bootwrapper.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011, 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 128 +#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/bootwrapper/c_start.c b/bootwrapper/c_start.c new file mode 100644 index 0000000..12442ff --- /dev/null +++ b/bootwrapper/c_start.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2011, 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, *bl_sec_image; +extern void bl_image(unsigned, unsigned, unsigned, unsigned); +extern void kernel_start(int, int, int, int); + +/* Reserve some stack space - 512 bytes per CPU -> 2048 bytes total */ +unsigned stack[NUM_CPUS * STACK_SIZE]; +unsigned stack_size = STACK_SIZE * sizeof(unsigned); +unsigned char cpus_ready[NUM_CLUSTERS][NUM_CPUS]; +unsigned thumb = T2; +void (*kernel_start_address) (int, int, int, int); +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) { + __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)&bl_sec_image); + 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)bl_image); + + /* 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 at 0x%x\n", kernel_start); + + if (thumb) + kernel_start_address = + (void (*)(int, int, int, int))((unsigned)kernel_start | 1); + else + kernel_start_address = kernel_start; + + printf("Kernel entry point 0x%x (%s)\n", kernel_start_address, + ((unsigned)kernel_start_address & 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_address(0, platform & PLATFORM_MASK, 0, 0); /* No return from here */ + + return; +} diff --git a/bootwrapper/emubuild.s b/bootwrapper/emubuild.s new file mode 100644 index 0000000..b487015 --- /dev/null +++ b/bootwrapper/emubuild.s @@ -0,0 +1,52 @@ + ; + ; Copyright (c) 2011, 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 + + END diff --git a/bootwrapper/filesystem.S b/bootwrapper/filesystem.S new file mode 100644 index 0000000..4b8cb31 --- /dev/null +++ b/bootwrapper/filesystem.S @@ -0,0 +1,29 @@ + ; + ; Copyright (c) 2011, 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 |filesystem|, CODE, ALIGN=2 + + EXPORT fs_start + EXPORT fs_end +fs_start + INCBIN payload/fsimg +fs_end + END diff --git a/bootwrapper/helpers.S b/bootwrapper/helpers.S new file mode 100644 index 0000000..811b263 --- /dev/null +++ b/bootwrapper/helpers.S @@ -0,0 +1,1320 @@ + ; + ; Copyright (c) 2011, 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 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/bootwrapper/helpers.h b/bootwrapper/helpers.h new file mode 100644 index 0000000..1142627 --- /dev/null +++ b/bootwrapper/helpers.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2011, 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/bootwrapper/kernel.S b/bootwrapper/kernel.S new file mode 100644 index 0000000..1586abb --- /dev/null +++ b/bootwrapper/kernel.S @@ -0,0 +1,27 @@ + ; + ; Copyright (c) 2011, 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 |kernel|, CODE, ALIGN=2 + EXPORT kernel_start +kernel_start + INCBIN payload/kernel + END diff --git a/bootwrapper/makemap b/bootwrapper/makemap new file mode 100755 index 0000000..47213c9 --- /dev/null +++ b/bootwrapper/makemap @@ -0,0 +1,174 @@ +#! /bin/env perl +# +# Copyright (c) 2011, 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. +# + +use strict; + +use vars qw( + $image + $source + $obj + $map + $kernaddr + $sh + $mh + %chunksdone + @chunks +); + +sub addchunk($$) +{ + my $file = shift; + my $addr = shift; + my $size = -s $file; + my $name = $file; + $name =~ s|^.*/([^/]+)$|$1|; + + # Multiple contiguous sections are saved as one chunk, so in that case only process the first + if (!defined $chunksdone{$name}) + { + print $sh <<EOF; + AREA |$name|, CODE, ALIGN=2 + INCBIN $file +EOF + + print $mh <<EOF; +$name $addr $size +{ + ${name}DATA $addr $size + { + $obj ($name) + } +} +EOF + + $chunksdone{$name} = 1; + push @chunks, [ $addr, $size ]; + } +} + +sub num($) +{ + my $n = shift; + $n = oct $n if $n =~ /^0/; + return $n; +} + +sub covered($) +{ + my $start = num(shift); + + for (@chunks) + { +# printf "Checking $start against chunk $_->[0] (%d), $_->[1] (%d), %d\n",num($_->[0]),num($_->[1]),num($_->[0])+num($_->[0]); + return 1 if $start >= num($_->[0]) && $start < num($_->[0])+num($_->[1]); + } + return 0; +} + +($image=shift) && ($source = shift) or die "\ +Usage: $0 image source [ kernaddr ] + Creates source and map files to load the sections of \$image + \(if it is an ARM ELF file\), or the whole of \$image at \$kernaddr"; + +$kernaddr=shift; +$map="$source.map"; +$obj="$source.o"; + +open $sh, ">$source.S" or die "Can't create '$source.S'"; +open $mh, ">$map" or die "Can't create '$map'"; + +# Check if $image is an ELF file +my $type=`file -L $image`; +if ( $type =~ /ELF.*ARM/ ) +{ +# print "$image is an ELF file - splitting\n"; + system("rm -rf $image.bin"); + system("fromelf --bin $image -o $image.bin"); + my $fromelfv=`fromelf --vsn`; + ($fromelfv=~/FromELF, (RVCT|)([\d\.]+)/) && ($2 >= 4.1) or die "fromelf version '$2' is too old - need 4.1 or greater"; + my $desc = `fromelf --text $image`; + my $chunk; + my $chunkdone; + my %chunkdefined; + my $zichunk; + + for my $line (split /\n/,$desc) + { + # Program header lines indicate what loadable chunks are present + # Handily, these refer to 'Virtual address' rather than 'Address' + $chunkdefined{$1} = 1 if $line =~ /^\s+Virtual address:\s+(0x[0-9a-fA-F]+)/; + + # Section entries give the chunk name + if ($line =~ /^\*+\s+Section\s+#\d+\s+'([^']+)/) + { + # If there's only one chunk, fromelf creates a single file not a directory + $chunk = -d "$image.bin" ? "$image.bin/$1" : "$image.bin"; + $zichunk = 0; + if ($line =~ / \(SHT_NOBITS\) /) + { + # We produce an explicit block of zeroes to cope with systems that don't auto-expand ZINIT areas + $chunk .= '.zi'; + $zichunk = 1; + } + } + + if ($zichunk && ($line =~ /^\s+Size\s*:\s+(\d+)\s+bytes/)) + { + my $size = $1; + my $h; + open $h, ">$chunk" or die "Can't create ZI chunk '$chunk'"; + binmode $h; + print $h chr(0) x $size; + close $h; + } + if ($line =~ /^\s+Address:\s+(0x[0-9a-fA-F]+)/ && ($zichunk || $chunkdefined{$1})) + { + # ZI data is already in the binary dump if it is followed by non-ZI data. + if ($zichunk && covered($1)) + { + print "ZI data at $1 set by existing data; will not set explicitly\n"; + $zichunk = 0; + # Remove .zi + $chunk = substr($chunk,0,-3); + } + else + { + # Multiple contiguous sections are saved as one chunk, so in that case only process the first + # Here we deal with the case where all the sections are contiguous + addchunk("$chunk",$1) if $zichunk || -d "$image.bin" || !$chunkdone; + $chunkdone = 1; + } + } + + $kernaddr=$1 if $line =~ /^\s+Image Entry point:\s+(0x[0-9a-fA-F]+)/; + } +} +else +{ +# print "$image being wrapped as plain binary to load at $kernaddr\n"; + addchunk($image,$kernaddr); +} + +die "No entry point in image or on command line" if !defined $kernaddr; + +print $sh " EXPORT ${source}_image\n${source}_image EQU $kernaddr\n END\n"; diff --git a/bootwrapper/payload/fsimg b/bootwrapper/payload/fsimg new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/bootwrapper/payload/fsimg diff --git a/bootwrapper/payload/kernel b/bootwrapper/payload/kernel Binary files differnew file mode 100644 index 0000000..4467aef --- /dev/null +++ b/bootwrapper/payload/kernel diff --git a/bootwrapper/uart.c b/bootwrapper/uart.c new file mode 100644 index 0000000..138b0d5 --- /dev/null +++ b/bootwrapper/uart.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, 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. + * Implements fputc() so you can use printf() in your code. + */ + +#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 + +static unsigned uart_base = NULL; + +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(); +} + +typedef struct __FILE { + int dummy; +} FILE; + +FILE __stdout; + +int fputc(int c, FILE * f) +{ + output_char(c); + return c; +} diff --git a/bootwrapper/vectors.S b/bootwrapper/vectors.S new file mode 100644 index 0000000..1474ff1 --- /dev/null +++ b/bootwrapper/vectors.S @@ -0,0 +1,73 @@ + ; + ; Copyright (c) 2011, 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 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/bootwrapper/vgic.h b/bootwrapper/vgic.h new file mode 100644 index 0000000..56b5389 --- /dev/null +++ b/bootwrapper/vgic.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011, 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/docs/01-Usage.txt b/docs/01-Usage.txt new file mode 100644 index 0000000..3eeb764 --- /dev/null +++ b/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_1-171111/bootwrapper/makemap + + Failure to make this modification will result in a build + failure. + + To build the software: + + $ tar -jxf arm-virtualizer-v2_1-171111.tar.bz2 + $ cd arm-virtualizer-v2_1-171111/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_1-171111/bootwrapper/payload/kernel + + .. and the placeholder dummy root filesystem image is located + at: + + arm-virtualizer-v2_1-171111/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 Kingfisher Real-Time System Model (RTSM VE Cortex-A15 KF + CCI version 6.2 Beta) 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/docs/02-Code-layout.txt b/docs/02-Code-layout.txt new file mode 100644 index 0000000..d033b39 --- /dev/null +++ b/docs/02-Code-layout.txt @@ -0,0 +1,565 @@ +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. & 2.
+ in an payload software agnostic manner.
+
+ This software is intended to be executed on the Cortex-A7
+ Real-Time System Model (RTSM VE Cortex-A15 KF CCI version
+ 6.2 Beta).
+
+ 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 & 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 & Locking
+ routines.
+
+ 4. big-little/include
+
+ 1. This directory contains the headers specific to HYP
+ mode setup, Switching process & 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 & 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 & 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 & configure some
+ coprocessor & 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 & 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/docs/03-Linux-kernel-build.txt b/docs/03-Linux-kernel-build.txt new file mode 100644 index 0000000..b5d79b2 --- /dev/null +++ b/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_1-171111.tar.bz2 +$ cd arm-virtualizer-v2_1-171111/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_1-171111/bootwrapper/img.axf. + +To launch the ARM FastModel with the virtualizer, first modify +arm-virtualizer-v2_1-171111/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. + +Eg. 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_1-171111/bootwrapper/img.axf"; + +The model can then be launched using: + +modeldebugger -s arm-virtualizer-v2_1-171111/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/docs/04-Cache-hit-rate-howto.txt b/docs/04-Cache-hit-rate-howto.txt new file mode 100644 index 0000000..60d37a5 --- /dev/null +++ b/docs/04-Cache-hit-rate-howto.txt @@ -0,0 +1,208 @@ +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 current version of ARM FastModels (RTSM VE Cortex-A15 KF + CCI version MODEL_VERSION) implements only one 'tube' + interface i.e. TUBE0. + + Subsequent releases will support upto four 'tube' interfaces i.e TUBE0-3. + The Virtualizer code has been internally tested to work with all four 'tube' + sources and assumes their presence. Writing to a non-existent + 'tube' interface is treated as a nop and the trace file will contain + messages only from the 'sw_trace_event' source i.e TUBE0. + + (Please correspond with the ARM FastModels team for details on future ARM + FastModels releases that will support all four tube interfaces). diff --git a/docs/05-FAQ.txt b/docs/05-FAQ.txt new file mode 100644 index 0000000..a2e9790 --- /dev/null +++ b/docs/05-FAQ.txt @@ -0,0 +1,18 @@ +Frequently asked questions +========================== + +1. What is the per-core context size that is switched between + clusters ? + +A. 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/docs/06-Optional-rootfs-build.txt b/docs/06-Optional-rootfs-build.txt new file mode 100644 index 0000000..6e372ea --- /dev/null +++ b/docs/06-Optional-rootfs-build.txt @@ -0,0 +1,125 @@ +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_1-171111/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_1-171111.tar.bz2 + $ cd arm-virtualizer-v2_1-171111/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 + + Use of a comprehensive root filesystem as opposed to busybox + is known to be unstable on the current ARM FastModel release (Release + 6.2 Beta). Subsequent model releases shall contain appropriate fixes as + required). |