Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57b5981c authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvm-s390-20140429' of...

Merge tag 'kvm-s390-20140429' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into kvm-next

1. Guest handling fixes
The handling of MVPG, PFMF and Test Block is fixed to better follow
the architecture. None of these fixes is critical for any current
Linux guests, but let's play safe.

2. Optimization for single CPU guests
We can enable the IBS facility if only one VCPU is running (!STOPPED
state). We also enable this optimization for guest > 1 VCPU as soon
as all but one VCPU is in stopped state. Thus will help guests that
have tools like cpuplugd (from s390-utils) that do dynamic offline/
online of CPUs.

3. NOTES
There is one non-s390 change in include/linux/kvm_host.h that
introduces 2 defines for VCPU requests:
define KVM_REQ_ENABLE_IBS        23
define KVM_REQ_DISABLE_IBS       24
parents e4c9a5a1 8ad35755
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ struct sca_block {
#define CPUSTAT_ZARCH      0x00000800
#define CPUSTAT_MCDS       0x00000100
#define CPUSTAT_SM         0x00000080
#define CPUSTAT_IBS        0x00000040
#define CPUSTAT_G          0x00000008
#define CPUSTAT_GED        0x00000004
#define CPUSTAT_J          0x00000002
@@ -411,6 +412,7 @@ struct kvm_arch{
	int use_cmma;
	struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
	wait_queue_head_t ipte_wq;
	spinlock_t start_stop_lock;
};

#define KVM_HVA_ERR_BAD		(-1UL)
+1 −1
Original line number Diff line number Diff line
@@ -176,7 +176,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
		return -EOPNOTSUPP;
	}

	atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
	kvm_s390_vcpu_stop(vcpu);
	vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM;
	vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL;
	vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT;
+28 −0
Original line number Diff line number Diff line
@@ -643,3 +643,31 @@ int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
	}
	return rc;
}

/**
 * kvm_s390_check_low_addr_protection - check for low-address protection
 * @ga: Guest address
 *
 * Checks whether an address is subject to low-address protection and set
 * up vcpu->arch.pgm accordingly if necessary.
 *
 * Return: 0 if no protection exception, or PGM_PROTECTION if protected.
 */
int kvm_s390_check_low_addr_protection(struct kvm_vcpu *vcpu, unsigned long ga)
{
	struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm;
	psw_t *psw = &vcpu->arch.sie_block->gpsw;
	struct trans_exc_code_bits *tec_bits;

	if (!is_low_address(ga) || !low_address_protection_enabled(vcpu))
		return 0;

	memset(pgm, 0, sizeof(*pgm));
	tec_bits = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
	tec_bits->fsi = FSI_STORE;
	tec_bits->as = psw_bits(*psw).as;
	tec_bits->addr = ga >> PAGE_SHIFT;
	pgm->code = PGM_PROTECTION;

	return pgm->code;
}
+1 −0
Original line number Diff line number Diff line
@@ -325,5 +325,6 @@ int read_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
}

int ipte_lock_held(struct kvm_vcpu *vcpu);
int kvm_s390_check_low_addr_protection(struct kvm_vcpu *vcpu, unsigned long ga);

#endif /* __KVM_S390_GACCESS_H */
+55 −3
Original line number Diff line number Diff line
/*
 * in-kernel handling for sie intercepts
 *
 * Copyright IBM Corp. 2008, 2009
 * Copyright IBM Corp. 2008, 2014
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (version 2 only)
@@ -65,8 +65,7 @@ static int handle_stop(struct kvm_vcpu *vcpu)
	trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits);

	if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) {
		atomic_set_mask(CPUSTAT_STOPPED,
				&vcpu->arch.sie_block->cpuflags);
		kvm_s390_vcpu_stop(vcpu);
		vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP;
		VCPU_EVENT(vcpu, 3, "%s", "cpu stopped");
		rc = -EOPNOTSUPP;
@@ -234,6 +233,58 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
	return rc2;
}

/**
 * Handle MOVE PAGE partial execution interception.
 *
 * This interception can only happen for guests with DAT disabled and
 * addresses that are currently not mapped in the host. Thus we try to
 * set up the mappings for the corresponding user pages here (or throw
 * addressing exceptions in case of illegal guest addresses).
 */
static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
{
	unsigned long hostaddr, srcaddr, dstaddr;
	psw_t *psw = &vcpu->arch.sie_block->gpsw;
	struct mm_struct *mm = current->mm;
	int reg1, reg2, rc;

	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
	srcaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg2]);
	dstaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg1]);

	/* Make sure that the source is paged-in */
	hostaddr = gmap_fault(srcaddr, vcpu->arch.gmap);
	if (IS_ERR_VALUE(hostaddr))
		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
	down_read(&mm->mmap_sem);
	rc = get_user_pages(current, mm, hostaddr, 1, 0, 0, NULL, NULL);
	up_read(&mm->mmap_sem);
	if (rc < 0)
		return rc;

	/* Make sure that the destination is paged-in */
	hostaddr = gmap_fault(dstaddr, vcpu->arch.gmap);
	if (IS_ERR_VALUE(hostaddr))
		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
	down_read(&mm->mmap_sem);
	rc = get_user_pages(current, mm, hostaddr, 1, 1, 0, NULL, NULL);
	up_read(&mm->mmap_sem);
	if (rc < 0)
		return rc;

	psw->addr = __rewind_psw(*psw, 4);

	return 0;
}

static int handle_partial_execution(struct kvm_vcpu *vcpu)
{
	if (vcpu->arch.sie_block->ipa == 0xb254)	/* MVPG */
		return handle_mvpg_pei(vcpu);

	return -EOPNOTSUPP;
}

static const intercept_handler_t intercept_funcs[] = {
	[0x00 >> 2] = handle_noop,
	[0x04 >> 2] = handle_instruction,
@@ -245,6 +296,7 @@ static const intercept_handler_t intercept_funcs[] = {
	[0x1C >> 2] = kvm_s390_handle_wait,
	[0x20 >> 2] = handle_validity,
	[0x28 >> 2] = handle_stop,
	[0x38 >> 2] = handle_partial_execution,
};

int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
Loading