diff options
Diffstat (limited to 'big-little/virtualisor/virt_context.c')
-rw-r--r-- | big-little/virtualisor/virt_context.c | 232 |
1 files changed, 232 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..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; +} |