forked from grate-driver/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
KVM: arm/arm64: Move cc/it checks under hyp's Makefile to avoid instr…
…umentation KVM has helpers to handle the condition codes of trapped aarch32 instructions. These are marked __hyp_text and used from HYP, but they aren't built by the 'hyp' Makefile, which has all the runes to avoid ASAN and KCOV instrumentation. Move this code to a new hyp/aarch32.c to avoid a hyp-panic when starting an aarch32 guest on a host built with the ASAN/KCOV debug options. Fixes: 021234e ("KVM: arm64: Make kvm_condition_valid32() accessible from EL2") Fixes: 8cebe75 ("arm64: KVM: Make kvm_skip_instr32 available to HYP") Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
- Loading branch information
James Morse
authored and
Marc Zyngier
committed
May 24, 2019
1 parent
b7c50fa
commit 623e152
Showing
4 changed files
with
138 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Hyp portion of the (not much of an) Emulation layer for 32bit guests. | ||
* | ||
* Copyright (C) 2012,2013 - ARM Ltd | ||
* Author: Marc Zyngier <marc.zyngier@arm.com> | ||
* | ||
* based on arch/arm/kvm/emulate.c | ||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University | ||
* Author: Christoffer Dall <c.dall@virtualopensystems.com> | ||
*/ | ||
|
||
#include <linux/kvm_host.h> | ||
#include <asm/kvm_emulate.h> | ||
#include <asm/kvm_hyp.h> | ||
|
||
/* | ||
* stolen from arch/arm/kernel/opcodes.c | ||
* | ||
* condition code lookup table | ||
* index into the table is test code: EQ, NE, ... LT, GT, AL, NV | ||
* | ||
* bit position in short is condition code: NZCV | ||
*/ | ||
static const unsigned short cc_map[16] = { | ||
0xF0F0, /* EQ == Z set */ | ||
0x0F0F, /* NE */ | ||
0xCCCC, /* CS == C set */ | ||
0x3333, /* CC */ | ||
0xFF00, /* MI == N set */ | ||
0x00FF, /* PL */ | ||
0xAAAA, /* VS == V set */ | ||
0x5555, /* VC */ | ||
0x0C0C, /* HI == C set && Z clear */ | ||
0xF3F3, /* LS == C clear || Z set */ | ||
0xAA55, /* GE == (N==V) */ | ||
0x55AA, /* LT == (N!=V) */ | ||
0x0A05, /* GT == (!Z && (N==V)) */ | ||
0xF5FA, /* LE == (Z || (N!=V)) */ | ||
0xFFFF, /* AL always */ | ||
0 /* NV */ | ||
}; | ||
|
||
/* | ||
* Check if a trapped instruction should have been executed or not. | ||
*/ | ||
bool __hyp_text kvm_condition_valid32(const struct kvm_vcpu *vcpu) | ||
{ | ||
unsigned long cpsr; | ||
u32 cpsr_cond; | ||
int cond; | ||
|
||
/* Top two bits non-zero? Unconditional. */ | ||
if (kvm_vcpu_get_hsr(vcpu) >> 30) | ||
return true; | ||
|
||
/* Is condition field valid? */ | ||
cond = kvm_vcpu_get_condition(vcpu); | ||
if (cond == 0xE) | ||
return true; | ||
|
||
cpsr = *vcpu_cpsr(vcpu); | ||
|
||
if (cond < 0) { | ||
/* This can happen in Thumb mode: examine IT state. */ | ||
unsigned long it; | ||
|
||
it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3); | ||
|
||
/* it == 0 => unconditional. */ | ||
if (it == 0) | ||
return true; | ||
|
||
/* The cond for this insn works out as the top 4 bits. */ | ||
cond = (it >> 4); | ||
} | ||
|
||
cpsr_cond = cpsr >> 28; | ||
|
||
if (!((cc_map[cond] >> cpsr_cond) & 1)) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* adjust_itstate - adjust ITSTATE when emulating instructions in IT-block | ||
* @vcpu: The VCPU pointer | ||
* | ||
* When exceptions occur while instructions are executed in Thumb IF-THEN | ||
* blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have | ||
* to do this little bit of work manually. The fields map like this: | ||
* | ||
* IT[7:0] -> CPSR[26:25],CPSR[15:10] | ||
*/ | ||
static void __hyp_text kvm_adjust_itstate(struct kvm_vcpu *vcpu) | ||
{ | ||
unsigned long itbits, cond; | ||
unsigned long cpsr = *vcpu_cpsr(vcpu); | ||
bool is_arm = !(cpsr & PSR_AA32_T_BIT); | ||
|
||
if (is_arm || !(cpsr & PSR_AA32_IT_MASK)) | ||
return; | ||
|
||
cond = (cpsr & 0xe000) >> 13; | ||
itbits = (cpsr & 0x1c00) >> (10 - 2); | ||
itbits |= (cpsr & (0x3 << 25)) >> 25; | ||
|
||
/* Perform ITAdvance (see page A2-52 in ARM DDI 0406C) */ | ||
if ((itbits & 0x7) == 0) | ||
itbits = cond = 0; | ||
else | ||
itbits = (itbits << 1) & 0x1f; | ||
|
||
cpsr &= ~PSR_AA32_IT_MASK; | ||
cpsr |= cond << 13; | ||
cpsr |= (itbits & 0x1c) << (10 - 2); | ||
cpsr |= (itbits & 0x3) << 25; | ||
*vcpu_cpsr(vcpu) = cpsr; | ||
} | ||
|
||
/** | ||
* kvm_skip_instr - skip a trapped instruction and proceed to the next | ||
* @vcpu: The vcpu pointer | ||
*/ | ||
void __hyp_text kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr) | ||
{ | ||
bool is_thumb; | ||
|
||
is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_AA32_T_BIT); | ||
if (is_thumb && !is_wide_instr) | ||
*vcpu_pc(vcpu) += 2; | ||
else | ||
*vcpu_pc(vcpu) += 4; | ||
kvm_adjust_itstate(vcpu); | ||
} |