Re: [Qemu-devel] [PATCH RESEND v15 08/10] target-arm: kvm64: inject synchronous External Abort

2018-11-26 Thread gengdongjiu
> >>
> >> Hi Peter,
> >>   Thanks for the review and comments.
> >>
> >> >
> >> > On 8 November 2018 at 10:29, Dongjiu Geng  wrote:
> >> > > +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t
> >> > > +fieldoffset)
> >> >
> >> > What is this about? Nothing else in QEMU needs to mess with the
> >> > cpustate synchronization. My first assumption is that you should not 
> >> > need to do so either.
> >>
> >> We should change the guest CP15 ESR_EL1's value, the only method is
> >> to change the cpu->cpreg_values[] in QEMU, then QEMU call 
> >> write_list_to_kvmstate() to set the cpu->cpreg_values[] to KVM which
> include the specified ESR_EL1 value, KVM do world switch, and then set the 
> specified ESR_EL1's value to guest kernel.
> >
> > Ah, I see. This is a bug in our current handling of the register
> > state, where we implicitly assume that nothing in QEMU will ever want
> > to change any system register values. This assumption is now false --
> > kvm_arm_handle_debug() broke it -- so we need to fix the code that
> > does kvm_arch_put_registers(). There is a comment in the kvm32.c
> > version of that function about this. (The kvm64.c version has the same
> > assumption but doesn't comment on it.)
> >
> > We should (ideally) fix this bug in the code that does register
> > syncing, without requiring places in QEMU that update system registers
> > to have to manually indicate which registers they have changed. I'll
> > have a think about how best to do this.
> >
> >> About the detailed explanation, as shown in [2].
> >>
> >> kvm_arm_handle_debug() does not need to do this because QEMU does not need 
> >> to change CP15 registers, such as ESR_EL1.
> >
> > kvm_arm_handle_debug does change ESR_EL1: it is injecting an exception
> > and so should set the exception register. This happens when it calls
> > the do_interrupt() hook, because arm_cpu_do_interrupt_aarch64() writes
> > to env->cp15.esr_el[new_el].
> >
> > I'm not entirely sure why this is working today, in fact.
> > Alex, did you test whether our debug-exception-injection reports the
> > correct ESR_EL1 to the guest ?
> 
> 
> I did not - I was mostly focusing in the host-debugging-the-guest test case. 
> I'll get a test rig up and check.

Thanks, please test it in the KVM mode, not in the TCG mode. Waiting for your 
test result.

> 
> --
> Alex Bennée


Re: [Qemu-devel] [PATCH RESEND v15 08/10] target-arm: kvm64: inject synchronous External Abort

2018-11-26 Thread Alex Bennée


Peter Maydell  writes:

> On Wed, 21 Nov 2018 at 14:34, gengdongjiu  wrote:
>>
>> Hi Peter,
>>   Thanks for the review and comments.
>>
>> >
>> > On 8 November 2018 at 10:29, Dongjiu Geng  wrote:
>> > > +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset)
>> >
>> > What is this about? Nothing else in QEMU needs to mess with the cpustate 
>> > synchronization. My first assumption is that you should not
>> > need to do so either.
>>
>> We should change the guest CP15 ESR_EL1's value, the only method is to 
>> change the cpu->cpreg_values[] in QEMU, then QEMU call 
>> write_list_to_kvmstate()
>> to set the cpu->cpreg_values[] to KVM which include the specified ESR_EL1 
>> value, KVM do world switch, and then set the specified ESR_EL1's value to 
>> guest kernel.
>
> Ah, I see. This is a bug in our current handling of the register
> state, where we implicitly assume that nothing in QEMU will ever
> want to change any system register values. This assumption is
> now false -- kvm_arm_handle_debug() broke it -- so we need to
> fix the code that does kvm_arch_put_registers(). There is a comment
> in the kvm32.c version of that function about this. (The kvm64.c
> version has the same assumption but doesn't comment on it.)
>
> We should (ideally) fix this bug in the code that does register
> syncing, without requiring places in QEMU that update system
> registers to have to manually indicate which registers they have
> changed. I'll have a think about how best to do this.
>
>> About the detailed explanation, as shown in [2].
>>
>> kvm_arm_handle_debug() does not need to do this because QEMU does not need 
>> to change CP15 registers, such as ESR_EL1.
>
> kvm_arm_handle_debug does change ESR_EL1: it is injecting an exception
> and so should set the exception register. This happens when it
> calls the do_interrupt() hook, because arm_cpu_do_interrupt_aarch64()
> writes to env->cp15.esr_el[new_el].
>
> I'm not entirely sure why this is working today, in fact.
> Alex, did you test whether our debug-exception-injection
> reports the correct ESR_EL1 to the guest ?


I did not - I was mostly focusing in the host-debugging-the-guest test
case. I'll get a test rig up and check.

--
Alex Bennée



Re: [Qemu-devel] [PATCH RESEND v15 08/10] target-arm: kvm64: inject synchronous External Abort

2018-11-23 Thread gengdongjiu
Hi Peter,

On 2018/11/24 2:45, Peter Maydell wrote:
> On Wed, 21 Nov 2018 at 14:34, gengdongjiu  wrote:
>>
>> Hi Peter,
>>   Thanks for the review and comments.
>>
>>>
>>> On 8 November 2018 at 10:29, Dongjiu Geng  wrote:
 +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset)
