arm64: KVM: Add patchable function selector
authorMarc Zyngier <marc.zyngier@arm.com>
Wed, 28 Oct 2015 08:45:37 +0000 (08:45 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 14 Dec 2015 11:30:40 +0000 (11:30 +0000)
KVM so far relies on code patching, and is likely to use it more
in the future. The main issue is that our alternative system works
at the instruction level, while we'd like to have alternatives at
the function level.

In order to cope with this, add the "hyp_alternate_select" macro that
outputs a brief sequence of code that in turn can be patched, allowing
an alternative function to be selected.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm64/kvm/hyp/hyp.h

index 080965348def1587da0edfb3c918c1d49a5df56a..73419a769112fbc01c822e063e57fd77f12c6341 100644 (file)
 #define hyp_kern_va(v) (typeof(v))((unsigned long)(v) - HYP_PAGE_OFFSET \
                                                      + PAGE_OFFSET)
 
+/**
+ * hyp_alternate_select - Generates patchable code sequences that are
+ * used to switch between two implementations of a function, depending
+ * on the availability of a feature.
+ *
+ * @fname: a symbol name that will be defined as a function returning a
+ * function pointer whose type will match @orig and @alt
+ * @orig: A pointer to the default function, as returned by @fname when
+ * @cond doesn't hold
+ * @alt: A pointer to the alternate function, as returned by @fname
+ * when @cond holds
+ * @cond: a CPU feature (as described in asm/cpufeature.h)
+ */
+#define hyp_alternate_select(fname, orig, alt, cond)                   \
+typeof(orig) * __hyp_text fname(void)                                  \
+{                                                                      \
+       typeof(alt) *val = orig;                                        \
+       asm volatile(ALTERNATIVE("nop           \n",                    \
+                                "mov   %0, %1  \n",                    \
+                                cond)                                  \
+                    : "+r" (val) : "r" (alt));                         \
+       return val;                                                     \
+}
+
 void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);