Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions arch/riscv/kvm/vcpu_sbi_sta.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ static int kvm_sbi_ext_sta_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num,
unsigned long reg_size, const void *reg_val)
{
unsigned long value;
gpa_t new_shmem = INVALID_GPA;

if (reg_size != sizeof(unsigned long))
return -EINVAL;
Expand All @@ -191,18 +192,18 @@ static int kvm_sbi_ext_sta_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num,
if (IS_ENABLED(CONFIG_32BIT)) {
gpa_t hi = upper_32_bits(vcpu->arch.sta.shmem);

vcpu->arch.sta.shmem = value;
vcpu->arch.sta.shmem |= hi << 32;
new_shmem = value;
new_shmem |= hi << 32;
} else {
vcpu->arch.sta.shmem = value;
new_shmem = value;
}
break;
case KVM_REG_RISCV_SBI_STA_REG(shmem_hi):
if (IS_ENABLED(CONFIG_32BIT)) {
gpa_t lo = lower_32_bits(vcpu->arch.sta.shmem);

vcpu->arch.sta.shmem = ((gpa_t)value << 32);
vcpu->arch.sta.shmem |= lo;
new_shmem = ((gpa_t)value << 32);
new_shmem |= lo;
} else if (value != 0) {
return -EINVAL;
}
Expand All @@ -211,6 +212,11 @@ static int kvm_sbi_ext_sta_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num,
return -ENOENT;
}

if (new_shmem != INVALID_GPA && !IS_ALIGNED(new_shmem, 64))
return -EINVAL;

vcpu->arch.sta.shmem = new_shmem;

return 0;
}

Expand Down
2 changes: 2 additions & 0 deletions tools/testing/selftests/kvm/include/kvm_util_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@
typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */
typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */

#define INVALID_GPA (~(uint64_t)0)

#endif /* SELFTEST_KVM_UTIL_TYPES_H */
98 changes: 82 additions & 16 deletions tools/testing/selftests/kvm/steal_time.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,10 @@ static bool is_steal_time_supported(struct kvm_vcpu *vcpu)

static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i)
{
int ret;

/* ST_GPA_BASE is identity mapped */
st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
sync_global_to_guest(vcpu->vm, st_gva[i]);

ret = _vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME,
(ulong)st_gva[i] | KVM_STEAL_RESERVED_MASK);
TEST_ASSERT(ret == 0, "Bad GPA didn't fail");

vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED);
}

Expand All @@ -99,6 +93,21 @@ static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
st->pad[8], st->pad[9], st->pad[10]);
}

static void check_steal_time_uapi(void)
{
struct kvm_vm *vm;
struct kvm_vcpu *vcpu;
int ret;

vm = vm_create_with_one_vcpu(&vcpu, NULL);

ret = _vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME,
(ulong)ST_GPA_BASE | KVM_STEAL_RESERVED_MASK);
TEST_ASSERT(ret == 0, "Bad GPA didn't fail");

kvm_vm_free(vm);
}

#elif defined(__aarch64__)

/* PV_TIME_ST must have 64-byte alignment */
Expand Down Expand Up @@ -170,29 +179,19 @@ static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i)
{
struct kvm_vm *vm = vcpu->vm;
uint64_t st_ipa;
int ret;

struct kvm_device_attr dev = {
.group = KVM_ARM_VCPU_PVTIME_CTRL,
.attr = KVM_ARM_VCPU_PVTIME_IPA,
.addr = (uint64_t)&st_ipa,
};

vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev);

/* ST_GPA_BASE is identity mapped */
st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
sync_global_to_guest(vm, st_gva[i]);

st_ipa = (ulong)st_gva[i] | 1;
ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL");

st_ipa = (ulong)st_gva[i];
vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);

ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
TEST_ASSERT(ret == -1 && errno == EEXIST, "Set IPA twice without EEXIST");
}

static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
Expand All @@ -205,6 +204,36 @@ static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
ksft_print_msg(" st_time: %ld\n", st->st_time);
}

static void check_steal_time_uapi(void)
{
struct kvm_vm *vm;
struct kvm_vcpu *vcpu;
uint64_t st_ipa;
int ret;

vm = vm_create_with_one_vcpu(&vcpu, NULL);

struct kvm_device_attr dev = {
.group = KVM_ARM_VCPU_PVTIME_CTRL,
.attr = KVM_ARM_VCPU_PVTIME_IPA,
.addr = (uint64_t)&st_ipa,
};

vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev);

st_ipa = (ulong)ST_GPA_BASE | 1;
ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL");

st_ipa = (ulong)ST_GPA_BASE;
vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);

ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
TEST_ASSERT(ret == -1 && errno == EEXIST, "Set IPA twice without EEXIST");

kvm_vm_free(vm);
}

#elif defined(__riscv)

/* SBI STA shmem must have 64-byte alignment */
Expand Down Expand Up @@ -301,6 +330,41 @@ static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
pr_info("\n");
}

static void check_steal_time_uapi(void)
{
struct kvm_vm *vm;
struct kvm_vcpu *vcpu;
struct kvm_one_reg reg;
uint64_t shmem;
int ret;

vm = vm_create_with_one_vcpu(&vcpu, NULL);

reg.id = KVM_REG_RISCV |
KVM_REG_SIZE_ULONG |
KVM_REG_RISCV_SBI_STATE |
KVM_REG_RISCV_SBI_STA |
KVM_REG_RISCV_SBI_STA_REG(shmem_lo);
reg.addr = (uint64_t)&shmem;

shmem = ST_GPA_BASE + 1;
ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, &reg);
TEST_ASSERT(ret == -1 && errno == EINVAL,
"misaligned STA shmem returns -EINVAL");

shmem = ST_GPA_BASE;
ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, &reg);
TEST_ASSERT(ret == 0,
"aligned STA shmem succeeds");

shmem = INVALID_GPA;
ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, &reg);
TEST_ASSERT(ret == 0,
"all-ones for STA shmem succeeds");

kvm_vm_free(vm);
}

#endif

static void *do_steal_time(void *arg)
Expand Down Expand Up @@ -369,6 +433,8 @@ int main(int ac, char **av)
TEST_REQUIRE(is_steal_time_supported(vcpus[0]));
ksft_set_plan(NR_VCPUS);

check_steal_time_uapi();

/* Run test on each VCPU */
for (i = 0; i < NR_VCPUS; ++i) {
steal_time_init(vcpus[i], i);
Expand Down