1 // SPDX-License-Identifier: GPL-2.0
3 * Test that KVM_SET_BOOT_CPU_ID works as intended
5 * Copyright (C) 2020, Red Hat, Inc.
7 #define _GNU_SOURCE /* for program_invocation_name */
12 #include <sys/ioctl.h>
14 #include "test_util.h"
16 #include "processor.h"
19 static void guest_bsp_vcpu(void *arg)
23 GUEST_ASSERT(get_bsp_flag() != 0);
28 static void guest_not_bsp_vcpu(void *arg)
32 GUEST_ASSERT(get_bsp_flag() == 0);
37 static void test_set_bsp_busy(struct kvm_vcpu *vcpu, const char *msg)
39 int r = __vm_ioctl(vcpu->vm, KVM_SET_BOOT_CPU_ID,
40 (void *)(unsigned long)vcpu->id);
42 TEST_ASSERT(r == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set %s", msg);
45 static void run_vcpu(struct kvm_vcpu *vcpu)
50 for (stage = 0; stage < 2; stage++) {
54 switch (get_ucall(vcpu, &uc)) {
56 TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
57 uc.args[1] == stage + 1,
58 "Stage %d: Unexpected register values vmexit, got %lx",
59 stage + 1, (ulong)uc.args[1]);
60 test_set_bsp_busy(vcpu, "while running vm");
63 TEST_ASSERT(stage == 1,
64 "Expected GUEST_DONE in stage 2, got stage %d",
68 TEST_ASSERT(false, "%s at %s:%ld\n\tvalues: %#lx, %#lx",
69 (const char *)uc.args[0], __FILE__,
70 uc.args[1], uc.args[2], uc.args[3]);
72 TEST_ASSERT(false, "Unexpected exit: %s",
73 exit_reason_str(vcpu->run->exit_reason));
78 static struct kvm_vm *create_vm(uint32_t nr_vcpus, uint32_t bsp_vcpu_id,
79 struct kvm_vcpu *vcpus[])
81 uint64_t vcpu_pages = (DEFAULT_STACK_PGS) * nr_vcpus;
82 uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * nr_vcpus;
83 uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages;
87 vm = vm_create(pages);
89 vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(unsigned long)bsp_vcpu_id);
91 for (i = 0; i < nr_vcpus; i++)
92 vcpus[i] = vm_vcpu_add(vm, i, i == bsp_vcpu_id ? guest_bsp_vcpu :
97 static void run_vm_bsp(uint32_t bsp_vcpu_id)
99 struct kvm_vcpu *vcpus[2];
102 vm = create_vm(ARRAY_SIZE(vcpus), bsp_vcpu_id, vcpus);
110 static void check_set_bsp_busy(void)
112 struct kvm_vcpu *vcpus[2];
115 vm = create_vm(ARRAY_SIZE(vcpus), 0, vcpus);
117 test_set_bsp_busy(vcpus[1], "after adding vcpu");
122 test_set_bsp_busy(vcpus[1], "to a terminated vcpu");
127 int main(int argc, char *argv[])
129 if (!kvm_check_cap(KVM_CAP_SET_BOOT_CPU_ID)) {
130 print_skip("set_boot_cpu_id not available");
138 check_set_bsp_busy();