summaryrefslogtreecommitdiff
path: root/big-little/virtualisor/virt_context.c
diff options
context:
space:
mode:
authorRobin Randhawa <robin.randhawa@arm.com>2011-10-12 16:07:02 +0100
committerRobin Randhawa <robin.randhawa@arm.com>2011-10-12 16:07:02 +0100
commit0656dea51f48c51a57e77187de4d5f66a6ba1337 (patch)
tree5b93e8967b0aa1cadd2724689346c6251cb47669 /big-little/virtualisor/virt_context.c
Initial commit of the virtualizer v2.0 release.
This will be the basis for the VSM.
Diffstat (limited to 'big-little/virtualisor/virt_context.c')
-rw-r--r--big-little/virtualisor/virt_context.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/big-little/virtualisor/virt_context.c b/big-little/virtualisor/virt_context.c
new file mode 100644
index 0000000..941f3dc
--- /dev/null
+++ b/big-little/virtualisor/virt_context.c
@@ -0,0 +1,226 @@
+/*
+ * $Copyright:
+ * ----------------------------------------------------------------
+ * This confidential and proprietary software may be used only as
+ * authorised by a licensing agreement from ARM Limited
+ * (C) COPYRIGHT 2008-2011 ARM Limited
+ * ALL RIGHTS RESERVED
+ * The entire notice above must be reproduced on all authorised
+ * copies and copies may only be made to the extent permitted
+ * by a licensing agreement from ARM Limited.
+ * ----------------------------------------------------------------
+ * File: virt_context.c
+ * ----------------------------------------------------------------
+ * $
+ */
+
+#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 = 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 = 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;
+}