arch/riscv/kvm/vcpu_pmu.c

Source file repositories/reference/linux-study-clean/arch/riscv/kvm/vcpu_pmu.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/kvm/vcpu_pmu.c
Extension
.c
Size
25799 bytes
Lines
935
Domain
Architecture Layer
Bucket
arch/riscv
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

if (csr_num == CSR_CYCLE || csr_num == CSR_INSTRET) {
			*val = 0;
			return ret;
		} else {
			return KVM_INSN_ILLEGAL_TRAP;
		}
	}

	/* The counter CSR are read only. Thus, any write should result in illegal traps */
	if (wr_mask)
		return KVM_INSN_ILLEGAL_TRAP;

	cidx = csr_num - CSR_CYCLE;

	if (pmu_ctr_read(vcpu, cidx, val) < 0)
		return KVM_INSN_ILLEGAL_TRAP;

	return ret;
}

static void kvm_pmu_clear_snapshot_area(struct kvm_vcpu *vcpu)
{
	struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);

	kfree(kvpmu->sdata);
	kvpmu->sdata = NULL;
	kvpmu->snapshot_addr = INVALID_GPA;
}

int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long saddr_low,
				      unsigned long saddr_high, unsigned long flags,
				      struct kvm_vcpu_sbi_return *retdata)
{
	struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
	int snapshot_area_size = sizeof(struct riscv_pmu_snapshot_data);
	int sbiret = 0;
	gpa_t saddr;

	if (!kvpmu || flags) {
		sbiret = SBI_ERR_INVALID_PARAM;
		goto out;
	}

	if (saddr_low == SBI_SHMEM_DISABLE && saddr_high == SBI_SHMEM_DISABLE) {
		kvm_pmu_clear_snapshot_area(vcpu);
		return 0;
	}

	saddr = saddr_low;

	if (saddr_high != 0) {
		if (IS_ENABLED(CONFIG_32BIT)) {
			saddr |= ((gpa_t)saddr_high << 32);
		} else {
			sbiret = SBI_ERR_INVALID_ADDRESS;
			goto out;
		}
	}

	kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC);
	if (!kvpmu->sdata) {
		sbiret = SBI_ERR_FAILURE;
		goto out;
	}

	/* No need to check writable slot explicitly as kvm_vcpu_write_guest does it internally */
	if (kvm_vcpu_write_guest(vcpu, saddr, kvpmu->sdata, snapshot_area_size)) {
		kfree(kvpmu->sdata);
		kvpmu->sdata = NULL;
		sbiret = SBI_ERR_INVALID_ADDRESS;
		goto out;
	}

	kvpmu->snapshot_addr = saddr;

out:
	retdata->err_val = sbiret;

	return 0;
}

int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low,
				  unsigned long saddr_high, unsigned long num_events,
				  unsigned long flags, struct kvm_vcpu_sbi_return *retdata)
{
	struct riscv_pmu_event_info *einfo = NULL;
	int shmem_size = num_events * sizeof(*einfo);
	gpa_t shmem;
	u32 eidx, etype;
	u64 econfig;

Annotation

Implementation Notes