>>>
>>> What is this about? Nothing else in QEMU needs to mess with the cpustate 
>>> synchronization. My first assumption is that you should not
>>> need to do so either.
>>
>> We should change the guest CP15 ESR_EL1's value, the only method is to 
>> change the cpu->cpreg_values[] in QEMU, then QEMU call 
>> write_list_to_kvmstate()
>> to set the cpu->cpreg_values[] to KVM which include the specified ESR_EL1 
>> value, KVM do world switch, and then set the specified ESR_EL1's value to 
>> guest kernel.
> 
> Ah, I see. This is a bug in our current handling of the register
> state, where we implicitly assume that nothing in QEMU will ever
> want to change any system register values. This assumption is
> now false -- kvm_arm_handle_debug() broke it -- so we need to
> fix the code that does kvm_arch_put_registers(). There is a comment
> in the kvm32.c version of that function about this. (The kvm64.c
> version has the same assumption but doesn't comment on it.)
> 
> We should (ideally) fix this bug in the code that does register
> syncing, without requiring places in QEMU that update system
> registers to have to manually indicate which registers they have
> changed. I'll have a think about how best to do this.

Ok, it is great that you will think about it, waiting for your wonderful 
solution

> 
>> About the detailed explanation, as shown in [2].
>>
>> kvm_arm_handle_debug() does not need to do this because QEMU does not need 
>> to change CP15 registers, such as ESR_EL1.
> 
> kvm_arm_handle_debug does change ESR_EL1: it is injecting an exception
> and so should set the exception register. This happens when it
> calls the do_interrupt() hook, because arm_cpu_do_interrupt_aarch64()
> writes to env->cp15.esr_el[new_el].

Yes, I see it, but the env->cp15.esr_el[new_el] shouldn't be successfully set 
to KVM when call kvm_arch_put_registers()

> 
> I'm not entirely sure why this is working today, in fact.
> Alex, did you test whether our debug-exception-injection
> reports the correct ESR_EL1 to the guest ?

Alex?

> 
 +/* Inject synchronous external abort */ static void
 +kvm_inject_arm_sea(CPUState *c) {
 +ARMCPU *cpu = ARM_CPU(c);
 +CPUARMState *env = >env;
 +CPUClass *cc = CPU_GET_CLASS(c);
 +uint32_t esr;
 +int ret;
 +
 +/* This exception is synchronous data abort */
 +c->exception_index = EXCP_DATA_ABORT;
 +/* Inject the exception to guest EL1 */
 +env->exception.target_el = 1;
>>>
>>> These comments don't tell us anything that the code does not.
>>
>>  Thanks, do you mean I need to remove it or add more detailed comments to it?
> 
> As a rule of thumb, comments should provide information to
> the reader which they wouldn't get if they only had the code.
> Comments often answer the "why do we do this" question, or
> provide an overall summary of what the code is going to do,
> or refer to an external source (a datasheet, an algorithm)
> that is necessary to understand the code. It's better to
> avoid comments that say "what the code is doing" at a line-by-line
> level, because the code itself already answers the "what"
> question at that level of detail.

sure, got it, thanks for the explanation and guidelines.

> 
> thanks
> -- PMM
> 
> .
> 




Re: [Qemu-devel] [PATCH RESEND v15 08/10] target-arm: kvm64: inject synchronous External Abort

2018-11-23 Thread Peter Maydell
On Wed, 21 Nov 2018 at 14:34, gengdongjiu  wrote:
>
> Hi Peter,
>   Thanks for the review and comments.
>
> >
> > On 8 November 2018 at 10:29, Dongjiu Geng  wrote:
> > > +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset)
> >
> > What is this about? Nothing else in QEMU needs to mess with the cpustate 
> > synchronization. My first assumption is that you should not
> > need to do so either.
>
> We should change the guest CP15 ESR_EL1's value, the only method is to change 
> the cpu->cpreg_values[] in QEMU, then QEMU call write_list_to_kvmstate()
> to set the cpu->cpreg_values[] to KVM which include the specified ESR_EL1 
> value, KVM do world switch, and then set the specified ESR_EL1's value to 
> guest kernel.

Ah, I see. This is a bug in our current handling of the register
state, where we implicitly assume that nothing in QEMU will ever
want to change any system register values. This assumption is
now false -- kvm_arm_handle_debug() broke it -- so we need to
fix the code that does kvm_arch_put_registers(). There is a comment
in the kvm32.c version of that function about this. (The kvm64.c
version has the same assumption but doesn't comment on it.)

We should (ideally) fix this bug in the code that does register
syncing, without requiring places in QEMU that update system
registers to have to manually indicate which registers they have
changed. I'll have a think about how best to do this.

> About the detailed explanation, as shown in [2].
>
> kvm_arm_handle_debug() does not need to do this because QEMU does not need to 
> change CP15 registers, such as ESR_EL1.

kvm_arm_handle_debug does change ESR_EL1: it is injecting an exception
and so should set the exception register. This happens when it
calls the do_interrupt() hook, because arm_cpu_do_interrupt_aarch64()
writes to env->cp15.esr_el[new_el].

I'm not entirely sure why this is working today, in fact.
Alex, did you test whether our debug-exception-injection
reports the correct ESR_EL1 to the guest ?

> > > +/* Inject synchronous external abort */ static void
> > > +kvm_inject_arm_sea(CPUState *c) {
> > > +ARMCPU *cpu = ARM_CPU(c);
> > > +CPUARMState *env = >env;
> > > +CPUClass *cc = CPU_GET_CLASS(c);
> > > +uint32_t esr;
> > > +int ret;
> > > +
> > > +/* This exception is synchronous data abort */
> > > +c->exception_index = EXCP_DATA_ABORT;
> > > +/* Inject the exception to guest EL1 */
> > > +env->exception.target_el = 1;
> >
> > These comments don't tell us anything that the code does not.
>
>  Thanks, do you mean I need to remove it or add more detailed comments to it?

As a rule of thumb, comments should provide information to
the reader which they wouldn't get if they only had the code.
Comments often answer the "why do we do this" question, or
provide an overall summary of what the code is going to do,
or refer to an external source (a datasheet, an algorithm)
that is necessary to understand the code. It's better to
avoid comments that say "what the code is doing" at a line-by-line
level, because the code itself already answers the "what"
question at that level of detail.

thanks
-- PMM



Re: [Qemu-devel] [PATCH RESEND v15 08/10] target-arm: kvm64: inject synchronous External Abort

2018-11-21 Thread gengdongjiu
Hi Peter,
  Thanks for the review and comments.

> 
> On 8 November 2018 at 10:29, Dongjiu Geng  wrote:
> > Add synchronous external abort injection logic, setup exception type
> > and syndrome value. When switch to guest, guest will jump to the
> > synchronous external abort vector table entry.
> >
> > The ESR_ELx.DFSC is set to synchronous external abort(0x10), and
> > ESR_ELx.FnV is set to not valid(0x1), which will tell guest that FAR
> > is not valid and holds an UNKNOWN value.
> > These value will be set to KVM register structures through
> > KVM_SET_ONE_REG IOCTL.
> >
> > Signed-off-by: Dongjiu Geng 
> > ---
> > Marc is against that KVM inject the synchronous external abort(SEA) in
> > [1], so user space how to inject it. The test result that injection
> > SEA to guest by Qemu is shown in [2].
> >
> > [1]: https://lkml.org/lkml/2017/3/2/110
> > [2]:
> > Taking exception 4 [Data Abort]
> > ...from EL0 to EL1
> > ...with ESR 0x24/0x92000410
> > ...with FAR 0x0
> > ...with ELR 0x40cf04
> > ...to EL1 PC 0xffc84c00 PSTATE 0x3c5 after kvm_inject_arm_sea
> > Unhandled fault: synchronous external abort (0x92000410) at
> > 0x007fa234c12c
> > CPU: 0 PID: 536 Comm: devmem Not tainted 4.1.0+ #20 Hardware name:
> > linux,dummy-virt (DT)
> > task: ffc019ab2b00 ti: ffc008134000 task.ti: ffc008134000
> > PC is at 0x40cf04 LR is at 0x40cdec pc : [<0040cf04>] lr :
> > [<0040cdec>] pstate: 6000 sp : 007ff7b24130
> > x29: 007ff7b24260 x28: 
> > x27: 00ad x26: 0049c000
> > x25: 0048904b x24: 0049c000
> > x23: 4060 x22: 007ff7b243a0
> > x21: 0002 x20: 
> > x19: 0020 x18: 
> > x17: 0049c6d0 x16: 007fa22c85c0
> > x15: 5798 x14: 007fa2205f1c
> > x13: 007fa241ccb0 x12: 0137
> > x11:  x10: 
> > x9 :  x8 : 00de
> > x7 :  x6 : 2000
> > x5 : 4060 x4 : 0003
> > x3 : 0001 x2 : 
> > x1 :  x0 : 007fa2418000
> > ---
> >  target/arm/cpu.h   |  2 ++
> >  target/arm/helper.c| 23 +++
> >  target/arm/internals.h |  5 +++--
> >  target/arm/kvm64.c | 39 +++
> >  target/arm/op_helper.c |  2 +-
> >  5 files changed, 68 insertions(+), 3 deletions(-)
> >
> > diff --git a/target/arm/cpu.h b/target/arm/cpu.h index
> > b5eff79..502507d 100644
> > --- a/target/arm/cpu.h
> > +++ b/target/arm/cpu.h
> > @@ -2331,6 +2331,8 @@ bool write_list_to_cpustate(ARMCPU *cpu);
> >   */
> >  bool write_cpustate_to_list(ARMCPU *cpu);
> >
> > +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset);
> > +
> >  #define ARM_CPUID_TI915T  0x54029152
> >  #define ARM_CPUID_TI925T  0x54029252
> >
> > diff --git a/target/arm/helper.c b/target/arm/helper.c index
> > 9630193..df078ff 100644
> > --- a/target/arm/helper.c
> > +++ b/target/arm/helper.c
> > @@ -263,6 +263,29 @@ static bool raw_accessors_invalid(const ARMCPRegInfo 
> > *ri)
> >  return true;
> >  }
> >
> > +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset)
> > +{
> > +const ARMCPRegInfo *ri;
> > +uint32_t regidx, i;
> > +
> > +for (i = 0; i < cpu->cpreg_array_len; i++) {
> > +regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
> > +ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
> > +if (!ri) {
> > +continue;
> > +}
> > +
> > +if (ri->type & ARM_CP_NO_RAW) {
> > +continue;
> > +}
> > +if (ri->fieldoffset == fieldoffset) {
> > +cpu->cpreg_values[i] = read_raw_cp_reg(>env, ri);
> > +return true;
> > +}
> > +}
> > +return false;
> > +}
> 
> What is this about? Nothing else in QEMU needs to mess with the cpustate 
> synchronization. My first assumption is that you should not
> need to do so either.

