File Index
Files and directories
Sign in
FILE

set_boot_cpu_id.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/x86/set_boot_cpu_id.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Test that KVM_SET_BOOT_CPU_ID works as intended
  4 *
  5 * Copyright (C) 2020, Red Hat, Inc.
  6 */
  7#include <fcntl.h>
  8#include <stdio.h>
  9#include <stdlib.h>
 10#include <string.h>
 11#include <sys/ioctl.h>
 12
 13#include "test_util.h"
 14#include "kvm_util.h"
 15#include "processor.h"
 16#include "apic.h"
 17
 18static void guest_bsp_vcpu(void *arg)
 19{
 20	GUEST_SYNC(1);
 21
 22	GUEST_ASSERT_NE(get_bsp_flag(), 0);
 23
 24	GUEST_DONE();
 25}
 26
 27static void guest_not_bsp_vcpu(void *arg)
 28{
 29	GUEST_SYNC(1);
 30
 31	GUEST_ASSERT_EQ(get_bsp_flag(), 0);
 32
 33	GUEST_DONE();
 34}
 35
 36static void test_set_invalid_bsp(struct kvm_vm *vm)
 37{
 38	unsigned long max_vcpu_id = vm_check_cap(vm, KVM_CAP_MAX_VCPU_ID);
 39	int r;
 40
 41	if (max_vcpu_id) {
 42		r = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(max_vcpu_id + 1));
 43		TEST_ASSERT(r == -1 && errno == EINVAL, "BSP with ID > MAX should fail");
 44	}
 45
 46	r = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(1L << 32));
 47	TEST_ASSERT(r == -1 && errno == EINVAL, "BSP with ID[63:32]!=0 should fail");
 48}
 49
 50static void test_set_bsp_busy(struct kvm_vcpu *vcpu, const char *msg)
 51{
 52	int r = __vm_ioctl(vcpu->vm, KVM_SET_BOOT_CPU_ID,
 53			   (void *)(unsigned long)vcpu->id);
 54
 55	TEST_ASSERT(r == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set %s", msg);
 56}
 57
 58static void run_vcpu(struct kvm_vcpu *vcpu)
 59{
 60	struct ucall uc;
 61	int stage;
 62
 63	for (stage = 0; stage < 2; stage++) {
 64
 65		vcpu_run(vcpu);
 66
 67		switch (get_ucall(vcpu, &uc)) {
 68		case UCALL_SYNC:
 69			TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
 70					uc.args[1] == stage + 1,
 71					"Stage %d: Unexpected register values vmexit, got %lx",
 72					stage + 1, (ulong)uc.args[1]);
 73			test_set_bsp_busy(vcpu, "while running vm");
 74			break;
 75		case UCALL_DONE:
 76			TEST_ASSERT(stage == 1,
 77					"Expected GUEST_DONE in stage 2, got stage %d",
 78					stage);
 79			break;
 80		case UCALL_ABORT:
 81			REPORT_GUEST_ASSERT(uc);
 82		default:
 83			TEST_ASSERT(false, "Unexpected exit: %s",
 84				    exit_reason_str(vcpu->run->exit_reason));
 85		}
 86	}
 87}
 88
 89static struct kvm_vm *create_vm(uint32_t nr_vcpus, uint32_t bsp_vcpu_id,
 90				struct kvm_vcpu *vcpus[])
 91{
 92	struct kvm_vm *vm;
 93	uint32_t i;
 94
 95	vm = vm_create(nr_vcpus);
 96
 97	test_set_invalid_bsp(vm);
 98
 99	vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(unsigned long)bsp_vcpu_id);
100
101	for (i = 0; i < nr_vcpus; i++)
102		vcpus[i] = vm_vcpu_add(vm, i, i == bsp_vcpu_id ? guest_bsp_vcpu :
103								 guest_not_bsp_vcpu);
104	return vm;
105}
106
107static void run_vm_bsp(uint32_t bsp_vcpu_id)
108{
109	struct kvm_vcpu *vcpus[2];
110	struct kvm_vm *vm;
111
112	vm = create_vm(ARRAY_SIZE(vcpus), bsp_vcpu_id, vcpus);
113
114	run_vcpu(vcpus[0]);
115	run_vcpu(vcpus[1]);
116
117	kvm_vm_free(vm);
118}
119
120static void check_set_bsp_busy(void)
121{
122	struct kvm_vcpu *vcpus[2];
123	struct kvm_vm *vm;
124
125	vm = create_vm(ARRAY_SIZE(vcpus), 0, vcpus);
126
127	test_set_bsp_busy(vcpus[1], "after adding vcpu");
128
129	run_vcpu(vcpus[0]);
130	run_vcpu(vcpus[1]);
131
132	test_set_bsp_busy(vcpus[1], "to a terminated vcpu");
133
134	kvm_vm_free(vm);
135}
136
137int main(int argc, char *argv[])
138{
139	TEST_REQUIRE(kvm_has_cap(KVM_CAP_SET_BOOT_CPU_ID));
140
141	run_vm_bsp(0);
142	run_vm_bsp(1);
143	run_vm_bsp(0);
144
145	check_set_bsp_busy();
146}
~/ Read-only file preview.