summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Martin <dave.martin@linaro.org>2011-12-16 11:41:59 +0000
committerDave Martin <dave.martin@linaro.org>2011-12-16 11:41:59 +0000
commit9945995974f51e86ff8a5e3162c47e1019ce9a08 (patch)
tree254d310b4a81e31f5ea2ab914b3cb9e643bf64a6
downloadswitcher-arm_v2.1.tar.gz
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).
l---------COPYING1
l---------README1
-rw-r--r--Release_Notes.txt237
-rw-r--r--acsr/c_helpers.c90
-rw-r--r--acsr/helpers.h222
-rw-r--r--acsr/helpers.s1065
-rw-r--r--acsr/v7.s646
-rw-r--r--acsr/v7_c.c273
-rwxr-xr-xbig-little/Makefile227
-rw-r--r--big-little/bl-sec.scf.template53
-rw-r--r--big-little/bl.scf.template37
-rw-r--r--big-little/common/cci.c57
-rw-r--r--big-little/common/hyp_setup.c107
-rw-r--r--big-little/common/hyp_vectors.s399
-rw-r--r--big-little/common/pagetable_setup.c442
-rw-r--r--big-little/common/vgic_handle.c210
-rw-r--r--big-little/common/vgic_setup.c82
-rw-r--r--big-little/common/vgiclib.c498
-rw-r--r--big-little/include/arm.h70
-rw-r--r--big-little/include/bakery.h53
-rw-r--r--big-little/include/bl.h47
-rw-r--r--big-little/include/context.h133
-rw-r--r--big-little/include/events.h78
-rw-r--r--big-little/include/gic_registers.h102
-rw-r--r--big-little/include/handler.h32
-rw-r--r--big-little/include/hvc.h44
-rw-r--r--big-little/include/hyp_types.h38
-rw-r--r--big-little/include/hyp_vmmap.h42
-rw-r--r--big-little/include/int_master.h50
-rw-r--r--big-little/include/misc.h404
-rw-r--r--big-little/include/traps.h102
-rw-r--r--big-little/include/vgiclib.h51
-rw-r--r--big-little/include/virt_helpers.h98
-rw-r--r--big-little/lib/bakery.c71
-rw-r--r--big-little/lib/tube.c58
-rw-r--r--big-little/lib/uart.c125
-rw-r--r--big-little/lib/virt_events.c120
-rw-r--r--big-little/lib/virt_helpers.s442
-rw-r--r--big-little/secure_world/events.c95
-rw-r--r--big-little/secure_world/flat_pagetable.s119
-rw-r--r--big-little/secure_world/monmode_vectors.s391
-rw-r--r--big-little/secure_world/secure_context.c210
-rw-r--r--big-little/secure_world/secure_resets.c292
-rw-r--r--big-little/secure_world/secure_world.h87
-rw-r--r--big-little/secure_world/ve_reset_handler.s58
-rw-r--r--big-little/switcher/context/gic.c264
-rw-r--r--big-little/switcher/context/ns_context.c295
-rw-r--r--big-little/switcher/context/sh_vgic.c225
-rw-r--r--big-little/switcher/trigger/async_switchover.c290
-rw-r--r--big-little/switcher/trigger/handle_switchover.s61
-rw-r--r--big-little/switcher/trigger/sync_switchover.c64
-rw-r--r--big-little/virtualisor/cache_geom.c443
-rw-r--r--big-little/virtualisor/cpus/a15/a15.c73
-rw-r--r--big-little/virtualisor/cpus/a15/include/a15.h26
-rw-r--r--big-little/virtualisor/cpus/a7/a7.c73
-rw-r--r--big-little/virtualisor/cpus/a7/include/a7.h26
-rw-r--r--big-little/virtualisor/include/cache_geom.h107
-rw-r--r--big-little/virtualisor/include/mem_trap.h53
-rw-r--r--big-little/virtualisor/include/virtualisor.h84
-rw-r--r--big-little/virtualisor/mem_trap.c132
-rw-r--r--big-little/virtualisor/vgic_trap_handler.c82
-rw-r--r--big-little/virtualisor/virt_context.c232
-rw-r--r--big-little/virtualisor/virt_handle.c589
-rw-r--r--big-little/virtualisor/virt_setup.c245
-rwxr-xr-xbootwrapper/Makefile138
l---------bootwrapper/acsr1
l---------bootwrapper/big-little1
-rwxr-xr-xbootwrapper/big-little-mp1.mxscript71
-rwxr-xr-xbootwrapper/big-little-mp4.mxscript89
-rwxr-xr-xbootwrapper/bl-mp1-fm-eac.mxscript76
-rwxr-xr-xbootwrapper/bl-mp4-fm-eac.mxscript94
-rw-r--r--bootwrapper/boot.S199
-rw-r--r--bootwrapper/boot.map.template65
-rw-r--r--bootwrapper/bootargs.S73
-rw-r--r--bootwrapper/bootwrapper.h68
-rw-r--r--bootwrapper/c_start.c275
-rw-r--r--bootwrapper/emubuild.s52
-rw-r--r--bootwrapper/filesystem.S29
-rw-r--r--bootwrapper/helpers.S1320
-rw-r--r--bootwrapper/helpers.h220
-rw-r--r--bootwrapper/kernel.S27
-rwxr-xr-xbootwrapper/makemap174
-rw-r--r--bootwrapper/payload/fsimg0
-rw-r--r--bootwrapper/payload/kernelbin0 -> 65856 bytes
-rw-r--r--bootwrapper/uart.c116
-rw-r--r--bootwrapper/vectors.S73
-rw-r--r--bootwrapper/vgic.h57
-rw-r--r--docs/01-Usage.txt90
-rw-r--r--docs/02-Code-layout.txt565
-rw-r--r--docs/03-Linux-kernel-build.txt58
-rw-r--r--docs/04-Cache-hit-rate-howto.txt208
-rw-r--r--docs/05-FAQ.txt18
-rw-r--r--docs/06-Optional-rootfs-build.txt125
93 files changed, 15705 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 120000
index 0000000..e8dfe57
--- /dev/null
+++ b/COPYING
@@ -0,0 +1 @@
+Release_Notes.txt \ No newline at end of file
diff --git a/README b/README
new file mode 120000
index 0000000..e8dfe57
--- /dev/null
+++ b/README
@@ -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 = &regs->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
new file mode 100644
index 0000000..4467aef
--- /dev/null
+++ b/bootwrapper/payload/kernel
Binary files differ
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).