We should change the guest CP15 ESR_EL1's value, the only method is to change 
the cpu->cpreg_values[] in QEMU, then QEMU call write_list_to_kvmstate()
to set the cpu->cpreg_values[] to KVM which include the specified ESR_EL1 
value, KVM do world switch, and then set the specified ESR_EL1's value to guest 
kernel.
About the detailed explanation, as shown in [2].

kvm_arm_handle_debug() does not need to do this because QEMU does not need to 
change CP15 registers, such as ESR_EL1.

> 
> > +
> >  bool write_cpustate_to_list(ARMCPU *cpu)  {
> >  /* Write the coprocessor state from cpu->env to the (index,value)
> > list. */ diff --git a/target/arm/internals.h b/target/arm/internals.h
> > index 6c2bb2d..04ea074 100644
> > --- a/target/arm/internals.h
> > +++ b/target/arm/internals.h
> > @@ -415,13 +415,14 @@ static inline uint32_t syn_insn_abort(int same_el, 
> > int ea, int s1ptw, int fsc)
> >  | 

Re: [Qemu-devel] [PATCH RESEND v15 08/10] target-arm: kvm64: inject synchronous External Abort

2018-11-20 Thread Peter Maydell
On 8 November 2018 at 10:29, Dongjiu Geng  wrote:
> Add synchronous external abort injection logic, setup
> exception type and syndrome value. When switch to guest,
> guest will jump to the synchronous external abort vector
> table entry.
>
> The ESR_ELx.DFSC is set to synchronous external abort(0x10),
> and ESR_ELx.FnV is set to not valid(0x1), which will tell
> guest that FAR is not valid and holds an UNKNOWN value.
> These value will be set to KVM register structures through
> KVM_SET_ONE_REG IOCTL.
>
> Signed-off-by: Dongjiu Geng 
> ---
> Marc is against that KVM inject the synchronous external abort(SEA) in [1],
> so user space how to inject it. The test result that injection SEA to guest 
> by Qemu
> is shown in [2].
>
> [1]: https://lkml.org/lkml/2017/3/2/110
> [2]:
> Taking exception 4 [Data Abort]
> ...from EL0 to EL1
> ...with ESR 0x24/0x92000410
> ...with FAR 0x0
> ...with ELR 0x40cf04
> ...to EL1 PC 0xffc84c00 PSTATE 0x3c5
> after kvm_inject_arm_sea
> Unhandled fault: synchronous external abort (0x92000410) at 0x007fa234c12c
> CPU: 0 PID: 536 Comm: devmem Not tainted 4.1.0+ #20
> Hardware name: linux,dummy-virt (DT)
> task: ffc019ab2b00 ti: ffc008134000 task.ti: ffc008134000
> PC is at 0x40cf04
> LR is at 0x40cdec
> pc : [<0040cf04>] lr : [<0040cdec>] pstate: 6000
> sp : 007ff7b24130
> x29: 007ff7b24260 x28: 
> x27: 00ad x26: 0049c000
> x25: 0048904b x24: 0049c000
> x23: 4060 x22: 007ff7b243a0
> x21: 0002 x20: 
> x19: 0020 x18: 
> x17: 0049c6d0 x16: 007fa22c85c0
> x15: 5798 x14: 007fa2205f1c
> x13: 007fa241ccb0 x12: 0137
> x11:  x10: 
> x9 :  x8 : 00de
> x7 :  x6 : 2000
> x5 : 4060 x4 : 0003
> x3 : 0001 x2 : 
> x1 :  x0 : 007fa2418000
> ---
>  target/arm/cpu.h   |  2 ++
>  target/arm/helper.c| 23 +++
>  target/arm/internals.h |  5 +++--
>  target/arm/kvm64.c | 39 +++
>  target/arm/op_helper.c |  2 +-
>  5 files changed, 68 insertions(+), 3 deletions(-)
>
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index b5eff79..502507d 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -2331,6 +2331,8 @@ bool write_list_to_cpustate(ARMCPU *cpu);
>   */
>  bool write_cpustate_to_list(ARMCPU *cpu);
>
> +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset);
> +
>  #define ARM_CPUID_TI915T  0x54029152
>  #define ARM_CPUID_TI925T  0x54029252
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 9630193..df078ff 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -263,6 +263,29 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
>  return true;
>  }
>
> +bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset)
> +{
> +const ARMCPRegInfo *ri;
> +uint32_t regidx, i;
> +
> +for (i = 0; i < cpu->cpreg_array_len; i++) {
> +regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
> +ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
> +if (!ri) {
> +continue;
> +}
> +
> +if (ri->type & ARM_CP_NO_RAW) {
> +continue;
> +}
> +if (ri->fieldoffset == fieldoffset) {
> +cpu->cpreg_values[i] = read_raw_cp_reg(>env, ri);
> +return true;
> +}
> +}
> +return false;
> +}

