From: Julien Grall <julien.grall@linaro.org>
To: Ian Campbell <ijc@hellion.org.uk>
Cc: stefano.stabellini@eu.citrix.com, tim@xen.org,
Ian Campbell <ian.campbell@citrix.com>,
xen-devel@lists.xen.org
Subject: Re: [PATCH] xen: arm: handle traps of condtional instructions.
Date: Fri, 26 Jul 2013 12:10:01 +0100 [thread overview]
Message-ID: <51F25909.9000903@linaro.org> (raw)
In-Reply-To: <1374604662-15337-1-git-send-email-ijc@hellion.org.uk>
On 07/23/2013 07:37 PM, Ian Campbell wrote:
> From: Ian Campbell <ian.campbell@citrix.com>
s/condtional/conditional/ in the title.
> This means handling the HSR.ccvalid field as well as correctly processing the
> Thumb If-Then state block in the CPSR correctly which is rather tricky. KVM
> provided a useful reference for all this.
>
> I suspect we aren't actually hitting these paths very often since the sorts of
> traps we take will not often be conditional so my limited testing may not
> actually be excercising these paths very much.
exercising
The logic of the code sounds good to me. Actually, I'm able to hit this
path only once on the Arndale :). Few comments inline.
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> ---
> xen/arch/arm/traps.c | 160 ++++++++++++++++++++++++++++++++++------
> xen/include/asm-arm/processor.h | 9 +++
> 2 files changed, 145 insertions(+), 24 deletions(-)
>
> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> index bbd60aa..28e39c8 100644
> --- a/xen/arch/arm/traps.c
> +++ b/xen/arch/arm/traps.c
> @@ -832,6 +832,116 @@ void do_multicall_call(struct multicall_entry *multi)
> multi->args[4]);
> }
>
> +/*
> + * 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 */
> +};
> +
> +static int check_conditional_instr(struct cpu_user_regs *regs, union hsr hsr)
> +{
> + unsigned long cpsr, cpsr_cond;
> + int cond;
> +
> + /* Unconditional Exception classes */
> + if ( hsr.ec >= 0x10 )
> + return 1;
> +
> + /* Check for valid condition in hsr */
> + cond = hsr.cond.ccvalid ? hsr.cond.cc : -1;
> +
> + /* Unconditional instruction */
> + if ( cond == 0xe )
> + return 1;
> +
> + cpsr = regs->cpsr;
> +
> + /* If cc is not valid then we need to examine the IT state */
> + if ( cond < 0 )
> + {
> + unsigned long it;
> +
> + BUG_ON( !is_pv32_domain(current->domain) || !(cpsr&PSR_THUMB) );
> +
> + it = ((cpsr >> 8) & 0xfc) | ((cpsr >> 25) & 0x3);
Is it possible to do (10 - 2) as below? I took few minutes to understand
the right shift of 8.
> +
> + /* it == 0 => unconditional. */
> + if (it == 0)
missing spaces
> + return 1;
> +
> + /* 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))
missing spaces
> + return 0;
> +
> + return 1;
> +}
> +
> +static void advance_pc(struct cpu_user_regs *regs, union hsr hsr)
> +{
> + unsigned long itbits, cond, cpsr = regs->cpsr;
> +
> + /* PSR_IT_MASK bits can only be set for 32-bit processors in Thumb mode. */
> + BUG_ON( (!is_pv32_domain(current->domain)||!(cpsr&PSR_THUMB))
> + && (cpsr&PSR_IT_MASK) );
> +
> + if ( is_pv32_domain(current->domain) && (cpsr&PSR_IT_MASK) )
> + {
> + /* The ITSTATE[7:0] block is contained in CPSR[15:10],CPSR[26:25]
> + *
> + * ITSTATE[7:5] are the condition code
> + * ITSTATE[4:0] are the IT bits
> + *
> + * If the condition is non-zero then the IT state machine is
> + * advanced by shifting the IT bits left.
> + *
> + * See A2-51 and B1-1148 of DDI 0406C.b.
> + */
> + cond = (cpsr & 0xe000) >> 13;
> + itbits = (cpsr & 0x1c00) >> (10 - 2);
> + itbits |= (cpsr & (0x3 << 25)) >> 25;
> +
> + if ((itbits & 0x7) == 0)
missing spaces
> + itbits = cond = 0;
> + else
> + itbits = (itbits << 1) & 0x1f;
> +
> + cpsr &= ~PSR_IT_MASK;
> + cpsr |= cond << 13;
> + cpsr |= (itbits & 0x1c) << (10 - 2);
> + cpsr |= (itbits & 0x3) << 25;
> +
> + regs->cpsr = cpsr;
> + }
> +
> + regs->pc += hsr.len ? 4 : 2;
> +}
> +
> static void do_cp15_32(struct cpu_user_regs *regs,
> union hsr hsr)
> {
> @@ -839,14 +949,10 @@ static void do_cp15_32(struct cpu_user_regs *regs,
> uint32_t *r = (uint32_t*)select_user_reg(regs, cp32.reg);
> struct vcpu *v = current;
>
> - if ( !cp32.ccvalid ) {
> - dprintk(XENLOG_ERR, "cp_15(32): need to handle invalid condition codes\n");
> - domain_crash_synchronous();
> - }
> - if ( cp32.cc != 0xe ) {
> - dprintk(XENLOG_ERR, "cp_15(32): need to handle condition codes %x\n",
> - cp32.cc);
> - domain_crash_synchronous();
> + if ( !check_conditional_instr(regs, hsr) )
> + {
> + advance_pc(regs, hsr);
> + return;
> }
>
> switch ( hsr.bits & HSR_CP32_REGS_MASK )
> @@ -901,8 +1007,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
> cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc);
> panic("unhandled 32-bit CP15 access %#x\n", hsr.bits & HSR_CP32_REGS_MASK);
> }
> - regs->pc += cp32.len ? 4 : 2;
> -
> + advance_pc(regs, hsr);
> }
>
> static void do_cp15_64(struct cpu_user_regs *regs,
> @@ -910,14 +1015,10 @@ static void do_cp15_64(struct cpu_user_regs *regs,
> {
> struct hsr_cp64 cp64 = hsr.cp64;
>
> - if ( !cp64.ccvalid ) {
> - dprintk(XENLOG_ERR, "cp_15(64): need to handle invalid condition codes\n");
> - domain_crash_synchronous();
> - }
> - if ( cp64.cc != 0xe ) {
> - dprintk(XENLOG_ERR, "cp_15(64): need to handle condition codes %x\n",
> - cp64.cc);
> - domain_crash_synchronous();
> + if ( !check_conditional_instr(regs, hsr) )
> + {
> + advance_pc(regs, hsr);
> + return;
> }
>
> switch ( hsr.bits & HSR_CP64_REGS_MASK )
> @@ -936,8 +1037,7 @@ static void do_cp15_64(struct cpu_user_regs *regs,
> cp64.op1, cp64.reg1, cp64.reg2, cp64.crm, regs->pc);
> panic("unhandled 64-bit CP15 access %#x\n", hsr.bits & HSR_CP64_REGS_MASK);
> }
> - regs->pc += cp64.len ? 4 : 2;
> -
> + advance_pc(regs, hsr);
> }
>
> void dump_guest_s1_walk(struct domain *d, vaddr_t addr)
> @@ -997,12 +1097,19 @@ done:
> }
>
> static void do_trap_data_abort_guest(struct cpu_user_regs *regs,
> - struct hsr_dabt dabt)
> + union hsr hsr)
> {
> + struct hsr_dabt dabt = hsr.dabt;
> const char *msg;
> int rc, level = -1;
> mmio_info_t info;
>
> + if ( !check_conditional_instr(regs, hsr) )
> + {
> + advance_pc(regs, hsr);
> + return;
> + }
> +
> info.dabt = dabt;
> #ifdef CONFIG_ARM_32
> info.gva = READ_CP32(HDFAR);
> @@ -1019,7 +1126,7 @@ static void do_trap_data_abort_guest(struct cpu_user_regs *regs,
>
> if (handle_mmio(&info))
> {
> - regs->pc += dabt.len ? 4 : 2;
> + advance_pc(regs, hsr);
> return;
> }
>
> @@ -1056,6 +1163,11 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
>
> switch (hsr.ec) {
> case HSR_EC_WFI_WFE:
> + if ( !check_conditional_instr(regs, hsr) )
> + {
> + advance_pc(regs, hsr);
> + return;
> + }
> /* at the moment we only trap WFI */
> vcpu_block();
> /* The ARM spec declares that even if local irqs are masked in
> @@ -1066,7 +1178,7 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
> */
> if ( local_events_need_delivery_nomask() )
> vcpu_unblock(current);
> - regs->pc += hsr.len ? 4 : 2;
> + advance_pc(regs, hsr);
> break;
> case HSR_EC_CP15_32:
> if ( ! is_pv32_domain(current->domain) )
> @@ -1092,7 +1204,7 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
> do_trap_hypercall(regs, hsr.iss);
> break;
> case HSR_EC_DATA_ABORT_GUEST:
> - do_trap_data_abort_guest(regs, hsr.dabt);
> + do_trap_data_abort_guest(regs, hsr);
> break;
> default:
> bad_trap:
> diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
> index 5181e7b..fc5fb3a 100644
> --- a/xen/include/asm-arm/processor.h
> +++ b/xen/include/asm-arm/processor.h
> @@ -223,6 +223,15 @@ union hsr {
> unsigned long ec:6; /* Exception Class */
> };
>
> + /* Common to all conditional exception classes (0x0N, except 0x00). */
> + struct hsr_cond {
> + unsigned long iss:20; /* Instruction Specific Syndrome */
> + unsigned long cc:4; /* Condition Code */
> + unsigned long ccvalid:1;/* CC Valid */
> + unsigned long len:1; /* Instruction length */
> + unsigned long ec:6; /* Exception Class */
> + } cond;
> +
> /* reg, reg0, reg1 are 4 bits on AArch32, the fifth bit is sbzp. */
> struct hsr_cp32 {
> unsigned long read:1; /* Direction */
>
prev parent reply other threads:[~2013-07-26 11:10 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-23 18:37 [PATCH] xen: arm: handle traps of condtional instructions Ian Campbell
2013-07-26 11:10 ` Julien Grall [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51F25909.9000903@linaro.org \
--to=julien.grall@linaro.org \
--cc=ian.campbell@citrix.com \
--cc=ijc@hellion.org.uk \
--cc=stefano.stabellini@eu.citrix.com \
--cc=tim@xen.org \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).