From 0656dea51f48c51a57e77187de4d5f66a6ba1337 Mon Sep 17 00:00:00 2001 From: Robin Randhawa Date: Wed, 12 Oct 2011 16:07:02 +0100 Subject: Initial commit of the virtualizer v2.0 release. This will be the basis for the VSM. --- big-little/virtualisor/virt_context.c | 226 ++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 big-little/virtualisor/virt_context.c (limited to 'big-little/virtualisor/virt_context.c') 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; +} -- cgit v1.2.3