brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · bcf5828 Raw
236 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * A test for GUEST_PRINTF4 *5 * Copyright 2022, Google, Inc. and/or its affiliates.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 "ucall_common.h"17 18struct guest_vals {19	uint64_t a;20	uint64_t b;21	uint64_t type;22};23 24static struct guest_vals vals;25 26/* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */27#define TYPE_LIST					\28TYPE(test_type_i64,  I64,  "%ld",   int64_t)		\29TYPE(test_type_u64,  U64u, "%lu",   uint64_t)		\30TYPE(test_type_x64,  U64x, "0x%lx", uint64_t)		\31TYPE(test_type_X64,  U64X, "0x%lX", uint64_t)		\32TYPE(test_type_u32,  U32u, "%u",    uint32_t)		\33TYPE(test_type_x32,  U32x, "0x%x",  uint32_t)		\34TYPE(test_type_X32,  U32X, "0x%X",  uint32_t)		\35TYPE(test_type_int,  INT,  "%d",    int)		\36TYPE(test_type_char, CHAR, "%c",    char)		\37TYPE(test_type_str,  STR,  "'%s'",  const char *)	\38TYPE(test_type_ptr,  PTR,  "%p",    uintptr_t)39 40enum args_type {41#define TYPE(fn, ext, fmt_t, T) TYPE_##ext,42	TYPE_LIST43#undef TYPE44};45 46static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,47		     const char *expected_assert);48 49#define BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)		     \50const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t;    \51const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead";  \52static void fn(struct kvm_vcpu *vcpu, T a, T b)				     \53{									     \54	char expected_printf[UCALL_BUFFER_LEN];				     \55	char expected_assert[UCALL_BUFFER_LEN];				     \56									     \57	snprintf(expected_printf, UCALL_BUFFER_LEN, PRINTF_FMT_##ext, a, b); \58	snprintf(expected_assert, UCALL_BUFFER_LEN, ASSERT_FMT_##ext, a, b); \59	vals = (struct guest_vals){ (uint64_t)a, (uint64_t)b, TYPE_##ext };  \60	sync_global_to_guest(vcpu->vm, vals);				     \61	run_test(vcpu, expected_printf, expected_assert);		     \62}63 64#define TYPE(fn, ext, fmt_t, T) \65		BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)66	TYPE_LIST67#undef TYPE68 69static void guest_code(void)70{71	while (1) {72		switch (vals.type) {73#define TYPE(fn, ext, fmt_t, T)							\74		case TYPE_##ext:						\75			GUEST_PRINTF(PRINTF_FMT_##ext, vals.a, vals.b);		\76			__GUEST_ASSERT(vals.a == vals.b,			\77				       ASSERT_FMT_##ext, vals.a, vals.b);	\78			break;79		TYPE_LIST80#undef TYPE81		default:82			GUEST_SYNC(vals.type);83		}84 85		GUEST_DONE();86	}87}88 89/*90 * Unfortunately this gets a little messy because 'assert_msg' doesn't91 * just contains the matching string, it also contains additional assert92 * info.  Fortunately the part that matches should be at the very end of93 * 'assert_msg'.94 */95static void ucall_abort(const char *assert_msg, const char *expected_assert_msg)96{97	int len_str = strlen(assert_msg);98	int len_substr = strlen(expected_assert_msg);99	int offset = len_str - len_substr;100 101	TEST_ASSERT(len_substr <= len_str,102		    "Expected '%s' to be a substring of '%s'",103		    assert_msg, expected_assert_msg);104 105	TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0,106		    "Unexpected mismatch. Expected: '%s', got: '%s'",107		    expected_assert_msg, &assert_msg[offset]);108}109 110/*111 * Open code vcpu_run(), sans the UCALL_ABORT handling, so that intentional112 * guest asserts guest can be verified instead of being reported as failures.113 */114static void do_vcpu_run(struct kvm_vcpu *vcpu)115{116	int r;117 118	do {119		r = __vcpu_run(vcpu);120	} while (r == -1 && errno == EINTR);121 122	TEST_ASSERT(!r, KVM_IOCTL_ERROR(KVM_RUN, r));123}124 125static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,126		     const char *expected_assert)127{128	struct kvm_run *run = vcpu->run;129	struct ucall uc;130 131	while (1) {132		do_vcpu_run(vcpu);133 134		TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,135			    "Unexpected exit reason: %u (%s),",136			    run->exit_reason, exit_reason_str(run->exit_reason));137 138		switch (get_ucall(vcpu, &uc)) {139		case UCALL_SYNC:140			TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]);141			break;142		case UCALL_PRINTF:143			TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0,144				    "Unexpected mismatch. Expected: '%s', got: '%s'",145				    expected_printf, uc.buffer);146			break;147		case UCALL_ABORT:148			ucall_abort(uc.buffer, expected_assert);149			break;150		case UCALL_DONE:151			return;152		default:153			TEST_FAIL("Unknown ucall %lu", uc.cmd);154		}155	}156}157 158static void guest_code_limits(void)159{160	char test_str[UCALL_BUFFER_LEN + 10];161 162	memset(test_str, 'a', sizeof(test_str));163	test_str[sizeof(test_str) - 1] = 0;164 165	GUEST_PRINTF("%s", test_str);166}167 168static void test_limits(void)169{170	struct kvm_vcpu *vcpu;171	struct kvm_run *run;172	struct kvm_vm *vm;173	struct ucall uc;174 175	vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits);176	run = vcpu->run;177	do_vcpu_run(vcpu);178 179	TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,180		    "Unexpected exit reason: %u (%s),",181		    run->exit_reason, exit_reason_str(run->exit_reason));182 183	TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT,184		    "Unexpected ucall command: %lu,  Expected: %u (UCALL_ABORT)",185		    uc.cmd, UCALL_ABORT);186 187	kvm_vm_free(vm);188}189 190int main(int argc, char *argv[])191{192	struct kvm_vcpu *vcpu;193	struct kvm_vm *vm;194 195	vm = vm_create_with_one_vcpu(&vcpu, guest_code);196 197	test_type_i64(vcpu, -1, -1);198	test_type_i64(vcpu, -1,  1);199	test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);200	test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);201 202	test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);203	test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);204	test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);205	test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);206	test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);207	test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);208 209	test_type_u32(vcpu, 0x90abcdef, 0x90abcdef);210	test_type_u32(vcpu, 0x90abcdef, 0x90abcdee);211	test_type_x32(vcpu, 0x90abcdef, 0x90abcdef);212	test_type_x32(vcpu, 0x90abcdef, 0x90abcdee);213	test_type_X32(vcpu, 0x90abcdef, 0x90abcdef);214	test_type_X32(vcpu, 0x90abcdef, 0x90abcdee);215 216	test_type_int(vcpu, -1, -1);217	test_type_int(vcpu, -1,  1);218	test_type_int(vcpu,  1,  1);219 220	test_type_char(vcpu, 'a', 'a');221	test_type_char(vcpu, 'a', 'A');222	test_type_char(vcpu, 'a', 'b');223 224	test_type_str(vcpu, "foo", "foo");225	test_type_str(vcpu, "foo", "bar");226 227	test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);228	test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);229 230	kvm_vm_free(vm);231 232	test_limits();233 234	return 0;235}236