Re: [PATCH 1/3] KVM: ARM: __kvm_va_to_pa()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 23, 2012 at 3:19 AM, Rusty Russell <rusty.russell@xxxxxxxxxx> wrote:
> Create a helper to do the guest va->pa mapping.  Then take the code out of the
> exit path, and use normal C.
>
> copy_from_guest_va() is a bit more generic than it needs to be, but
> not much.
>
> Signed-off-by: Rusty Russell <rusty.russell@xxxxxxxxxx>
>
> diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
> index 85bd676..ee21cd2 100644
> --- a/arch/arm/include/asm/kvm_asm.h
> +++ b/arch/arm/include/asm/kvm_asm.h
> @@ -54,6 +54,8 @@ extern void __kvm_flush_vm_context(void);
>  extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
>
>  extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
> +
> +extern u64 __kvm_va_to_pa(struct kvm_vcpu *vcpu, u32 va, bool priv);
>  #endif
>
>  #endif /* __ARM_KVM_ASM_H__ */
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 778d2af..79b5318 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -131,9 +131,6 @@ struct kvm_vcpu_arch {
>         u32 hdfar;              /* Hyp Data Fault Address Register */
>         u32 hifar;              /* Hyp Inst. Fault Address Register */
>         u32 hpfar;              /* Hyp IPA Fault Address Register */
> -       u64 pc_ipa;             /* IPA for the current PC (VA to PA result) */
> -       u64 pc_ipa2;            /* same as above, but for non-aligned wide thumb
> -                                  instructions */
>
>         /* Floating point registers (VFP and Advanced SIMD/NEON) */
>         struct vfp_hard_struct vfp_guest;
> diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
> index aca6c2c..bb18fd4 100644
> --- a/arch/arm/kernel/asm-offsets.c
> +++ b/arch/arm/kernel/asm-offsets.c
> @@ -184,8 +184,6 @@ int main(void)
>    DEFINE(VCPU_HDFAR,           offsetof(struct kvm_vcpu, arch.hdfar));
>    DEFINE(VCPU_HIFAR,           offsetof(struct kvm_vcpu, arch.hifar));
>    DEFINE(VCPU_HPFAR,           offsetof(struct kvm_vcpu, arch.hpfar));
> -  DEFINE(VCPU_PC_IPA,          offsetof(struct kvm_vcpu, arch.pc_ipa));
> -  DEFINE(VCPU_PC_IPA2,         offsetof(struct kvm_vcpu, arch.pc_ipa2));
>    DEFINE(VCPU_HYP_PC,          offsetof(struct kvm_vcpu, arch.hyp_pc));
>    DEFINE(KVM_VTTBR,            offsetof(struct kvm, arch.vttbr));
>  #endif
> diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
> index b70394a..d282860 100644
> --- a/arch/arm/kvm/interrupts.S
> +++ b/arch/arm/kvm/interrupts.S
> @@ -510,6 +510,37 @@ after_vfp_restore:
>         clrex                           @ Clear exclusive monitor
>         bx      lr                      @ return to IOCTL
>
> +@ Arguments:
> +@  r0: pointer to vcpu struct
> +@  r1: virtual address to map (rounded to page)
> +@  r2: 1 = P1 (read) mapping, 0 = P0 (read) mapping.
> +@ Returns 64 bit PAR value.
> +ENTRY(__kvm_va_to_pa)
> +       hvc     #0                      @ switch to hyp-mode
> +
> +       push    {r4-r12}
> +
> +       @ Fold flag into r1, easier than using stack.

In case some bonehead calls this with r1 not a bool but some other
non-zero value, we would never see errors, but really weird bugs,
wouldn't it be more safe to do:

cmp    r1, #0
movne  r1, #1

> +       orr     r1, r1, r2
> +
> +       @ This swaps too many registers, but we're in the slow path anyway.
> +       read_cp15_state
> +       write_cp15_state 1, r0
> +
> +       ands    r2, r1, #1
> +       sub     r1, r1, r2

I think "bic r1, r1, r2" is clearer

> +       mcrne   p15, 0, r1, c7, c8, 0   @ VA to PA, ATS1CPR
> +       mcreq   p15, 0, r1, c7, c8, 2   @ VA to PA, ATS1CUR
> +

Page B4-1730 in the arm arm seems to suggest we need an ISB here (yes
I know, it's my bug, not yours)

> +       @ Restore host state.
> +       read_cp15_state 1, r0
> +       write_cp15_state
> +
> +       mrrc    p15, 0, r0, r1, c7      @ PAR
> +       pop     {r4-r12}
> +       hvc     #0                      @ Back to SVC
> +       bx      lr
> +
>  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>  @  Hypervisor exception vector and handlers
>  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
> @@ -686,34 +717,6 @@ guest_trap:
>         cmpne   r2, #HSR_EC_DABT
>         bne     1f
>
> -       @ For non-valid data aborts, get the offending instr. PA
> -       lsr     r2, r0, #HSR_ISV_SHIFT
> -       ands    r2, r2, #1
> -       bne     2f
> -       mrs     r3, ELR_hyp
> -       mrs     r7, spsr
> -       and     r7, r7, #0xf
> -       cmp     r7, #0                  @ fault happened in user mode?
> -       mcreq   p15, 0, r3, c7, c8, 2   @ VA to PA, ATS1CUR
> -       mcrne   p15, 0, r3, c7, c8, 0   @ VA to PA, ATS1CPR
> -       mrrc    p15, 0, r4, r5, c7      @ PAR
> -       add     r6, r1, #VCPU_PC_IPA
> -       strd    r4, r5, [r6]
> -
> -       @ Check if we might have a wide thumb instruction spill-over
> -       ldr     r5, =0xfff
> -       bic     r4, r3, r5              @ clear page mask
> -       sub     r5, r5, #1              @ last 2-byte page bounday, 0xffe
> -       cmp     r4, r5
> -       bne     2f
> -       add     r4, r3, #2              @ _really_ unlikely!
> -       cmp     r7, #0                  @ fault happened in user mode?
> -       mcreq   p15, 0, r4, c7, c8, 2   @ VA to PA, ATS1CUR
> -       mcrne   p15, 0, r4, c7, c8, 0   @ VA to PA, ATS1CPR
> -       mrrc    p15, 0, r4, r5, c7      @ PAR
> -       add     r6, r1, #VCPU_PC_IPA2
> -       strd    r4, r5, [r6]
> -
>  2:     mrc     p15, 4, r2, c6, c0, 0   @ HDFAR
>         mrc     p15, 4, r3, c6, c0, 2   @ HIFAR
>         mrc     p15, 4, r4, c6, c0, 4   @ HPFAR
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index 3df4fa8..6909a83 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -580,6 +580,62 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  }
>
>  /**
> + * copy_from_guest_va - copy memory from guest (very slow!)
> + * @vcpu:      vcpu pointer
> + * @dest:      memory to copy into
> + * @va:                virtual address in guest to copy from

nit: gva might even be more kvm'ish and clearer

> + * @len:       length to copy
> + * @priv:      use guest PL1 (ie. kernel) mappings, otherwise use guest PL0 mappings.
> + *
> + * Returns 0 on success, or errno.
> + */
> +static int copy_from_guest_va(struct kvm_vcpu *vcpu,
> +                             void *dest, unsigned long va, size_t len,
> +                             bool priv)
> +{
> +       u64 par;
> +       phys_addr_t pc_ipa;
> +       size_t cur_len;
> +       int err;
> +
> +       /* A 32-bit thumb2 instruction can actually go over a page boundary! */
> +       do {
> +               par = __kvm_va_to_pa(vcpu, va & PAGE_MASK, priv);
> +               if (par & 1) {
> +                       kvm_err("I/O Abort from invalid instruction address? Wrong!\n");
> +                       return -EINVAL;

what if it was unmapped from under us? Do we really want to print
Wrong! and write to the kernel error log?

> +               }
> +
> +               if (par & (1U << 11)) {
> +                       /* LPAE PAR format */
> +                       /*
> +                        * TODO: Check if this ever happens
> +                        * - called from Hyp mode
> +                        */

Getting a chance to revisit this, surely it has to happen if the guest
uses LPAE - otherwise you wouldn't be able to get the top bits from
the VA to PA operation executed from Hyp mode.

Peter/Marc, can you verify?

> +                       pc_ipa = par & PAGE_MASK & ((1ULL << 32) - 1);
> +               } else {
> +                       /* VMSAv7 PAR format */
> +                       pc_ipa = par & PAGE_MASK & ((1ULL << 40) - 1);
> +               }
> +               pc_ipa += va & ~PAGE_MASK;
> +
> +               /* Only copy up to end of page. */
> +               cur_len = (pc_ipa & PAGE_MASK) + PAGE_SIZE - pc_ipa;
> +               if (likely(cur_len > len))
> +                       cur_len = len;
> +
> +               err = kvm_read_guest(vcpu->kvm, pc_ipa, dest, cur_len);
> +               if (unlikely(err))
> +                       return err;
> +
> +               len -= cur_len;
> +               va += cur_len;
> +       } while (unlikely(len != 0));
> +
> +       return 0;
> +}
> +
> +/**
>   * invalid_io_mem_abort -- Handle I/O aborts ISV bit is clear
>   *
>   * @vcpu:      The vcpu pointer
> @@ -593,22 +649,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  static int invalid_io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
>  {
>         unsigned long instr;
> -       phys_addr_t pc_ipa;
> -
> -       if (vcpu->arch.pc_ipa & 1) {
> -               kvm_err("I/O Abort from invalid instruction address? Wrong!\n");
> -               return -EINVAL;
> -       }
> -
> -       if (vcpu->arch.pc_ipa & (1U << 11)) {
> -               /* LPAE PAR format */
> -               /* TODO: Check if this ever happens - called from Hyp mode */
> -               pc_ipa = vcpu->arch.pc_ipa & PAGE_MASK & ((1ULL << 32) - 1);
> -       } else {
> -               /* VMSAv7 PAR format */
> -               pc_ipa = vcpu->arch.pc_ipa & PAGE_MASK & ((1ULL << 40) - 1);
> -       }
> -       pc_ipa += vcpu->arch.regs.pc & ~PAGE_MASK;
> +       int err;
>
>         if (vcpu->arch.regs.cpsr & PSR_T_BIT) {
>                 /* TODO: Check validity of PC IPA and IPA2!!! */
> @@ -617,9 +658,11 @@ static int invalid_io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
>                 return -EINVAL;
>         }
>
> -       if (kvm_read_guest(vcpu->kvm, pc_ipa, &instr, sizeof(instr))) {
> +       err = copy_from_guest_va(vcpu, &instr, vcpu->arch.regs.pc, sizeof(instr),
> +                                vcpu_mode_priv(vcpu));
> +       if (err) {
>                 kvm_err("Could not copy guest instruction\n");
> -               return -EFAULT;
> +               return err;
>         }
>
>         return kvm_emulate_mmio_ls(vcpu, fault_ipa, instr);


awesome cleanup!
_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm


[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux