xref: /openbmc/linux/arch/powerpc/kernel/kvm.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d94d71cbSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22a342ed5SAlexander Graf /*
32a342ed5SAlexander Graf  * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
4940b45ecSScott Wood  * Copyright 2010-2011 Freescale Semiconductor, Inc.
52a342ed5SAlexander Graf  *
62a342ed5SAlexander Graf  * Authors:
72a342ed5SAlexander Graf  *     Alexander Graf <agraf@suse.de>
82a342ed5SAlexander Graf  */
92a342ed5SAlexander Graf 
102a342ed5SAlexander Graf #include <linux/kvm_host.h>
112a342ed5SAlexander Graf #include <linux/init.h>
1266b15db6SPaul Gortmaker #include <linux/export.h>
13298a32b1SCatalin Marinas #include <linux/kmemleak.h>
142a342ed5SAlexander Graf #include <linux/kvm_para.h>
152a342ed5SAlexander Graf #include <linux/slab.h>
162a342ed5SAlexander Graf #include <linux/of.h>
179f9eae5cSMathieu Malaterre #include <linux/pagemap.h>
182a342ed5SAlexander Graf 
192a342ed5SAlexander Graf #include <asm/reg.h>
202a342ed5SAlexander Graf #include <asm/sections.h>
212a342ed5SAlexander Graf #include <asm/cacheflush.h>
222a342ed5SAlexander Graf #include <asm/disassemble.h>
23940b45ecSScott Wood #include <asm/ppc-opcode.h>
242e1ae9c0SLiu Yu-B13201 #include <asm/epapr_hcalls.h>
252a342ed5SAlexander Graf 
26d17051cbSAlexander Graf #define KVM_MAGIC_PAGE		(-4096L)
27d17051cbSAlexander Graf #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x)
28d17051cbSAlexander Graf 
29d1293c92SAlexander Graf #define KVM_INST_LWZ		0x80000000
30d1293c92SAlexander Graf #define KVM_INST_STW		0x90000000
31d1293c92SAlexander Graf #define KVM_INST_LD		0xe8000000
32d1293c92SAlexander Graf #define KVM_INST_STD		0xf8000000
33d1293c92SAlexander Graf #define KVM_INST_NOP		0x60000000
34d1293c92SAlexander Graf #define KVM_INST_B		0x48000000
35d1293c92SAlexander Graf #define KVM_INST_B_MASK		0x03ffffff
36d1293c92SAlexander Graf #define KVM_INST_B_MAX		0x01ffffff
37940b45ecSScott Wood #define KVM_INST_LI		0x38000000
38d1293c92SAlexander Graf 
3973a18109SAlexander Graf #define KVM_MASK_RT		0x03e00000
40512ba59eSAlexander Graf #define KVM_RT_30		0x03c00000
41cbe487faSAlexander Graf #define KVM_MASK_RB		0x0000f800
42d1293c92SAlexander Graf #define KVM_INST_MFMSR		0x7c0000a6
43d1293c92SAlexander Graf 
44b5904972SScott Wood #define SPR_FROM		0
45b5904972SScott Wood #define SPR_TO			0x100
46b5904972SScott Wood 
47b5904972SScott Wood #define KVM_INST_SPR(sprn, moveto) (0x7c0002a6 | \
48b5904972SScott Wood 				    (((sprn) & 0x1f) << 16) | \
49b5904972SScott Wood 				    (((sprn) & 0x3e0) << 6) | \
50b5904972SScott Wood 				    (moveto))
51b5904972SScott Wood 
52b5904972SScott Wood #define KVM_INST_MFSPR(sprn)	KVM_INST_SPR(sprn, SPR_FROM)
53b5904972SScott Wood #define KVM_INST_MTSPR(sprn)	KVM_INST_SPR(sprn, SPR_TO)
5473a18109SAlexander Graf 
55d1290b15SAlexander Graf #define KVM_INST_TLBSYNC	0x7c00046c
5678109277SAlexander Graf #define KVM_INST_MTMSRD_L0	0x7c000164
57819a63dcSAlexander Graf #define KVM_INST_MTMSRD_L1	0x7c010164
5878109277SAlexander Graf #define KVM_INST_MTMSR		0x7c000124
59d1290b15SAlexander Graf 
60940b45ecSScott Wood #define KVM_INST_WRTEE		0x7c000106
61644bfa01SAlexander Graf #define KVM_INST_WRTEEI_0	0x7c000146
62644bfa01SAlexander Graf #define KVM_INST_WRTEEI_1	0x7c008146
63644bfa01SAlexander Graf 
64cbe487faSAlexander Graf #define KVM_INST_MTSRIN		0x7c0001e4
65cbe487faSAlexander Graf 
6673a18109SAlexander Graf static bool kvm_patching_worked = true;
670cb0837fSMichael Ellerman extern char kvm_tmp[];
680cb0837fSMichael Ellerman extern char kvm_tmp_end[];
692d4f5671SAlexander Graf static int kvm_tmp_index;
7073a18109SAlexander Graf 
kvm_patch_ins(u32 * inst,u32 new_inst)71731dade1SMichael Ellerman static void __init kvm_patch_ins(u32 *inst, u32 new_inst)
7273a18109SAlexander Graf {
7373a18109SAlexander Graf 	*inst = new_inst;
7473a18109SAlexander Graf 	flush_icache_range((ulong)inst, (ulong)inst + 4);
7573a18109SAlexander Graf }
7673a18109SAlexander Graf 
kvm_patch_ins_ll(u32 * inst,long addr,u32 rt)77731dade1SMichael Ellerman static void __init kvm_patch_ins_ll(u32 *inst, long addr, u32 rt)
78512ba59eSAlexander Graf {
79512ba59eSAlexander Graf #ifdef CONFIG_64BIT
80512ba59eSAlexander Graf 	kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
81512ba59eSAlexander Graf #else
82512ba59eSAlexander Graf 	kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000fffc));
83512ba59eSAlexander Graf #endif
84512ba59eSAlexander Graf }
85512ba59eSAlexander Graf 
kvm_patch_ins_ld(u32 * inst,long addr,u32 rt)86731dade1SMichael Ellerman static void __init kvm_patch_ins_ld(u32 *inst, long addr, u32 rt)
87d1293c92SAlexander Graf {
88d1293c92SAlexander Graf #ifdef CONFIG_64BIT
89d1293c92SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
90d1293c92SAlexander Graf #else
91d1293c92SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_LWZ | rt | ((addr + 4) & 0x0000fffc));
92d1293c92SAlexander Graf #endif
93d1293c92SAlexander Graf }
94d1293c92SAlexander Graf 
kvm_patch_ins_lwz(u32 * inst,long addr,u32 rt)95731dade1SMichael Ellerman static void __init kvm_patch_ins_lwz(u32 *inst, long addr, u32 rt)
96d1293c92SAlexander Graf {
97d1293c92SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000ffff));
98d1293c92SAlexander Graf }
99d1293c92SAlexander Graf 
kvm_patch_ins_std(u32 * inst,long addr,u32 rt)100731dade1SMichael Ellerman static void __init kvm_patch_ins_std(u32 *inst, long addr, u32 rt)
101d1293c92SAlexander Graf {
102d1293c92SAlexander Graf #ifdef CONFIG_64BIT
103d1293c92SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_STD | rt | (addr & 0x0000fffc));
104d1293c92SAlexander Graf #else
105d1293c92SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_STW | rt | ((addr + 4) & 0x0000fffc));
106d1293c92SAlexander Graf #endif
107d1293c92SAlexander Graf }
108d1293c92SAlexander Graf 
kvm_patch_ins_stw(u32 * inst,long addr,u32 rt)109731dade1SMichael Ellerman static void __init kvm_patch_ins_stw(u32 *inst, long addr, u32 rt)
110d1293c92SAlexander Graf {
111d1293c92SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_STW | rt | (addr & 0x0000fffc));
112d1293c92SAlexander Graf }
113d1293c92SAlexander Graf 
kvm_patch_ins_nop(u32 * inst)114731dade1SMichael Ellerman static void __init kvm_patch_ins_nop(u32 *inst)
115d1290b15SAlexander Graf {
116d1290b15SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_NOP);
117d1290b15SAlexander Graf }
118d1290b15SAlexander Graf 
kvm_patch_ins_b(u32 * inst,int addr)119731dade1SMichael Ellerman static void __init kvm_patch_ins_b(u32 *inst, int addr)
12071ee8e34SAlexander Graf {
121a36be100SScott Wood #if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC_BOOK3S)
12271ee8e34SAlexander Graf 	/* On relocatable kernels interrupts handlers and our code
12371ee8e34SAlexander Graf 	   can be in different regions, so we don't patch them */
12471ee8e34SAlexander Graf 
12571ee8e34SAlexander Graf 	if ((ulong)inst < (ulong)&__end_interrupts)
12671ee8e34SAlexander Graf 		return;
12771ee8e34SAlexander Graf #endif
12871ee8e34SAlexander Graf 
12971ee8e34SAlexander Graf 	kvm_patch_ins(inst, KVM_INST_B | (addr & KVM_INST_B_MASK));
13071ee8e34SAlexander Graf }
13171ee8e34SAlexander Graf 
kvm_alloc(int len)132731dade1SMichael Ellerman static u32 * __init kvm_alloc(int len)
1332d4f5671SAlexander Graf {
1342d4f5671SAlexander Graf 	u32 *p;
1352d4f5671SAlexander Graf 
1360cb0837fSMichael Ellerman 	if ((kvm_tmp_index + len) > (kvm_tmp_end - kvm_tmp)) {
1372d4f5671SAlexander Graf 		printk(KERN_ERR "KVM: No more space (%d + %d)\n",
1382d4f5671SAlexander Graf 				kvm_tmp_index, len);
1392d4f5671SAlexander Graf 		kvm_patching_worked = false;
1402d4f5671SAlexander Graf 		return NULL;
1412d4f5671SAlexander Graf 	}
1422d4f5671SAlexander Graf 
1432d4f5671SAlexander Graf 	p = (void*)&kvm_tmp[kvm_tmp_index];
1442d4f5671SAlexander Graf 	kvm_tmp_index += len;
1452d4f5671SAlexander Graf 
1462d4f5671SAlexander Graf 	return p;
1472d4f5671SAlexander Graf }
1482d4f5671SAlexander Graf 
149819a63dcSAlexander Graf extern u32 kvm_emulate_mtmsrd_branch_offs;
150819a63dcSAlexander Graf extern u32 kvm_emulate_mtmsrd_reg_offs;
151df08bd10SAlexander Graf extern u32 kvm_emulate_mtmsrd_orig_ins_offs;
152819a63dcSAlexander Graf extern u32 kvm_emulate_mtmsrd_len;
153819a63dcSAlexander Graf extern u32 kvm_emulate_mtmsrd[];
154819a63dcSAlexander Graf 
kvm_patch_ins_mtmsrd(u32 * inst,u32 rt)155731dade1SMichael Ellerman static void __init kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
156819a63dcSAlexander Graf {
157819a63dcSAlexander Graf 	u32 *p;
158819a63dcSAlexander Graf 	int distance_start;
159819a63dcSAlexander Graf 	int distance_end;
160819a63dcSAlexander Graf 	ulong next_inst;
161819a63dcSAlexander Graf 
162819a63dcSAlexander Graf 	p = kvm_alloc(kvm_emulate_mtmsrd_len * 4);
163819a63dcSAlexander Graf 	if (!p)
164819a63dcSAlexander Graf 		return;
165819a63dcSAlexander Graf 
166819a63dcSAlexander Graf 	/* Find out where we are and put everything there */
167819a63dcSAlexander Graf 	distance_start = (ulong)p - (ulong)inst;
168819a63dcSAlexander Graf 	next_inst = ((ulong)inst + 4);
169819a63dcSAlexander Graf 	distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsrd_branch_offs];
170819a63dcSAlexander Graf 
171819a63dcSAlexander Graf 	/* Make sure we only write valid b instructions */
172819a63dcSAlexander Graf 	if (distance_start > KVM_INST_B_MAX) {
173819a63dcSAlexander Graf 		kvm_patching_worked = false;
174819a63dcSAlexander Graf 		return;
175819a63dcSAlexander Graf 	}
176819a63dcSAlexander Graf 
177819a63dcSAlexander Graf 	/* Modify the chunk to fit the invocation */
178819a63dcSAlexander Graf 	memcpy(p, kvm_emulate_mtmsrd, kvm_emulate_mtmsrd_len * 4);
179819a63dcSAlexander Graf 	p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK;
180df08bd10SAlexander Graf 	switch (get_rt(rt)) {
181df08bd10SAlexander Graf 	case 30:
182df08bd10SAlexander Graf 		kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
183df08bd10SAlexander Graf 				 magic_var(scratch2), KVM_RT_30);
184df08bd10SAlexander Graf 		break;
185df08bd10SAlexander Graf 	case 31:
186df08bd10SAlexander Graf 		kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
187df08bd10SAlexander Graf 				 magic_var(scratch1), KVM_RT_30);
188df08bd10SAlexander Graf 		break;
189df08bd10SAlexander Graf 	default:
190819a63dcSAlexander Graf 		p[kvm_emulate_mtmsrd_reg_offs] |= rt;
191df08bd10SAlexander Graf 		break;
192df08bd10SAlexander Graf 	}
193df08bd10SAlexander Graf 
194df08bd10SAlexander Graf 	p[kvm_emulate_mtmsrd_orig_ins_offs] = *inst;
195819a63dcSAlexander Graf 	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsrd_len * 4);
196819a63dcSAlexander Graf 
197819a63dcSAlexander Graf 	/* Patch the invocation */
198819a63dcSAlexander Graf 	kvm_patch_ins_b(inst, distance_start);
199819a63dcSAlexander Graf }
200819a63dcSAlexander Graf 
20178109277SAlexander Graf extern u32 kvm_emulate_mtmsr_branch_offs;
20278109277SAlexander Graf extern u32 kvm_emulate_mtmsr_reg1_offs;
20378109277SAlexander Graf extern u32 kvm_emulate_mtmsr_reg2_offs;
20478109277SAlexander Graf extern u32 kvm_emulate_mtmsr_orig_ins_offs;
20578109277SAlexander Graf extern u32 kvm_emulate_mtmsr_len;
20678109277SAlexander Graf extern u32 kvm_emulate_mtmsr[];
20778109277SAlexander Graf 
kvm_patch_ins_mtmsr(u32 * inst,u32 rt)208731dade1SMichael Ellerman static void __init kvm_patch_ins_mtmsr(u32 *inst, u32 rt)
20978109277SAlexander Graf {
21078109277SAlexander Graf 	u32 *p;
21178109277SAlexander Graf 	int distance_start;
21278109277SAlexander Graf 	int distance_end;
21378109277SAlexander Graf 	ulong next_inst;
21478109277SAlexander Graf 
21578109277SAlexander Graf 	p = kvm_alloc(kvm_emulate_mtmsr_len * 4);
21678109277SAlexander Graf 	if (!p)
21778109277SAlexander Graf 		return;
21878109277SAlexander Graf 
21978109277SAlexander Graf 	/* Find out where we are and put everything there */
22078109277SAlexander Graf 	distance_start = (ulong)p - (ulong)inst;
22178109277SAlexander Graf 	next_inst = ((ulong)inst + 4);
22278109277SAlexander Graf 	distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsr_branch_offs];
22378109277SAlexander Graf 
22478109277SAlexander Graf 	/* Make sure we only write valid b instructions */
22578109277SAlexander Graf 	if (distance_start > KVM_INST_B_MAX) {
22678109277SAlexander Graf 		kvm_patching_worked = false;
22778109277SAlexander Graf 		return;
22878109277SAlexander Graf 	}
22978109277SAlexander Graf 
23078109277SAlexander Graf 	/* Modify the chunk to fit the invocation */
23178109277SAlexander Graf 	memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4);
23278109277SAlexander Graf 	p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK;
233512ba59eSAlexander Graf 
234512ba59eSAlexander Graf 	/* Make clobbered registers work too */
235512ba59eSAlexander Graf 	switch (get_rt(rt)) {
236512ba59eSAlexander Graf 	case 30:
237512ba59eSAlexander Graf 		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
238512ba59eSAlexander Graf 				 magic_var(scratch2), KVM_RT_30);
239512ba59eSAlexander Graf 		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
240512ba59eSAlexander Graf 				 magic_var(scratch2), KVM_RT_30);
241512ba59eSAlexander Graf 		break;
242512ba59eSAlexander Graf 	case 31:
243512ba59eSAlexander Graf 		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
244512ba59eSAlexander Graf 				 magic_var(scratch1), KVM_RT_30);
245512ba59eSAlexander Graf 		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
246512ba59eSAlexander Graf 				 magic_var(scratch1), KVM_RT_30);
247512ba59eSAlexander Graf 		break;
248512ba59eSAlexander Graf 	default:
24978109277SAlexander Graf 		p[kvm_emulate_mtmsr_reg1_offs] |= rt;
25078109277SAlexander Graf 		p[kvm_emulate_mtmsr_reg2_offs] |= rt;
251512ba59eSAlexander Graf 		break;
252512ba59eSAlexander Graf 	}
253512ba59eSAlexander Graf 
25478109277SAlexander Graf 	p[kvm_emulate_mtmsr_orig_ins_offs] = *inst;
25578109277SAlexander Graf 	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsr_len * 4);
25678109277SAlexander Graf 
25778109277SAlexander Graf 	/* Patch the invocation */
25878109277SAlexander Graf 	kvm_patch_ins_b(inst, distance_start);
25978109277SAlexander Graf }
26078109277SAlexander Graf 
261644bfa01SAlexander Graf #ifdef CONFIG_BOOKE
262644bfa01SAlexander Graf 
263940b45ecSScott Wood extern u32 kvm_emulate_wrtee_branch_offs;
264940b45ecSScott Wood extern u32 kvm_emulate_wrtee_reg_offs;
265940b45ecSScott Wood extern u32 kvm_emulate_wrtee_orig_ins_offs;
266940b45ecSScott Wood extern u32 kvm_emulate_wrtee_len;
267940b45ecSScott Wood extern u32 kvm_emulate_wrtee[];
268644bfa01SAlexander Graf 
kvm_patch_ins_wrtee(u32 * inst,u32 rt,int imm_one)269731dade1SMichael Ellerman static void __init kvm_patch_ins_wrtee(u32 *inst, u32 rt, int imm_one)
270644bfa01SAlexander Graf {
271644bfa01SAlexander Graf 	u32 *p;
272644bfa01SAlexander Graf 	int distance_start;
273644bfa01SAlexander Graf 	int distance_end;
274644bfa01SAlexander Graf 	ulong next_inst;
275644bfa01SAlexander Graf 
276940b45ecSScott Wood 	p = kvm_alloc(kvm_emulate_wrtee_len * 4);
277644bfa01SAlexander Graf 	if (!p)
278644bfa01SAlexander Graf 		return;
279644bfa01SAlexander Graf 
280644bfa01SAlexander Graf 	/* Find out where we are and put everything there */
281644bfa01SAlexander Graf 	distance_start = (ulong)p - (ulong)inst;
282644bfa01SAlexander Graf 	next_inst = ((ulong)inst + 4);
283940b45ecSScott Wood 	distance_end = next_inst - (ulong)&p[kvm_emulate_wrtee_branch_offs];
284644bfa01SAlexander Graf 
285644bfa01SAlexander Graf 	/* Make sure we only write valid b instructions */
286644bfa01SAlexander Graf 	if (distance_start > KVM_INST_B_MAX) {
287644bfa01SAlexander Graf 		kvm_patching_worked = false;
288644bfa01SAlexander Graf 		return;
289644bfa01SAlexander Graf 	}
290644bfa01SAlexander Graf 
291644bfa01SAlexander Graf 	/* Modify the chunk to fit the invocation */
292940b45ecSScott Wood 	memcpy(p, kvm_emulate_wrtee, kvm_emulate_wrtee_len * 4);
293940b45ecSScott Wood 	p[kvm_emulate_wrtee_branch_offs] |= distance_end & KVM_INST_B_MASK;
294940b45ecSScott Wood 
295940b45ecSScott Wood 	if (imm_one) {
296940b45ecSScott Wood 		p[kvm_emulate_wrtee_reg_offs] =
297c75df6f9SMichael Neuling 			KVM_INST_LI | __PPC_RT(R30) | MSR_EE;
298940b45ecSScott Wood 	} else {
299940b45ecSScott Wood 		/* Make clobbered registers work too */
300940b45ecSScott Wood 		switch (get_rt(rt)) {
301940b45ecSScott Wood 		case 30:
302940b45ecSScott Wood 			kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
303940b45ecSScott Wood 					 magic_var(scratch2), KVM_RT_30);
304940b45ecSScott Wood 			break;
305940b45ecSScott Wood 		case 31:
306940b45ecSScott Wood 			kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
307940b45ecSScott Wood 					 magic_var(scratch1), KVM_RT_30);
308940b45ecSScott Wood 			break;
309940b45ecSScott Wood 		default:
310940b45ecSScott Wood 			p[kvm_emulate_wrtee_reg_offs] |= rt;
311940b45ecSScott Wood 			break;
312940b45ecSScott Wood 		}
313940b45ecSScott Wood 	}
314940b45ecSScott Wood 
315940b45ecSScott Wood 	p[kvm_emulate_wrtee_orig_ins_offs] = *inst;
316940b45ecSScott Wood 	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrtee_len * 4);
317940b45ecSScott Wood 
318940b45ecSScott Wood 	/* Patch the invocation */
319940b45ecSScott Wood 	kvm_patch_ins_b(inst, distance_start);
320940b45ecSScott Wood }
321940b45ecSScott Wood 
322940b45ecSScott Wood extern u32 kvm_emulate_wrteei_0_branch_offs;
323940b45ecSScott Wood extern u32 kvm_emulate_wrteei_0_len;
324940b45ecSScott Wood extern u32 kvm_emulate_wrteei_0[];
325940b45ecSScott Wood 
kvm_patch_ins_wrteei_0(u32 * inst)326731dade1SMichael Ellerman static void __init kvm_patch_ins_wrteei_0(u32 *inst)
327940b45ecSScott Wood {
328940b45ecSScott Wood 	u32 *p;
329940b45ecSScott Wood 	int distance_start;
330940b45ecSScott Wood 	int distance_end;
331940b45ecSScott Wood 	ulong next_inst;
332940b45ecSScott Wood 
333940b45ecSScott Wood 	p = kvm_alloc(kvm_emulate_wrteei_0_len * 4);
334940b45ecSScott Wood 	if (!p)
335940b45ecSScott Wood 		return;
336940b45ecSScott Wood 
337940b45ecSScott Wood 	/* Find out where we are and put everything there */
338940b45ecSScott Wood 	distance_start = (ulong)p - (ulong)inst;
339940b45ecSScott Wood 	next_inst = ((ulong)inst + 4);
340940b45ecSScott Wood 	distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_0_branch_offs];
341940b45ecSScott Wood 
342940b45ecSScott Wood 	/* Make sure we only write valid b instructions */
343940b45ecSScott Wood 	if (distance_start > KVM_INST_B_MAX) {
344940b45ecSScott Wood 		kvm_patching_worked = false;
345940b45ecSScott Wood 		return;
346940b45ecSScott Wood 	}
347940b45ecSScott Wood 
348940b45ecSScott Wood 	memcpy(p, kvm_emulate_wrteei_0, kvm_emulate_wrteei_0_len * 4);
349940b45ecSScott Wood 	p[kvm_emulate_wrteei_0_branch_offs] |= distance_end & KVM_INST_B_MASK;
350940b45ecSScott Wood 	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_0_len * 4);
351644bfa01SAlexander Graf 
352644bfa01SAlexander Graf 	/* Patch the invocation */
353644bfa01SAlexander Graf 	kvm_patch_ins_b(inst, distance_start);
354644bfa01SAlexander Graf }
355644bfa01SAlexander Graf 
356644bfa01SAlexander Graf #endif
357644bfa01SAlexander Graf 
358cbe487faSAlexander Graf #ifdef CONFIG_PPC_BOOK3S_32
359cbe487faSAlexander Graf 
360cbe487faSAlexander Graf extern u32 kvm_emulate_mtsrin_branch_offs;
361cbe487faSAlexander Graf extern u32 kvm_emulate_mtsrin_reg1_offs;
362cbe487faSAlexander Graf extern u32 kvm_emulate_mtsrin_reg2_offs;
363cbe487faSAlexander Graf extern u32 kvm_emulate_mtsrin_orig_ins_offs;
364cbe487faSAlexander Graf extern u32 kvm_emulate_mtsrin_len;
365cbe487faSAlexander Graf extern u32 kvm_emulate_mtsrin[];
366cbe487faSAlexander Graf 
kvm_patch_ins_mtsrin(u32 * inst,u32 rt,u32 rb)367731dade1SMichael Ellerman static void __init kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb)
368cbe487faSAlexander Graf {
369cbe487faSAlexander Graf 	u32 *p;
370cbe487faSAlexander Graf 	int distance_start;
371cbe487faSAlexander Graf 	int distance_end;
372cbe487faSAlexander Graf 	ulong next_inst;
373cbe487faSAlexander Graf 
374cbe487faSAlexander Graf 	p = kvm_alloc(kvm_emulate_mtsrin_len * 4);
375cbe487faSAlexander Graf 	if (!p)
376cbe487faSAlexander Graf 		return;
377cbe487faSAlexander Graf 
378cbe487faSAlexander Graf 	/* Find out where we are and put everything there */
379cbe487faSAlexander Graf 	distance_start = (ulong)p - (ulong)inst;
380cbe487faSAlexander Graf 	next_inst = ((ulong)inst + 4);
381cbe487faSAlexander Graf 	distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs];
382cbe487faSAlexander Graf 
383cbe487faSAlexander Graf 	/* Make sure we only write valid b instructions */
384cbe487faSAlexander Graf 	if (distance_start > KVM_INST_B_MAX) {
385cbe487faSAlexander Graf 		kvm_patching_worked = false;
386cbe487faSAlexander Graf 		return;
387cbe487faSAlexander Graf 	}
388cbe487faSAlexander Graf 
389cbe487faSAlexander Graf 	/* Modify the chunk to fit the invocation */
390cbe487faSAlexander Graf 	memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4);
391cbe487faSAlexander Graf 	p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK;
392cbe487faSAlexander Graf 	p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10);
393cbe487faSAlexander Graf 	p[kvm_emulate_mtsrin_reg2_offs] |= rt;
394cbe487faSAlexander Graf 	p[kvm_emulate_mtsrin_orig_ins_offs] = *inst;
395cbe487faSAlexander Graf 	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4);
396cbe487faSAlexander Graf 
397cbe487faSAlexander Graf 	/* Patch the invocation */
398cbe487faSAlexander Graf 	kvm_patch_ins_b(inst, distance_start);
399cbe487faSAlexander Graf }
400cbe487faSAlexander Graf 
401cbe487faSAlexander Graf #endif
402cbe487faSAlexander Graf 
kvm_map_magic_page(void * data)403731dade1SMichael Ellerman static void __init kvm_map_magic_page(void *data)
40473a18109SAlexander Graf {
4057508e16cSAlexander Graf 	u32 *features = data;
4067508e16cSAlexander Graf 
4071820a8d2SBharat Bhushan 	ulong in[8] = {0};
4087508e16cSAlexander Graf 	ulong out[8];
4097508e16cSAlexander Graf 
4107508e16cSAlexander Graf 	in[0] = KVM_MAGIC_PAGE;
4115c165aecSAlexander Graf 	in[1] = KVM_MAGIC_PAGE | MAGIC_PAGE_FLAG_NOT_MAPPED_NX;
4127508e16cSAlexander Graf 
4131820a8d2SBharat Bhushan 	epapr_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE));
4147508e16cSAlexander Graf 
4157508e16cSAlexander Graf 	*features = out[0];
41673a18109SAlexander Graf }
41773a18109SAlexander Graf 
kvm_check_ins(u32 * inst,u32 features)418731dade1SMichael Ellerman static void __init kvm_check_ins(u32 *inst, u32 features)
41973a18109SAlexander Graf {
42073a18109SAlexander Graf 	u32 _inst = *inst;
42173a18109SAlexander Graf 	u32 inst_no_rt = _inst & ~KVM_MASK_RT;
42273a18109SAlexander Graf 	u32 inst_rt = _inst & KVM_MASK_RT;
42373a18109SAlexander Graf 
42473a18109SAlexander Graf 	switch (inst_no_rt) {
425d1293c92SAlexander Graf 	/* Loads */
426d1293c92SAlexander Graf 	case KVM_INST_MFMSR:
427d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(msr), inst_rt);
428d1293c92SAlexander Graf 		break;
429b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG0):
430d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt);
431d1293c92SAlexander Graf 		break;
432b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG1):
433d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt);
434d1293c92SAlexander Graf 		break;
435b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG2):
436d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt);
437d1293c92SAlexander Graf 		break;
438b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG3):
439d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt);
440d1293c92SAlexander Graf 		break;
441b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SRR0):
442d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt);
443d1293c92SAlexander Graf 		break;
444b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SRR1):
445d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt);
446d1293c92SAlexander Graf 		break;
447b5904972SScott Wood #ifdef CONFIG_BOOKE
448b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_DEAR):
449b5904972SScott Wood #else
450b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_DAR):
451b5904972SScott Wood #endif
452d1293c92SAlexander Graf 		kvm_patch_ins_ld(inst, magic_var(dar), inst_rt);
453d1293c92SAlexander Graf 		break;
454b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_DSISR):
455d1293c92SAlexander Graf 		kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt);
456d1293c92SAlexander Graf 		break;
457d1293c92SAlexander Graf 
458*aa5f59dfSChristophe Leroy #ifdef CONFIG_PPC_E500
459b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_MAS0):
460b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
461b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(mas0), inst_rt);
462b5904972SScott Wood 		break;
463b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_MAS1):
464b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
465b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(mas1), inst_rt);
466b5904972SScott Wood 		break;
467b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_MAS2):
468b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
469b5904972SScott Wood 			kvm_patch_ins_ld(inst, magic_var(mas2), inst_rt);
470b5904972SScott Wood 		break;
471b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_MAS3):
472b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
473b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(mas7_3) + 4, inst_rt);
474b5904972SScott Wood 		break;
475b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_MAS4):
476b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
477b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(mas4), inst_rt);
478b5904972SScott Wood 		break;
479b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_MAS6):
480b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
481b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(mas6), inst_rt);
482b5904972SScott Wood 		break;
483b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_MAS7):
484b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
485b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(mas7_3), inst_rt);
486b5904972SScott Wood 		break;
487*aa5f59dfSChristophe Leroy #endif /* CONFIG_PPC_E500 */
488b5904972SScott Wood 
489b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG4):
490b5904972SScott Wood #ifdef CONFIG_BOOKE
491b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG4R):
492b5904972SScott Wood #endif
493b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
494b5904972SScott Wood 			kvm_patch_ins_ld(inst, magic_var(sprg4), inst_rt);
495b5904972SScott Wood 		break;
496b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG5):
497b5904972SScott Wood #ifdef CONFIG_BOOKE
498b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG5R):
499b5904972SScott Wood #endif
500b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
501b5904972SScott Wood 			kvm_patch_ins_ld(inst, magic_var(sprg5), inst_rt);
502b5904972SScott Wood 		break;
503b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG6):
504b5904972SScott Wood #ifdef CONFIG_BOOKE
505b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG6R):
506b5904972SScott Wood #endif
507b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
508b5904972SScott Wood 			kvm_patch_ins_ld(inst, magic_var(sprg6), inst_rt);
509b5904972SScott Wood 		break;
510b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG7):
511b5904972SScott Wood #ifdef CONFIG_BOOKE
512b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_SPRG7R):
513b5904972SScott Wood #endif
514b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
515b5904972SScott Wood 			kvm_patch_ins_ld(inst, magic_var(sprg7), inst_rt);
516b5904972SScott Wood 		break;
517b5904972SScott Wood 
518b5904972SScott Wood #ifdef CONFIG_BOOKE
519b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_ESR):
520b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
521b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(esr), inst_rt);
522b5904972SScott Wood 		break;
523b5904972SScott Wood #endif
524b5904972SScott Wood 
525b5904972SScott Wood 	case KVM_INST_MFSPR(SPRN_PIR):
526b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
527b5904972SScott Wood 			kvm_patch_ins_lwz(inst, magic_var(pir), inst_rt);
528b5904972SScott Wood 		break;
529b5904972SScott Wood 
530b5904972SScott Wood 
531d1293c92SAlexander Graf 	/* Stores */
532b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG0):
533d1293c92SAlexander Graf 		kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt);
534d1293c92SAlexander Graf 		break;
535b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG1):
536d1293c92SAlexander Graf 		kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt);
537d1293c92SAlexander Graf 		break;
538b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG2):
539d1293c92SAlexander Graf 		kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt);
540d1293c92SAlexander Graf 		break;
541b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG3):
542d1293c92SAlexander Graf 		kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt);
543d1293c92SAlexander Graf 		break;
544b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SRR0):
545d1293c92SAlexander Graf 		kvm_patch_ins_std(inst, magic_var(srr0), inst_rt);
546d1293c92SAlexander Graf 		break;
547b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SRR1):
548d1293c92SAlexander Graf 		kvm_patch_ins_std(inst, magic_var(srr1), inst_rt);
549d1293c92SAlexander Graf 		break;
550b5904972SScott Wood #ifdef CONFIG_BOOKE
551b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_DEAR):
552b5904972SScott Wood #else
553b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_DAR):
554b5904972SScott Wood #endif
555d1293c92SAlexander Graf 		kvm_patch_ins_std(inst, magic_var(dar), inst_rt);
556d1293c92SAlexander Graf 		break;
557b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_DSISR):
558d1293c92SAlexander Graf 		kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt);
559d1293c92SAlexander Graf 		break;
560*aa5f59dfSChristophe Leroy #ifdef CONFIG_PPC_E500
561b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_MAS0):
562b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
563b5904972SScott Wood 			kvm_patch_ins_stw(inst, magic_var(mas0), inst_rt);
564b5904972SScott Wood 		break;
565b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_MAS1):
566b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
567b5904972SScott Wood 			kvm_patch_ins_stw(inst, magic_var(mas1), inst_rt);
568b5904972SScott Wood 		break;
569b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_MAS2):
570b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
571b5904972SScott Wood 			kvm_patch_ins_std(inst, magic_var(mas2), inst_rt);
572b5904972SScott Wood 		break;
573b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_MAS3):
574b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
575b5904972SScott Wood 			kvm_patch_ins_stw(inst, magic_var(mas7_3) + 4, inst_rt);
576b5904972SScott Wood 		break;
577b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_MAS4):
578b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
579b5904972SScott Wood 			kvm_patch_ins_stw(inst, magic_var(mas4), inst_rt);
580b5904972SScott Wood 		break;
581b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_MAS6):
582b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
583b5904972SScott Wood 			kvm_patch_ins_stw(inst, magic_var(mas6), inst_rt);
584b5904972SScott Wood 		break;
585b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_MAS7):
586b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
587b5904972SScott Wood 			kvm_patch_ins_stw(inst, magic_var(mas7_3), inst_rt);
588b5904972SScott Wood 		break;
589*aa5f59dfSChristophe Leroy #endif /* CONFIG_PPC_E500 */
590b5904972SScott Wood 
591b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG4):
592b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
593b5904972SScott Wood 			kvm_patch_ins_std(inst, magic_var(sprg4), inst_rt);
594b5904972SScott Wood 		break;
595b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG5):
596b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
597b5904972SScott Wood 			kvm_patch_ins_std(inst, magic_var(sprg5), inst_rt);
598b5904972SScott Wood 		break;
599b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG6):
600b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
601b5904972SScott Wood 			kvm_patch_ins_std(inst, magic_var(sprg6), inst_rt);
602b5904972SScott Wood 		break;
603b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_SPRG7):
604b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
605b5904972SScott Wood 			kvm_patch_ins_std(inst, magic_var(sprg7), inst_rt);
606b5904972SScott Wood 		break;
607b5904972SScott Wood 
608b5904972SScott Wood #ifdef CONFIG_BOOKE
609b5904972SScott Wood 	case KVM_INST_MTSPR(SPRN_ESR):
610b5904972SScott Wood 		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
611b5904972SScott Wood 			kvm_patch_ins_stw(inst, magic_var(esr), inst_rt);
612b5904972SScott Wood 		break;
613b5904972SScott Wood #endif
614d1290b15SAlexander Graf 
615d1290b15SAlexander Graf 	/* Nops */
616d1290b15SAlexander Graf 	case KVM_INST_TLBSYNC:
617d1290b15SAlexander Graf 		kvm_patch_ins_nop(inst);
618d1290b15SAlexander Graf 		break;
619819a63dcSAlexander Graf 
620819a63dcSAlexander Graf 	/* Rewrites */
621819a63dcSAlexander Graf 	case KVM_INST_MTMSRD_L1:
622819a63dcSAlexander Graf 		kvm_patch_ins_mtmsrd(inst, inst_rt);
623819a63dcSAlexander Graf 		break;
62478109277SAlexander Graf 	case KVM_INST_MTMSR:
62578109277SAlexander Graf 	case KVM_INST_MTMSRD_L0:
62678109277SAlexander Graf 		kvm_patch_ins_mtmsr(inst, inst_rt);
62778109277SAlexander Graf 		break;
628940b45ecSScott Wood #ifdef CONFIG_BOOKE
629940b45ecSScott Wood 	case KVM_INST_WRTEE:
630940b45ecSScott Wood 		kvm_patch_ins_wrtee(inst, inst_rt, 0);
631940b45ecSScott Wood 		break;
632940b45ecSScott Wood #endif
63373a18109SAlexander Graf 	}
63473a18109SAlexander Graf 
635cbe487faSAlexander Graf 	switch (inst_no_rt & ~KVM_MASK_RB) {
636cbe487faSAlexander Graf #ifdef CONFIG_PPC_BOOK3S_32
637cbe487faSAlexander Graf 	case KVM_INST_MTSRIN:
638cbe487faSAlexander Graf 		if (features & KVM_MAGIC_FEAT_SR) {
639cbe487faSAlexander Graf 			u32 inst_rb = _inst & KVM_MASK_RB;
640cbe487faSAlexander Graf 			kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb);
641cbe487faSAlexander Graf 		}
642cbe487faSAlexander Graf 		break;
643cbe487faSAlexander Graf #endif
644cbe487faSAlexander Graf 	}
645cbe487faSAlexander Graf 
64673a18109SAlexander Graf 	switch (_inst) {
647644bfa01SAlexander Graf #ifdef CONFIG_BOOKE
648644bfa01SAlexander Graf 	case KVM_INST_WRTEEI_0:
649940b45ecSScott Wood 		kvm_patch_ins_wrteei_0(inst);
650940b45ecSScott Wood 		break;
651940b45ecSScott Wood 
652644bfa01SAlexander Graf 	case KVM_INST_WRTEEI_1:
653940b45ecSScott Wood 		kvm_patch_ins_wrtee(inst, 0, 1);
654644bfa01SAlexander Graf 		break;
655644bfa01SAlexander Graf #endif
65673a18109SAlexander Graf 	}
65773a18109SAlexander Graf }
65873a18109SAlexander Graf 
659befdc0a6SLiu Yu-B13201 extern u32 kvm_template_start[];
660befdc0a6SLiu Yu-B13201 extern u32 kvm_template_end[];
661befdc0a6SLiu Yu-B13201 
kvm_use_magic_page(void)662731dade1SMichael Ellerman static void __init kvm_use_magic_page(void)
66373a18109SAlexander Graf {
66473a18109SAlexander Graf 	u32 *p;
66573a18109SAlexander Graf 	u32 *start, *end;
6667508e16cSAlexander Graf 	u32 features;
66773a18109SAlexander Graf 
66873a18109SAlexander Graf 	/* Tell the host to map the magic page to -4096 on all CPUs */
6697508e16cSAlexander Graf 	on_each_cpu(kvm_map_magic_page, &features, 1);
67073a18109SAlexander Graf 
67173a18109SAlexander Graf 	/* Quick self-test to see if the mapping works */
672bb523b40SAndreas Gruenbacher 	if (fault_in_readable((const char __user *)KVM_MAGIC_PAGE,
673bb523b40SAndreas Gruenbacher 			      sizeof(u32))) {
67473a18109SAlexander Graf 		kvm_patching_worked = false;
67573a18109SAlexander Graf 		return;
67673a18109SAlexander Graf 	}
67773a18109SAlexander Graf 
67873a18109SAlexander Graf 	/* Now loop through all code and find instructions */
67973a18109SAlexander Graf 	start = (void*)_stext;
68073a18109SAlexander Graf 	end = (void*)_etext;
68173a18109SAlexander Graf 
682b5904972SScott Wood 	/*
683b5904972SScott Wood 	 * Being interrupted in the middle of patching would
684b5904972SScott Wood 	 * be bad for SPRG4-7, which KVM can't keep in sync
685b5904972SScott Wood 	 * with emulated accesses because reads don't trap.
686b5904972SScott Wood 	 */
687b5904972SScott Wood 	local_irq_disable();
688b5904972SScott Wood 
689befdc0a6SLiu Yu-B13201 	for (p = start; p < end; p++) {
690befdc0a6SLiu Yu-B13201 		/* Avoid patching the template code */
691befdc0a6SLiu Yu-B13201 		if (p >= kvm_template_start && p < kvm_template_end) {
692befdc0a6SLiu Yu-B13201 			p = kvm_template_end - 1;
693befdc0a6SLiu Yu-B13201 			continue;
694befdc0a6SLiu Yu-B13201 		}
6957508e16cSAlexander Graf 		kvm_check_ins(p, features);
696befdc0a6SLiu Yu-B13201 	}
69773a18109SAlexander Graf 
698b5904972SScott Wood 	local_irq_enable();
699b5904972SScott Wood 
70073a18109SAlexander Graf 	printk(KERN_INFO "KVM: Live patching for a fast VM %s\n",
70173a18109SAlexander Graf 			 kvm_patching_worked ? "worked" : "failed");
70273a18109SAlexander Graf }
70373a18109SAlexander Graf 
kvm_guest_init(void)70473a18109SAlexander Graf static int __init kvm_guest_init(void)
70573a18109SAlexander Graf {
70673a18109SAlexander Graf 	if (!kvm_para_available())
7070cb0837fSMichael Ellerman 		return 0;
70873a18109SAlexander Graf 
7092e1ae9c0SLiu Yu-B13201 	if (!epapr_paravirt_enabled)
7100cb0837fSMichael Ellerman 		return 0;
71173a18109SAlexander Graf 
71273a18109SAlexander Graf 	if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
71373a18109SAlexander Graf 		kvm_use_magic_page();
71473a18109SAlexander Graf 
715591bd8e7SAlexander Graf #ifdef CONFIG_PPC_BOOK3S_64
716ad087376SAlexander Graf 	/* Enable napping */
717ad087376SAlexander Graf 	powersave_nap = 1;
718591bd8e7SAlexander Graf #endif
719ad087376SAlexander Graf 
72073a18109SAlexander Graf 	return 0;
72173a18109SAlexander Graf }
72273a18109SAlexander Graf 
72373a18109SAlexander Graf postcore_initcall(kvm_guest_init);
724