summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2010-07-29 16:48:01 +0400
committerAvi Kivity <avi@redhat.com>2010-10-24 12:50:54 +0400
commit2d4f567103ff5a931e773f2e356b4eb303115deb (patch)
treeae80b4e8f5137a1ab6f03dbb93413b89800930c6 /arch/powerpc/kernel
parentd1290b15e7f139e24150cc6e6d8e904214359e8a (diff)
downloadlinux-2d4f567103ff5a931e773f2e356b4eb303115deb.tar.xz
KVM: PPC: Introduce kvm_tmp framework
We will soon require more sophisticated methods to replace single instructions with multiple instructions. We do that by branching to a memory region where we write replacement code for the instruction to. This region needs to be within 32 MB of the patched instruction though, because that's the furthest we can jump with immediate branches. So we keep 1MB of free space around in bss. After we're done initing we can just tell the mm system that the unused pages are free, but until then we have enough space to fit all our code in. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/kvm.c42
1 files changed, 40 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index 3258922cc22c..926f93fd722d 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -65,6 +65,8 @@
#define KVM_INST_TLBSYNC 0x7c00046c
static bool kvm_patching_worked = true;
+static char kvm_tmp[1024 * 1024];
+static int kvm_tmp_index;
static inline void kvm_patch_ins(u32 *inst, u32 new_inst)
{
@@ -105,6 +107,23 @@ static void kvm_patch_ins_nop(u32 *inst)
kvm_patch_ins(inst, KVM_INST_NOP);
}
+static u32 *kvm_alloc(int len)
+{
+ u32 *p;
+
+ if ((kvm_tmp_index + len) > ARRAY_SIZE(kvm_tmp)) {
+ printk(KERN_ERR "KVM: No more space (%d + %d)\n",
+ kvm_tmp_index, len);
+ kvm_patching_worked = false;
+ return NULL;
+ }
+
+ p = (void*)&kvm_tmp[kvm_tmp_index];
+ kvm_tmp_index += len;
+
+ return p;
+}
+
static void kvm_map_magic_page(void *data)
{
kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE,
@@ -270,17 +289,36 @@ static int kvm_para_setup(void)
return 0;
}
+static __init void kvm_free_tmp(void)
+{
+ unsigned long start, end;
+
+ start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK;
+ end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
+
+ /* Free the tmp space we don't need */
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ init_page_count(virt_to_page(start));
+ free_page(start);
+ totalram_pages++;
+ }
+}
+
static int __init kvm_guest_init(void)
{
if (!kvm_para_available())
- return 0;
+ goto free_tmp;
if (kvm_para_setup())
- return 0;
+ goto free_tmp;
if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
kvm_use_magic_page();
+free_tmp:
+ kvm_free_tmp();
+
return 0;
}