Commit afbb1b1c authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/s1ptw-write-fault into kvmarm-master/fixes



* kvm-arm64/s1ptw-write-fault:
  : .
  : Fix S1PTW fault handling that was until then always taken
  : as a write. From the cover letter:
  :
  : `Recent developments on the EFI front have resulted in guests that
  : simply won't boot if the page tables are in a read-only memslot and
  : that you're a bit unlucky in the way S2 gets paged in... The core
  : issue is related to the fact that we treat a S1PTW as a write, which
  : is close enough to what needs to be done. Until to get to RO memslots.
  :
  : The first patch fixes this and is definitely a stable candidate. It
  : splits the faulting of page tables in two steps (RO translation fault,
  : followed by a writable permission fault -- should it even happen).
  : The second one documents the slightly odd behaviour of PTW writes to
  : RO memslot, which do not result in a KVM_MMIO exit. The last patch is
  : totally optional, only tangentially related, and randomly repainting
  : stuff (maybe that's contagious, who knows)."
  :
  : .
  KVM: arm64: Convert FSC_* over to ESR_ELx_FSC_*
  KVM: arm64: Document the behaviour of S1PTW faults on RO memslots
  KVM: arm64: Fix S1PTW handling on RO memslots

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents d5b4d07b b0803ba7
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -1354,6 +1354,14 @@ the memory region are automatically reflected into the guest. For example, an
mmap() that affects the region will be made visible immediately.  Another
example is madvise(MADV_DROP).

Note: On arm64, a write generated by the page-table walker (to update
the Access and Dirty flags, for example) never results in a
KVM_EXIT_MMIO exit when the slot has the KVM_MEM_READONLY flag. This
is because KVM cannot provide the data that would be written by the
page-table walker, making it impossible to emulate the access.
Instead, an abort (data abort if the cause of the page-table update
was a load or a store, instruction abort if it was an instruction
fetch) is injected in the guest.

4.36 KVM_SET_TSS_ADDR
---------------------
+9 −0
Original line number Diff line number Diff line
@@ -114,6 +114,15 @@
#define ESR_ELx_FSC_ACCESS	(0x08)
#define ESR_ELx_FSC_FAULT	(0x04)
#define ESR_ELx_FSC_PERM	(0x0C)
#define ESR_ELx_FSC_SEA_TTW0	(0x14)
#define ESR_ELx_FSC_SEA_TTW1	(0x15)
#define ESR_ELx_FSC_SEA_TTW2	(0x16)
#define ESR_ELx_FSC_SEA_TTW3	(0x17)
#define ESR_ELx_FSC_SECC	(0x18)
#define ESR_ELx_FSC_SECC_TTW0	(0x1c)
#define ESR_ELx_FSC_SECC_TTW1	(0x1d)
#define ESR_ELx_FSC_SECC_TTW2	(0x1e)
#define ESR_ELx_FSC_SECC_TTW3	(0x1f)

/* ISS field definitions for Data Aborts */
#define ESR_ELx_ISV_SHIFT	(24)
+0 −15
Original line number Diff line number Diff line
@@ -319,21 +319,6 @@
				 BIT(18) |		\
				 GENMASK(16, 15))

/* For compatibility with fault code shared with 32-bit */
#define FSC_FAULT	ESR_ELx_FSC_FAULT
#define FSC_ACCESS	ESR_ELx_FSC_ACCESS
#define FSC_PERM	ESR_ELx_FSC_PERM
#define FSC_SEA		ESR_ELx_FSC_EXTABT
#define FSC_SEA_TTW0	(0x14)
#define FSC_SEA_TTW1	(0x15)
#define FSC_SEA_TTW2	(0x16)
#define FSC_SEA_TTW3	(0x17)
#define FSC_SECC	(0x18)
#define FSC_SECC_TTW0	(0x1c)
#define FSC_SECC_TTW1	(0x1d)
#define FSC_SECC_TTW2	(0x1e)
#define FSC_SECC_TTW3	(0x1f)

/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
#define HPFAR_MASK	(~UL(0xf))
/*
+30 −12
Original line number Diff line number Diff line
@@ -349,16 +349,16 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *v
static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
{
	switch (kvm_vcpu_trap_get_fault(vcpu)) {
	case FSC_SEA:
	case FSC_SEA_TTW0:
	case FSC_SEA_TTW1:
	case FSC_SEA_TTW2:
	case FSC_SEA_TTW3:
	case FSC_SECC:
	case FSC_SECC_TTW0:
	case FSC_SECC_TTW1:
	case FSC_SECC_TTW2:
	case FSC_SECC_TTW3:
	case ESR_ELx_FSC_EXTABT:
	case ESR_ELx_FSC_SEA_TTW0:
	case ESR_ELx_FSC_SEA_TTW1:
	case ESR_ELx_FSC_SEA_TTW2:
	case ESR_ELx_FSC_SEA_TTW3:
	case ESR_ELx_FSC_SECC:
	case ESR_ELx_FSC_SECC_TTW0:
	case ESR_ELx_FSC_SECC_TTW1:
	case ESR_ELx_FSC_SECC_TTW2:
	case ESR_ELx_FSC_SECC_TTW3:
		return true;
	default:
		return false;
@@ -373,8 +373,26 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)

static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
{
	if (kvm_vcpu_abt_iss1tw(vcpu))
	if (kvm_vcpu_abt_iss1tw(vcpu)) {
		/*
		 * Only a permission fault on a S1PTW should be
		 * considered as a write. Otherwise, page tables baked
		 * in a read-only memslot will result in an exception
		 * being delivered in the guest.
		 *
		 * The drawback is that we end-up faulting twice if the
		 * guest is using any of HW AF/DB: a translation fault
		 * to map the page containing the PT (read only at
		 * first), then a permission fault to allow the flags
		 * to be set.
		 */
		switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
		case ESR_ELx_FSC_PERM:
			return true;
		default:
			return false;
		}
	}

	if (kvm_vcpu_trap_is_iabt(vcpu))
		return false;
+1 −1
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ static inline bool __get_fault_info(u64 esr, struct kvm_vcpu_fault_info *fault)
	 */
	if (!(esr & ESR_ELx_S1PTW) &&
	    (cpus_have_final_cap(ARM64_WORKAROUND_834220) ||
	     (esr & ESR_ELx_FSC_TYPE) == FSC_PERM)) {
	     (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM)) {
		if (!__translate_far_to_hpfar(far, &hpfar))
			return false;
	} else {
Loading