What is this about? Nothing else in QEMU needs to mess with the
cpustate synchronization. My first assumption is that you should
not need to do so either.

> +
>  bool write_cpustate_to_list(ARMCPU *cpu)
>  {
>  /* Write the coprocessor state from cpu->env to the (index,value) list. 
> */
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 6c2bb2d..04ea074 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -415,13 +415,14 @@ static inline uint32_t syn_insn_abort(int same_el, int 
> ea, int s1ptw, int fsc)
>  | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc;
>  }
>
> -static inline uint32_t syn_data_abort_no_iss(int same_el,
> +static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv,
>   int ea, int cm, int s1ptw,
>   int wnr, int fsc)
>  {
>  return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
> | ARM_EL_IL
> -   | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
> +   | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7)
> +   | (wnr << 6) | fsc;
>  }
>
>  static inline uint32_t syn_data_abort_with_iss(int same_el,
> diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> index 5de8ff0..0ca2b29 100644

[Qemu-devel] [PATCH RESEND v15 08/10] target-arm: kvm64: inject synchronous External Abort

2018-11-08 Thread Dongjiu Geng
Add synchronous external abort injection logic, setup
exception type and syndrome value. When switch to guest,
guest will jump to the synchronous external abort vector
table entry.

The ESR_ELx.DFSC is set to synchronous external abort(0x10),
and ESR_ELx.FnV is set to not valid(0x1), which will tell
guest that FAR is not valid and holds an UNKNOWN value.
These value will be set to KVM register structures through
KVM_SET_ONE_REG IOCTL.

Signed-off-by: Dongjiu Geng 
---
Marc is against that KVM inject the synchronous external abort(SEA) in [1],
so user space how to inject it. The test result that injection SEA to guest by 
Qemu
is shown in [2].

[1]: https://lkml.org/lkml/2017/3/2/110
[2]:
Taking exception 4 [Data Abort]
...from EL0 to EL1
...with ESR 0x24/0x92000410
...with FAR 0x0
...with ELR 0x40cf04
...to EL1 PC 0xffc84c00 PSTATE 0x3c5
after kvm_inject_arm_sea
Unhandled fault: synchronous external abort (0x92000410) at 0x007fa234c12c
CPU: 0 PID: 536 Comm: devmem Not tainted 4.1.0+ #20
Hardware name: linux,dummy-virt (DT)
task: ffc019ab2b00 ti: ffc008134000 task.ti: ffc008134000
PC is at 0x40cf04
LR is at 0x40cdec
pc : [<0040cf04>] lr : [<0040cdec>] pstate: 6000
sp : 007ff7b24130
x29: 007ff7b24260 x28: 
x27: 00ad x26: 0049c000
x25: 0048904b x24: 0049c000
x23: 4060 x22: 007ff7b243a0
x21: 0002 x20: 
x19: 0020 x18: 
x17: 0049c6d0 x16: 007fa22c85c0
x15: 5798 x14: 007fa2205f1c
x13: 007fa241ccb0 x12: 0137
x11:  x10: 
x9 :  x8 : 00de
x7 :  x6 : 2000
x5 : 4060 x4 : 0003
x3 : 0001 x2 : 
x1 :  x0 : 007fa2418000
---
 target/arm/cpu.h   |  2 ++
 target/arm/helper.c| 23 +++
 target/arm/internals.h |  5 +++--
 target/arm/kvm64.c | 39 +++
 target/arm/op_helper.c |  2 +-
 5 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index b5eff79..502507d 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2331,6 +2331,8 @@ bool write_list_to_cpustate(ARMCPU *cpu);
  */
 bool write_cpustate_to_list(ARMCPU *cpu);
 
+bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset);
+
 #define ARM_CPUID_TI915T  0x54029152
 #define ARM_CPUID_TI925T  0x54029252
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 9630193..df078ff 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -263,6 +263,29 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
 return true;
 }
 
+bool write_part_cpustate_to_list(ARMCPU *cpu, ptrdiff_t fieldoffset)
+{
+const ARMCPRegInfo *ri;
+uint32_t regidx, i;
+
+for (i = 0; i < cpu->cpreg_array_len; i++) {
+regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
+ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
+if (!ri) {
+continue;
+}
+
+if (ri->type & ARM_CP_NO_RAW) {
+continue;
+}
+if (ri->fieldoffset == fieldoffset) {
+cpu->cpreg_values[i] = read_raw_cp_reg(>env, ri);
+return true;
+}
+}
+return false;
+}
+
 bool write_cpustate_to_list(ARMCPU *cpu)
 {
 /* Write the coprocessor state from cpu->env to the (index,value) list. */
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 6c2bb2d..04ea074 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -415,13 +415,14 @@ static inline uint32_t syn_insn_abort(int same_el, int 
ea, int s1ptw, int fsc)
 | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc;
 }
 
-static inline uint32_t syn_data_abort_no_iss(int same_el,
+static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv,
  int ea, int cm, int s1ptw,
  int wnr, int fsc)
 {
 return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
| ARM_EL_IL
-   | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
+   | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7)
+   | (wnr << 6) | fsc;
 }
 
 static inline uint32_t syn_data_abort_with_iss(int same_el,
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 5de8ff0..0ca2b29 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -594,6 +594,45 @@ int kvm_arm_cpreg_level(uint64_t regidx)
 return KVM_PUT_RUNTIME_STATE;
 }
 
+/* Inject synchronous external abort */
+static void kvm_inject_arm_sea(CPUState *c)
+{
+ARMCPU *cpu = ARM_CPU(c);
+CPUARMState *env = >env;
+CPUClass *cc = CPU_GET_CLASS(c);
+uint32_t esr;
+int ret;
+
+/* This exception is synchronous data abort */
+c->exception_index =