arch/s390/kvm/sigp.c

Source file repositories/reference/linux-study-clean/arch/s390/kvm/sigp.c

File Facts

System
Linux kernel
Corpus path
arch/s390/kvm/sigp.c
Extension
.c
Size
13354 bytes
Lines
496
Domain
Architecture Layer
Bucket
arch/s390
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * handling interprocessor communication
 *
 * Copyright IBM Corp. 2008, 2013
 *
 *    Author(s): Carsten Otte <cotte@de.ibm.com>
 *               Christian Borntraeger <borntraeger@de.ibm.com>
 *               Christian Ehrhardt <ehrhardt@de.ibm.com>
 */

#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <linux/slab.h>
#include <asm/sigp.h>
#include "gaccess.h"
#include "kvm-s390.h"
#include "trace.h"

static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
			u64 *reg)
{
	const bool stopped = kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_STOPPED);
	int rc;
	int ext_call_pending;

	ext_call_pending = kvm_s390_ext_call_pending(dst_vcpu);
	if (!stopped && !ext_call_pending)
		rc = SIGP_CC_ORDER_CODE_ACCEPTED;
	else {
		*reg &= 0xffffffff00000000UL;
		if (ext_call_pending)
			*reg |= SIGP_STATUS_EXT_CALL_PENDING;
		if (stopped)
			*reg |= SIGP_STATUS_STOPPED;
		rc = SIGP_CC_STATUS_STORED;
	}

	VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", dst_vcpu->vcpu_id,
		   rc);
	return rc;
}

static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
				    struct kvm_vcpu *dst_vcpu)
{
	struct kvm_s390_irq irq = {
		.type = KVM_S390_INT_EMERGENCY,
		.u.emerg.code = vcpu->vcpu_id,
	};
	int rc = 0;

	rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
	if (!rc)
		VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
			   dst_vcpu->vcpu_id);

	return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
}

static int __sigp_emergency(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu)
{
	return __inject_sigp_emergency(vcpu, dst_vcpu);
}

static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
					struct kvm_vcpu *dst_vcpu,
					u16 asn, u64 *reg)
{
	const u64 psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
	u16 p_asn, s_asn;
	psw_t *psw;
	bool idle;

	idle = is_vcpu_idle(vcpu);
	psw = &dst_vcpu->arch.sie_block->gpsw;
	p_asn = dst_vcpu->arch.sie_block->gcr[4] & 0xffff;  /* Primary ASN */
	s_asn = dst_vcpu->arch.sie_block->gcr[3] & 0xffff;  /* Secondary ASN */

	/* Inject the emergency signal? */
	if (!is_vcpu_stopped(vcpu)
	    || (psw->mask & psw_int_mask) != psw_int_mask
	    || (idle && psw->addr != 0)
	    || (!idle && (asn == p_asn || asn == s_asn))) {
		return __inject_sigp_emergency(vcpu, dst_vcpu);
	} else {
		*reg &= 0xffffffff00000000UL;
		*reg |= SIGP_STATUS_INCORRECT_STATE;
		return SIGP_CC_STATUS_STORED;
	}

Annotation

Implementation Notes