staticvoid __init kvm_patch_ins_b(u32 *inst, int addr)
{ #ifdefined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC_BOOK3S) /* On relocatable kernels interrupts handlers and our code
can be in different regions, so we don't patch them */
if ((ulong)inst < (ulong)&__end_interrupts) return; #endif
staticvoid __init kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
{
u32 *p; int distance_start; int distance_end;
ulong next_inst;
p = kvm_alloc(kvm_emulate_mtmsrd_len * 4); if (!p) return;
/* Find out where we are and put everything there */
distance_start = (ulong)p - (ulong)inst;
next_inst = ((ulong)inst + 4);
distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsrd_branch_offs];
/* Make sure we only write valid b instructions */ if (distance_start > KVM_INST_B_MAX) {
kvm_patching_worked = false; return;
}
/* Modify the chunk to fit the invocation */
memcpy(p, kvm_emulate_mtmsrd, kvm_emulate_mtmsrd_len * 4);
p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK; switch (get_rt(rt)) { case 30:
kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
magic_var(scratch2), KVM_RT_30); break; case 31:
kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
magic_var(scratch1), KVM_RT_30); break; default:
p[kvm_emulate_mtmsrd_reg_offs] |= rt; break;
}
staticvoid __init kvm_patch_ins_mtmsr(u32 *inst, u32 rt)
{
u32 *p; int distance_start; int distance_end;
ulong next_inst;
p = kvm_alloc(kvm_emulate_mtmsr_len * 4); if (!p) return;
/* Find out where we are and put everything there */
distance_start = (ulong)p - (ulong)inst;
next_inst = ((ulong)inst + 4);
distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsr_branch_offs];
/* Make sure we only write valid b instructions */ if (distance_start > KVM_INST_B_MAX) {
kvm_patching_worked = false; return;
}
/* Modify the chunk to fit the invocation */
memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4);
p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK;
/* Make clobbered registers work too */ switch (get_rt(rt)) { case 30:
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
magic_var(scratch2), KVM_RT_30);
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
magic_var(scratch2), KVM_RT_30); break; case 31:
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
magic_var(scratch1), KVM_RT_30);
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
magic_var(scratch1), KVM_RT_30); break; default:
p[kvm_emulate_mtmsr_reg1_offs] |= rt;
p[kvm_emulate_mtmsr_reg2_offs] |= rt; break;
}
staticvoid __init kvm_patch_ins_wrtee(u32 *inst, u32 rt, int imm_one)
{
u32 *p; int distance_start; int distance_end;
ulong next_inst;
p = kvm_alloc(kvm_emulate_wrtee_len * 4); if (!p) return;
/* Find out where we are and put everything there */
distance_start = (ulong)p - (ulong)inst;
next_inst = ((ulong)inst + 4);
distance_end = next_inst - (ulong)&p[kvm_emulate_wrtee_branch_offs];
/* Make sure we only write valid b instructions */ if (distance_start > KVM_INST_B_MAX) {
kvm_patching_worked = false; return;
}
/* Modify the chunk to fit the invocation */
memcpy(p, kvm_emulate_wrtee, kvm_emulate_wrtee_len * 4);
p[kvm_emulate_wrtee_branch_offs] |= distance_end & KVM_INST_B_MASK;
if (imm_one) {
p[kvm_emulate_wrtee_reg_offs] =
KVM_INST_LI | __PPC_RT(R30) | MSR_EE;
} else { /* Make clobbered registers work too */ switch (get_rt(rt)) { case 30:
kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
magic_var(scratch2), KVM_RT_30); break; case 31:
kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
magic_var(scratch1), KVM_RT_30); break; default:
p[kvm_emulate_wrtee_reg_offs] |= rt; break;
}
}
staticvoid __init kvm_patch_ins_wrteei_0(u32 *inst)
{
u32 *p; int distance_start; int distance_end;
ulong next_inst;
p = kvm_alloc(kvm_emulate_wrteei_0_len * 4); if (!p) return;
/* Find out where we are and put everything there */
distance_start = (ulong)p - (ulong)inst;
next_inst = ((ulong)inst + 4);
distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_0_branch_offs];
/* Make sure we only write valid b instructions */ if (distance_start > KVM_INST_B_MAX) {
kvm_patching_worked = false; return;
}
staticvoid __init kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb)
{
u32 *p; int distance_start; int distance_end;
ulong next_inst;
p = kvm_alloc(kvm_emulate_mtsrin_len * 4); if (!p) return;
/* Find out where we are and put everything there */
distance_start = (ulong)p - (ulong)inst;
next_inst = ((ulong)inst + 4);
distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs];
/* Make sure we only write valid b instructions */ if (distance_start > KVM_INST_B_MAX) {
kvm_patching_worked = false; return;
}
/* Modify the chunk to fit the invocation */
memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4);
p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK;
p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10);
p[kvm_emulate_mtsrin_reg2_offs] |= rt;
p[kvm_emulate_mtsrin_orig_ins_offs] = *inst;
flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4);
/* Patch the invocation */
kvm_patch_ins_b(inst, distance_start);
}
switch (inst_no_rt) { /* Loads */ case KVM_INST_MFMSR:
kvm_patch_ins_ld(inst, magic_var(msr), inst_rt); break; case KVM_INST_MFSPR(SPRN_SPRG0):
kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt); break; case KVM_INST_MFSPR(SPRN_SPRG1):
kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt); break; case KVM_INST_MFSPR(SPRN_SPRG2):
kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt); break; case KVM_INST_MFSPR(SPRN_SPRG3):
kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt); break; case KVM_INST_MFSPR(SPRN_SRR0):
kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt); break; case KVM_INST_MFSPR(SPRN_SRR1):
kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt); break; #ifdef CONFIG_BOOKE case KVM_INST_MFSPR(SPRN_DEAR): #else case KVM_INST_MFSPR(SPRN_DAR): #endif
kvm_patch_ins_ld(inst, magic_var(dar), inst_rt); break; case KVM_INST_MFSPR(SPRN_DSISR):
kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt); break;
#ifdef CONFIG_PPC_E500 case KVM_INST_MFSPR(SPRN_MAS0): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(mas0), inst_rt); break; case KVM_INST_MFSPR(SPRN_MAS1): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(mas1), inst_rt); break; case KVM_INST_MFSPR(SPRN_MAS2): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_ld(inst, magic_var(mas2), inst_rt); break; case KVM_INST_MFSPR(SPRN_MAS3): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(mas7_3) + 4, inst_rt); break; case KVM_INST_MFSPR(SPRN_MAS4): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(mas4), inst_rt); break; case KVM_INST_MFSPR(SPRN_MAS6): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(mas6), inst_rt); break; case KVM_INST_MFSPR(SPRN_MAS7): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(mas7_3), inst_rt); break; #endif/* CONFIG_PPC_E500 */
case KVM_INST_MFSPR(SPRN_SPRG4): #ifdef CONFIG_BOOKE case KVM_INST_MFSPR(SPRN_SPRG4R): #endif if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_ld(inst, magic_var(sprg4), inst_rt); break; case KVM_INST_MFSPR(SPRN_SPRG5): #ifdef CONFIG_BOOKE case KVM_INST_MFSPR(SPRN_SPRG5R): #endif if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_ld(inst, magic_var(sprg5), inst_rt); break; case KVM_INST_MFSPR(SPRN_SPRG6): #ifdef CONFIG_BOOKE case KVM_INST_MFSPR(SPRN_SPRG6R): #endif if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_ld(inst, magic_var(sprg6), inst_rt); break; case KVM_INST_MFSPR(SPRN_SPRG7): #ifdef CONFIG_BOOKE case KVM_INST_MFSPR(SPRN_SPRG7R): #endif if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_ld(inst, magic_var(sprg7), inst_rt); break;
#ifdef CONFIG_BOOKE case KVM_INST_MFSPR(SPRN_ESR): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(esr), inst_rt); break; #endif
case KVM_INST_MFSPR(SPRN_PIR): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_lwz(inst, magic_var(pir), inst_rt); break;
/* Stores */ case KVM_INST_MTSPR(SPRN_SPRG0):
kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt); break; case KVM_INST_MTSPR(SPRN_SPRG1):
kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt); break; case KVM_INST_MTSPR(SPRN_SPRG2):
kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt); break; case KVM_INST_MTSPR(SPRN_SPRG3):
kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt); break; case KVM_INST_MTSPR(SPRN_SRR0):
kvm_patch_ins_std(inst, magic_var(srr0), inst_rt); break; case KVM_INST_MTSPR(SPRN_SRR1):
kvm_patch_ins_std(inst, magic_var(srr1), inst_rt); break; #ifdef CONFIG_BOOKE case KVM_INST_MTSPR(SPRN_DEAR): #else case KVM_INST_MTSPR(SPRN_DAR): #endif
kvm_patch_ins_std(inst, magic_var(dar), inst_rt); break; case KVM_INST_MTSPR(SPRN_DSISR):
kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt); break; #ifdef CONFIG_PPC_E500 case KVM_INST_MTSPR(SPRN_MAS0): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_stw(inst, magic_var(mas0), inst_rt); break; case KVM_INST_MTSPR(SPRN_MAS1): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_stw(inst, magic_var(mas1), inst_rt); break; case KVM_INST_MTSPR(SPRN_MAS2): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_std(inst, magic_var(mas2), inst_rt); break; case KVM_INST_MTSPR(SPRN_MAS3): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_stw(inst, magic_var(mas7_3) + 4, inst_rt); break; case KVM_INST_MTSPR(SPRN_MAS4): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_stw(inst, magic_var(mas4), inst_rt); break; case KVM_INST_MTSPR(SPRN_MAS6): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_stw(inst, magic_var(mas6), inst_rt); break; case KVM_INST_MTSPR(SPRN_MAS7): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_stw(inst, magic_var(mas7_3), inst_rt); break; #endif/* CONFIG_PPC_E500 */
case KVM_INST_MTSPR(SPRN_SPRG4): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_std(inst, magic_var(sprg4), inst_rt); break; case KVM_INST_MTSPR(SPRN_SPRG5): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_std(inst, magic_var(sprg5), inst_rt); break; case KVM_INST_MTSPR(SPRN_SPRG6): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_std(inst, magic_var(sprg6), inst_rt); break; case KVM_INST_MTSPR(SPRN_SPRG7): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_std(inst, magic_var(sprg7), inst_rt); break;
#ifdef CONFIG_BOOKE case KVM_INST_MTSPR(SPRN_ESR): if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
kvm_patch_ins_stw(inst, magic_var(esr), inst_rt); break; #endif
/* Nops */ case KVM_INST_TLBSYNC:
kvm_patch_ins_nop(inst); break;
/* Rewrites */ case KVM_INST_MTMSRD_L1:
kvm_patch_ins_mtmsrd(inst, inst_rt); break; case KVM_INST_MTMSR: case KVM_INST_MTMSRD_L0:
kvm_patch_ins_mtmsr(inst, inst_rt); break; #ifdef CONFIG_BOOKE case KVM_INST_WRTEE:
kvm_patch_ins_wrtee(inst, inst_rt, 0); break; #endif
}
/* Tell the host to map the magic page to -4096 on all CPUs */
on_each_cpu(kvm_map_magic_page, &features, 1);
/* Quick self-test to see if the mapping works */ if (fault_in_readable((constchar __user *)KVM_MAGIC_PAGE, sizeof(u32))) {
kvm_patching_worked = false; return;
}
/* Now loop through all code and find instructions */
start = (void*)_stext;
end = (void*)_etext;
/* * Being interrupted in the middle of patching would * be bad for SPRG4-7, which KVM can't keep in sync * with emulated accesses because reads don't trap.
*/
local_irq_disable();
for (p = start; p < end; p++) { /* Avoid patching the template code */ if (p >= kvm_template_start && p < kvm_template_end) {
p = kvm_template_end - 1; continue;
}
kvm_check_ins(p, features);
}
local_irq_enable();
printk(KERN_INFO "KVM: Live patching for a fast VM %s\n",
kvm_patching_worked ? "worked" : "failed");
}
staticint __init kvm_guest_init(void)
{ if (!kvm_para_available()) return 0;
if (!epapr_paravirt_enabled) return 0;
if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
kvm_use_magic_page();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.