예제 #1
0
static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
{
    struct kvm *kvm = source_vcpu->kvm;
    struct kvm_vcpu *vcpu = NULL;
    wait_queue_head_t *wq;
    unsigned long cpu_id;
    unsigned long context_id;
    phys_addr_t target_pc;

    cpu_id = *vcpu_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
    if (vcpu_mode_is_32bit(source_vcpu))
        cpu_id &= ~((u32) 0);

    vcpu = kvm_mpidr_to_vcpu(kvm, cpu_id);

    /*
     * Make sure the caller requested a valid CPU and that the CPU is
     * turned off.
     */
    if (!vcpu)
        return PSCI_RET_INVALID_PARAMS;
    if (!vcpu->arch.power_off) {
        if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
            return PSCI_RET_ALREADY_ON;
        else
            return PSCI_RET_INVALID_PARAMS;
    }

    target_pc = *vcpu_reg(source_vcpu, 2);
    context_id = *vcpu_reg(source_vcpu, 3);

    kvm_reset_vcpu(vcpu);

    /* Gracefully handle Thumb2 entry point */
    if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) {
        target_pc &= ~((phys_addr_t) 1);
        vcpu_set_thumb(vcpu);
    }

    /* Propagate caller endianness */
    if (kvm_vcpu_is_be(source_vcpu))
        kvm_vcpu_set_be(vcpu);

    *vcpu_pc(vcpu) = target_pc;
    /*
     * NOTE: We always update r0 (or x0) because for PSCI v0.1
     * the general puspose registers are undefined upon CPU_ON.
     */
    *vcpu_reg(vcpu, 0) = context_id;
    vcpu->arch.power_off = false;
    smp_mb();		/* Make sure the above is visible */

    wq = kvm_arch_vcpu_wq(vcpu);
    wake_up_interruptible(wq);

    return PSCI_RET_SUCCESS;
}
예제 #2
0
static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
{
	struct kvm *kvm = source_vcpu->kvm;
	struct kvm_vcpu *vcpu;
	wait_queue_head_t *wq;
	unsigned long cpu_id;
	phys_addr_t target_pc;

	cpu_id = *vcpu_reg(source_vcpu, 1);
	if (vcpu_mode_is_32bit(source_vcpu))
		cpu_id &= ~((u32) 0);

	if (cpu_id >= atomic_read(&kvm->online_vcpus))
		return KVM_PSCI_RET_INVAL;

	target_pc = *vcpu_reg(source_vcpu, 2);

	vcpu = kvm_get_vcpu(kvm, cpu_id);

	wq = kvm_arch_vcpu_wq(vcpu);
	if (!waitqueue_active(wq))
		return KVM_PSCI_RET_INVAL;

	kvm_reset_vcpu(vcpu);

	/* Gracefully handle Thumb2 entry point */
	if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) {
		target_pc &= ~((phys_addr_t) 1);
		vcpu_set_thumb(vcpu);
	}

	*vcpu_pc(vcpu) = target_pc;
	vcpu->arch.pause = false;
	smp_mb();		/* Make sure the above is visible */

	wake_up_interruptible(wq);

	return KVM_PSCI_RET_SUCCESS;
}