summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIsaku Yamahata <yamahata@valinux.co.jp>2008-10-17 11:18:00 +0900
committerTony Luck <tony.luck@intel.com>2008-10-17 10:03:24 -0700
commit4b83ce4367943aa3eb960df56759f45d70722a4c (patch)
tree5016104e05b1293c3f06eb7f039dd8cf978575bb
parentb5a26e4db818d4647a019d5c462f6778b8213112 (diff)
downloadlinux-4b83ce4367943aa3eb960df56759f45d70722a4c.tar.bz2
ia64/pv_ops/xen: define xen pv_cpu_ops.
define xen pv_cpu_ops which implementes xen paravirtualized privileged instructions. Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r--arch/ia64/xen/xen_pv_ops.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/arch/ia64/xen/xen_pv_ops.c b/arch/ia64/xen/xen_pv_ops.c
index fc9d599b62ae..c236f04ffad5 100644
--- a/arch/ia64/xen/xen_pv_ops.c
+++ b/arch/ia64/xen/xen_pv_ops.c
@@ -163,6 +163,119 @@ static const struct pv_init_ops xen_init_ops __initdata = {
};
/***************************************************************************
+ * pv_cpu_ops
+ * intrinsics hooks.
+ */
+
+static void xen_setreg(int regnum, unsigned long val)
+{
+ switch (regnum) {
+ case _IA64_REG_AR_KR0 ... _IA64_REG_AR_KR7:
+ xen_set_kr(regnum - _IA64_REG_AR_KR0, val);
+ break;
+#ifdef CONFIG_IA32_SUPPORT
+ case _IA64_REG_AR_EFLAG:
+ xen_set_eflag(val);
+ break;
+#endif
+ case _IA64_REG_CR_TPR:
+ xen_set_tpr(val);
+ break;
+ case _IA64_REG_CR_ITM:
+ xen_set_itm(val);
+ break;
+ case _IA64_REG_CR_EOI:
+ xen_eoi(val);
+ break;
+ default:
+ ia64_native_setreg_func(regnum, val);
+ break;
+ }
+}
+
+static unsigned long xen_getreg(int regnum)
+{
+ unsigned long res;
+
+ switch (regnum) {
+ case _IA64_REG_PSR:
+ res = xen_get_psr();
+ break;
+#ifdef CONFIG_IA32_SUPPORT
+ case _IA64_REG_AR_EFLAG:
+ res = xen_get_eflag();
+ break;
+#endif
+ case _IA64_REG_CR_IVR:
+ res = xen_get_ivr();
+ break;
+ case _IA64_REG_CR_TPR:
+ res = xen_get_tpr();
+ break;
+ default:
+ res = ia64_native_getreg_func(regnum);
+ break;
+ }
+ return res;
+}
+
+/* turning on interrupts is a bit more complicated.. write to the
+ * memory-mapped virtual psr.i bit first (to avoid race condition),
+ * then if any interrupts were pending, we have to execute a hyperprivop
+ * to ensure the pending interrupt gets delivered; else we're done! */
+static void
+xen_ssm_i(void)
+{
+ int old = xen_get_virtual_psr_i();
+ xen_set_virtual_psr_i(1);
+ barrier();
+ if (!old && xen_get_virtual_pend())
+ xen_hyper_ssm_i();
+}
+
+/* turning off interrupts can be paravirtualized simply by writing
+ * to a memory-mapped virtual psr.i bit (implemented as a 16-bit bool) */
+static void
+xen_rsm_i(void)
+{
+ xen_set_virtual_psr_i(0);
+ barrier();
+}
+
+static unsigned long
+xen_get_psr_i(void)
+{
+ return xen_get_virtual_psr_i() ? IA64_PSR_I : 0;
+}
+
+static void
+xen_intrin_local_irq_restore(unsigned long mask)
+{
+ if (mask & IA64_PSR_I)
+ xen_ssm_i();
+ else
+ xen_rsm_i();
+}
+
+static const struct pv_cpu_ops xen_cpu_ops __initdata = {
+ .fc = xen_fc,
+ .thash = xen_thash,
+ .get_cpuid = xen_get_cpuid,
+ .get_pmd = xen_get_pmd,
+ .getreg = xen_getreg,
+ .setreg = xen_setreg,
+ .ptcga = xen_ptcga,
+ .get_rr = xen_get_rr,
+ .set_rr = xen_set_rr,
+ .set_rr0_to_rr4 = xen_set_rr0_to_rr4,
+ .ssm_i = xen_ssm_i,
+ .rsm_i = xen_rsm_i,
+ .get_psr_i = xen_get_psr_i,
+ .intrin_local_irq_restore
+ = xen_intrin_local_irq_restore,
+};
+
+/***************************************************************************
* pv_ops initialization
*/
@@ -172,4 +285,5 @@ xen_setup_pv_ops(void)
xen_info_init();
pv_info = xen_info;
pv_init_ops = xen_init_ops;
+ pv_cpu_ops = xen_cpu_ops;
}