aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/kvm.c
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2010-07-29 08:48:01 -0400
committerAvi Kivity <avi@redhat.com>2010-10-24 04:50:54 -0400
commit2d4f567103ff5a931e773f2e356b4eb303115deb (patch)
treeae80b4e8f5137a1ab6f03dbb93413b89800930c6 /arch/powerpc/kernel/kvm.c
parentd1290b15e7f139e24150cc6e6d8e904214359e8a (diff)
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/kvm.c')
-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 @@
65#define KVM_INST_TLBSYNC 0x7c00046c 65#define KVM_INST_TLBSYNC 0x7c00046c
66 66
67static bool kvm_patching_worked = true; 67static bool kvm_patching_worked = true;
68static char kvm_tmp[1024 * 1024];
69static int kvm_tmp_index;
68 70
69static inline void kvm_patch_ins(u32 *inst, u32 new_inst) 71static inline void kvm_patch_ins(u32 *inst, u32 new_inst)
70{ 72{
@@ -105,6 +107,23 @@ static void kvm_patch_ins_nop(u32 *inst)
105 kvm_patch_ins(inst, KVM_INST_NOP); 107 kvm_patch_ins(inst, KVM_INST_NOP);
106} 108}
107 109
110static u32 *kvm_alloc(int len)
111{
112 u32 *p;
113
114 if ((kvm_tmp_index + len) > ARRAY_SIZE(kvm_tmp)) {
115 printk(KERN_ERR "KVM: No more space (%d + %d)\n",
116 kvm_tmp_index, len);
117 kvm_patching_worked = false;
118 return NULL;
119 }
120
121 p = (void*)&kvm_tmp[kvm_tmp_index];
122 kvm_tmp_index += len;
123
124 return p;
125}
126
108static void kvm_map_magic_page(void *data) 127static void kvm_map_magic_page(void *data)
109{ 128{
110 kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE, 129 kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE,
@@ -270,17 +289,36 @@ static int kvm_para_setup(void)
270 return 0; 289 return 0;
271} 290}
272 291
292static __init void kvm_free_tmp(void)
293{
294 unsigned long start, end;
295
296 start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK;
297 end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
298
299 /* Free the tmp space we don't need */
300 for (; start < end; start += PAGE_SIZE) {
301 ClearPageReserved(virt_to_page(start));
302 init_page_count(virt_to_page(start));
303 free_page(start);
304 totalram_pages++;
305 }
306}
307
273static int __init kvm_guest_init(void) 308static int __init kvm_guest_init(void)
274{ 309{
275 if (!kvm_para_available()) 310 if (!kvm_para_available())
276 return 0; 311 goto free_tmp;
277 312
278 if (kvm_para_setup()) 313 if (kvm_para_setup())
279 return 0; 314 goto free_tmp;
280 315
281 if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE)) 316 if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
282 kvm_use_magic_page(); 317 kvm_use_magic_page();
283 318
319free_tmp:
320 kvm_free_tmp();
321
284 return 0; 322 return 0;
285} 323}
286 324