All of lore.kernel.org
 help / color / mirror / Atom feed
From: Richard Palethorpe <rpalethorpe@suse.de>
To: Martin Doucha <mdoucha@suse.cz>
Cc: ltp@lists.linux.it
Subject: Re: [LTP] [PATCH 1/2] KVM test infrastructure
Date: Tue, 15 Mar 2022 15:00:08 +0000	[thread overview]
Message-ID: <87k0cv5ij5.fsf@suse.de> (raw)
In-Reply-To: <20220309164954.23751-1-mdoucha@suse.cz>

Hi Martin,

Martin Doucha <mdoucha@suse.cz> writes:

> Implement LTP infrastructure for tests which require executing a special
> program inside KVM virtual machine. The infrastructure is split into two parts:
> the host library and the guest library.
>
> The host library provides functions for setting up and running virtual machines
> with test payload built from test sources.
>
> The guest library provides CPU bootstrap code and basic implementation of
> some C and LTP library functions as well as functions for accessing low-level
> arch features like special registers, interrupt tables or memory mapping tables.
>
> The test sources will contain both guest-side payload code and host-side setup
> code separated by preprocessor switch. The files get compiled twice with
> different compiler options. Once to build the VM payload, once to build
> the main program that will create the VM and execute the payload
> inside it.

This is great!

Due to its size I'll just comment as I get chance to read it.

> diff --git a/testcases/kernel/kvm/lib_host.c b/testcases/kernel/kvm/lib_host.c
> new file mode 100644
> index 000000000..d070c8106
> --- /dev/null
> +++ b/testcases/kernel/kvm/lib_host.c
> @@ -0,0 +1,215 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2021 SUSE LLC <mdoucha@suse.cz>
> + *
> + * KVM host library for setting up and running virtual machine tests.
> + */
> +
> +#include <stdlib.h>
> +#include <errno.h>
> +
> +#define TST_NO_DEFAULT_MAIN
> +#include "tst_test.h"
> +#include "kvm_host.h"
> +
> +static struct tst_kvm_instance test_vm = { .vm_fd = -1 };
> +
> +const unsigned char tst_kvm_reset_code[VM_RESET_CODE_SIZE] = {
> +	0xea, 0x00, 0x10, 0x00, 0x00	/* JMP 0x1000 */
> +};
> +
> +void tst_kvm_validate_result(int value)
> +{
> +	int ttype, valid_result[] = {TPASS, TFAIL, TBROK, TWARN, TINFO, TCONF};
> +	size_t i;
> +
> +	if (value == KVM_TNONE)
> +		tst_brk(TBROK, "KVM test did not return any result");
> +
> +	ttype = TTYPE_RESULT(value);
> +
> +	for (i = 0; i < ARRAY_SIZE(valid_result); i++) {
> +		if (ttype == valid_result[i])
> +			return;
> +	}
> +
> +	tst_brk(TBROK, "KVM test returned invalid result value %d", value);
> +}
> +
> +void tst_kvm_print_result(const struct tst_kvm_result *result)
> +{
> +	int ttype;
> +
> +	tst_kvm_validate_result(result->result);
> +	ttype = TTYPE_RESULT(result->result);
> +
> +	if (ttype == TBROK)
> +		tst_brk(ttype, "%s", result->message);
> +	else
> +		tst_res(ttype, "%s", result->message);
> +}

Could you please pass the file and lineno from the test?

> +
> +void *tst_kvm_alloc_memory(int vm, unsigned int slot, uint64_t baseaddr,
> +	size_t size, unsigned int flags)
> +{
> +	size_t pagesize;
> +	void *ret;
> +	struct kvm_userspace_memory_region memslot = {
> +		.slot = slot,
> +		.flags = flags
> +	};
> +
> +	pagesize = SAFE_SYSCONF(_SC_PAGESIZE);
> +	size += (baseaddr % pagesize) + pagesize - 1;
> +	baseaddr -= baseaddr % pagesize;
> +	size -= size % pagesize;
> +	ret = tst_alloc(size);
> +
> +	memslot.guest_phys_addr = baseaddr;
> +	memslot.memory_size = size;
> +	memslot.userspace_addr = (uintptr_t)ret;
> +	SAFE_IOCTL(vm, KVM_SET_USER_MEMORY_REGION, &memslot);
> +	return ret;
> +}
> +
> +struct kvm_cpuid2 *tst_kvm_get_cpuid(int sysfd)
> +{
> +	unsigned int count;
> +	int result;
> +	struct kvm_cpuid2 *ret;
> +
> +	if (!SAFE_IOCTL(sysfd, KVM_CHECK_EXTENSION, KVM_CAP_EXT_CPUID))
> +		return NULL;
> +
> +	for (count = 8; count < 1 << 30; count *= 2) {
> +		ret = SAFE_MALLOC(sizeof(struct kvm_cpuid2) +
> +			count * sizeof(struct kvm_cpuid_entry2));
> +		ret->nent = count;
> +		errno = 0;
> +		result = ioctl(sysfd, KVM_GET_SUPPORTED_CPUID, ret);
> +
> +		if (!result)
> +			return ret;
> +
> +		free(ret);
> +
> +		if (errno != E2BIG)
> +			break;
> +	}
> +
> +	tst_brk(TBROK | TERRNO, "ioctl(KVM_GET_SUPPORTED_CPUID) failed");
> +	return NULL;
> +}
> +
> +void tst_kvm_create_instance(struct tst_kvm_instance *inst, size_t ram_size)
> +{
> +	int sys_fd;
> +	size_t pagesize, result_pageaddr = KVM_RESULT_BASEADDR;
> +	char *vm_result, *reset_ptr;
> +	struct kvm_cpuid2 *cpuid_data;
> +	const size_t payload_size = kvm_payload_end - kvm_payload_start;
> +
> +	memset(inst, 0, sizeof(struct tst_kvm_instance));
> +	inst->vm_fd = -1;
> +	inst->vcpu_fd = -1;
> +	inst->vcpu_info = MAP_FAILED;
> +
> +	pagesize = SAFE_SYSCONF(_SC_PAGESIZE);
> +	result_pageaddr -= result_pageaddr % pagesize;
> +
> +	if (payload_size + MIN_FREE_RAM > ram_size - VM_KERNEL_BASEADDR) {
> +		ram_size = payload_size + MIN_FREE_RAM + VM_KERNEL_BASEADDR;
> +		ram_size += 1024 * 1024 - 1;
> +		ram_size -= ram_size % (1024 * 1024);
> +		tst_res(TWARN, "RAM size increased to %zu bytes", ram_size);
> +	}
> +
> +	if (ram_size > result_pageaddr) {
> +		ram_size = result_pageaddr;
> +		tst_res(TWARN, "RAM size truncated to %zu bytes", ram_size);
> +	}
> +
> +	/* Create VM */

These comments are pretty redundant when we have ioctl's like
KVM_CREATE_VM and KVM_CREATE_VCPU. There are much harder things to
understand in this patchset.

> +	sys_fd = SAFE_OPEN("/dev/kvm", O_RDWR);
> +	inst->vcpu_info_size = SAFE_IOCTL(sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
> +	inst->vm_fd = SAFE_IOCTL(sys_fd, KVM_CREATE_VM, 0);
> +	cpuid_data = tst_kvm_get_cpuid(sys_fd);
> +	SAFE_CLOSE(sys_fd);
> +
> +	/* Create virtual CPU */
> +	inst->vcpu_fd = SAFE_IOCTL(inst->vm_fd, KVM_CREATE_VCPU, 0);
> +
> +	if (cpuid_data) {
> +		SAFE_IOCTL(inst->vcpu_fd, KVM_SET_CPUID2, cpuid_data);
> +		free(cpuid_data);
> +	}
> +
> +	inst->vcpu_info = SAFE_MMAP(NULL, inst->vcpu_info_size,
> +		PROT_READ | PROT_WRITE, MAP_SHARED, inst->vcpu_fd, 0);
> +
> +	/* Set VM memory banks and install test program */
> +	inst->ram = tst_kvm_alloc_memory(inst->vm_fd, 0, 0, ram_size, 0);
> +	vm_result = tst_kvm_alloc_memory(inst->vm_fd, 1, KVM_RESULT_BASEADDR,
> +		KVM_RESULT_SIZE, 0);
> +	memset(vm_result, 0, KVM_RESULT_SIZE);
> +	memcpy(inst->ram + VM_KERNEL_BASEADDR, kvm_payload_start, payload_size);
> +
> +	reset_ptr = vm_result + (VM_RESET_BASEADDR % pagesize);
> +	memcpy(reset_ptr, tst_kvm_reset_code, sizeof(tst_kvm_reset_code));
> +	inst->result = (struct tst_kvm_result *)(vm_result +
> +		(KVM_RESULT_BASEADDR % pagesize));
> +	inst->result->result = KVM_TNONE;
> +	inst->result->message[0] = '\0';
> +}
> +
> +void tst_kvm_run_instance(struct tst_kvm_instance *inst)
> +{
> +	struct kvm_regs regs;
> +
> +	while (1) {
> +		inst->result->result = KVM_TNONE;
> +		inst->result->message[0] = '\0';
> +		SAFE_IOCTL(inst->vcpu_fd, KVM_RUN, 0);
> +
> +		if (inst->vcpu_info->exit_reason != KVM_EXIT_HLT) {
> +			SAFE_IOCTL(inst->vcpu_fd, KVM_GET_REGS, &regs);
> +			tst_brk(TBROK,
> +				"Unexpected VM exit, RIP=0x%llx, reason=%u",
> +				regs.rip, inst->vcpu_info->exit_reason);
> +		}
> +
> +		if (inst->result->result == KVM_TEXIT)
> +			break;
> +
> +		tst_kvm_print_result(inst->result);
> +	}
> +}
> +
> +void tst_kvm_destroy_instance(struct tst_kvm_instance *inst)
> +{
> +	if (inst->vm_fd < 0)
> +		return;
> +
> +	if (inst->vcpu_info != MAP_FAILED)
> +		SAFE_MUNMAP(inst->vcpu_info, inst->vcpu_info_size);
> +
> +	if (inst->vcpu_fd >= 0)
> +		SAFE_CLOSE(inst->vcpu_fd);
> +
> +	SAFE_CLOSE(inst->vm_fd);
> +}
> +
> +void tst_kvm_setup(void)
> +{
> +	tst_kvm_create_instance(&test_vm, DEFAULT_RAM_SIZE);
> +}
> +
> +void tst_kvm_run(void)
> +{
> +	tst_kvm_run_instance(&test_vm);
> +}
> +
> +void tst_kvm_cleanup(void)
> +{
> +	tst_kvm_destroy_instance(&test_vm);
> +}

-- 
Thank you,
Richard.

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

  parent reply	other threads:[~2022-03-15 15:42 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-09 16:49 [LTP] [PATCH 1/2] KVM test infrastructure Martin Doucha
2022-03-09 16:49 ` [LTP] [PATCH 2/2] Add test for CVE 2021-38198 Martin Doucha
2022-03-15 14:19   ` Richard Palethorpe
2022-03-15 15:04     ` Martin Doucha
2022-03-15 15:44       ` Richard Palethorpe
2022-03-15 16:14         ` Martin Doucha
2022-03-17  7:35           ` Richard Palethorpe
2022-03-17 11:55             ` Martin Doucha
2022-03-09 19:13 ` [LTP] [PATCH 1/2] KVM test infrastructure Petr Vorel
2022-03-10 14:10   ` Martin Doucha
2022-03-10 20:41     ` Petr Vorel
2022-03-15 15:00 ` Richard Palethorpe [this message]
2022-03-16 17:03   ` Martin Doucha
2022-03-17  7:59     ` Richard Palethorpe
2022-03-17  8:16     ` Li Wang
2022-03-17 10:42   ` Richard Palethorpe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87k0cv5ij5.fsf@suse.de \
    --to=rpalethorpe@suse.de \
    --cc=ltp@lists.linux.it \
    --cc=mdoucha@suse.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.