From patchwork Wed Jun 7 22:45:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lewis X-Patchwork-Id: 13271435 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F1FE4C7EE23 for ; Wed, 7 Jun 2023 22:45:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232902AbjFGWp3 (ORCPT ); Wed, 7 Jun 2023 18:45:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50780 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230479AbjFGWp1 (ORCPT ); Wed, 7 Jun 2023 18:45:27 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0626119AC for ; Wed, 7 Jun 2023 15:45:27 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-bb39aebdd87so128831276.0 for ; Wed, 07 Jun 2023 15:45:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1686177926; x=1688769926; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=1+MCqRHVNOx8W0kVp/VmN1Saomw+ZEFw4eyiGWfCUqk=; b=NPTep/eSq/8ePDH5Ce7IvCAKq8+wE6+eAcPZUxUU1JodNoE1DBdE9hasFa5OX20dIk p+CAvcoGml3CZLXA6gg7ZxrBivhsGWDztx3hNPwrXVLUXX3fGuqAzLJ3DkgeF6A9eCS3 R+tQ+g5KLe4tPXhhL/5t7sFai+NWihGKmBWQsDlMy7bqoBGw0QcZfSlGdZRFs8HjnGzm MohmsFG0GpvJ/RlskUq7llqm7gI0VkN4Ce5KekHhbmK468/AmotHQa/TYY5UjxsVuB8A tLNxfwAgi0jdfdo6q/bntl6o2oL2/tJHKOWLenRWxd/7mtLp+BE6V8EmtB/kSic29y2W 65jQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686177926; x=1688769926; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=1+MCqRHVNOx8W0kVp/VmN1Saomw+ZEFw4eyiGWfCUqk=; b=BrVV+SKbo2wbNqYqL2zW7lGL2LlUtA2JmO1b7j7zz/i4ZY2abVz8kP+w1w36SKXyEC T/d0ffUIN9ohMTRvziek2rv4P9FWwlcS5c++cUZs0/8S9qUxajnQp3EA7Q5scFMiOZFH 7+X3WIEapiABUdCrNJ2Ani4N9cynK50NsHa1IdUvSTw42uQbnpFjKoCQlCEP6cYuhnJZ vt9FfbUD0zyQYO5khqk80UhOOgNluPp1FRF1pAbhjAbCdepDfDI7GtlPHbsjwbDUaBGo LzZR1aMsa4ckZlbbhbXg6woKR/W/EHXCyLIjzOtVPdrUgbDUn/4mHYhd0uyA8syYDARI YTMg== X-Gm-Message-State: AC+VfDwhVqKUw2JWJFUbHGiNazxoqK72v7/gL5ctvY+X55Yuhog3IuzH t1JxuatZ8ZP2Sf2lLEJmY9f5GksnCdmvtiQ1EP/UqTndDrO7PiiZHSHv24366tnXJCMchhRv8fV fsD+Sw4zmDxZ1IZsx2A1AvWNJySBwfUwx8BhPEeDxdLTU7EZTonuxQSGz34GXqMjwS1y6 X-Google-Smtp-Source: ACHHUZ5/pC61pIo71Xy5814qFBDhuiVbOKRtzTXhNZWRQwz6wuog8bNqIfKBWIZG67J0HTA4XRY997jNaFrOV3AM X-Received: from aaronlewis-2.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:519c]) (user=aaronlewis job=sendgmr) by 2002:a05:6902:1826:b0:bac:adb9:40b7 with SMTP id cf38-20020a056902182600b00bacadb940b7mr245111ybb.5.1686177926213; Wed, 07 Jun 2023 15:45:26 -0700 (PDT) Date: Wed, 7 Jun 2023 22:45:16 +0000 In-Reply-To: <20230607224520.4164598-1-aaronlewis@google.com> Mime-Version: 1.0 References: <20230607224520.4164598-1-aaronlewis@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230607224520.4164598-2-aaronlewis@google.com> Subject: [PATCH v3 1/5] KVM: selftests: Add strnlen() to the string overrides From: Aaron Lewis To: kvm@vger.kernel.org Cc: pbonzini@redhat.com, jmattson@google.com, seanjc@google.com, Aaron Lewis Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add strnlen() to the string overrides to allow it to be called in the guest. The implementation for strnlen() was taken from the kernel's generic version, lib/string.c. This will be needed when printf() is introduced. Signed-off-by: Aaron Lewis --- tools/testing/selftests/kvm/Makefile | 1 + tools/testing/selftests/kvm/lib/string_override.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index ee41ff0c5a86..adbf94cbc67e 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -200,6 +200,7 @@ endif CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \ -Wno-gnu-variable-sized-type-not-at-end \ -fno-builtin-memcmp -fno-builtin-memcpy -fno-builtin-memset \ + -fno-builtin-strnlen \ -fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \ -I$(LINUX_TOOL_ARCH_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude \ -I$( X-Patchwork-Id: 13271436 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4DC2BC7EE23 for ; Wed, 7 Jun 2023 22:45:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232978AbjFGWpa (ORCPT ); Wed, 7 Jun 2023 18:45:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50788 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230479AbjFGWp3 (ORCPT ); Wed, 7 Jun 2023 18:45:29 -0400 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5584E19AC for ; Wed, 7 Jun 2023 15:45:28 -0700 (PDT) Received: by mail-pg1-x54a.google.com with SMTP id 41be03b00d2f7-528ab7097afso6875824a12.1 for ; Wed, 07 Jun 2023 15:45:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1686177928; x=1688769928; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8LMsdweGtjazuBg5g5mPUO7EVRtXft0hLcztlezlTzI=; b=RDh9x/Bj8VCgWH+1cb/sncXTGcXbUL1Xhy2erVQYKOWJ2Z0meiQXFzyAiSJ6YUQagg 3OkV4ERvcdWm3S5VuiY26+i6a78Bu7xt7TNujJRM3ZDnLkX/ksmswhzDKSHSgcuBu+48 VcWfshZ5LLZAW/r8qGE93/CERnnKhBnEV88ajPWbHpze3VFNzIhAUZikncz+pNUSoNw7 sLLJohLyQxfszkc9nBeHcWf0nPqIRxi2jkzRi2LoxgFODUT+yjTkzfSVm6mBWcTd0ynX UVQPPoBFGgqlZ6/BLyzxXu1oovzzQ2hvy7cxL0o4c+ja1Hfg6eWk9DRqVjctJjbx+7Ek S/KQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686177928; x=1688769928; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8LMsdweGtjazuBg5g5mPUO7EVRtXft0hLcztlezlTzI=; b=ETZui5N2aTFIl2EoDX/qwHWi7NZ+QOYiDWO5xsuH2Qj/G7fcbYh7Mel8c48PfYXR8m cJBT+CLtnRh905F6Nv1WZjDQkS2gq6shrePHHMS5CX1EYdNMV8cahvzCXEI5hclpO49x zsQd3W64vBWzcHkX6kY5rIxkS6CXiv+Z7lJ+qsVcSGYR3gBs4wevoa5BDbrvdd1FOZL0 3gP0lZxiMEulC6Y3zNi50Q8cfcdGtketitQ9g0Uq069vdVkB5lChnW1HynsOrT7EaNU0 1gxlbbiK9pfQfWfunn5sOQCDr4ZJqSPdWbT75HK99d4D7yXHueonFwM302hHbS9//mvK w2bA== X-Gm-Message-State: AC+VfDxIOm/716cn962iQSIrcRrQc8K5sSU8XKum7bFToY/VYEAXdrGi QBNpd+KoFN6GOuK2mJzXBfpcUtRA7d2vQyV9cKMR8FK6d17PKnOMzhmrz855Xl6VDZPrc4uKNb6 oqWGhC31dnkN5QeZaxHb4PJpwan42xJcd/MP+dtmhiosI6euu8Hg2F4ZRNAsiKXbcNl+b X-Google-Smtp-Source: ACHHUZ6L1lgws8x1fKeTDpJhBYd6TbHLB/bSmW/bUm3evRPTTOjLUc6fA/LE/DvBwQF5Kc7ARAlFodDNDYc5fQ3b X-Received: from aaronlewis-2.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:519c]) (user=aaronlewis job=sendgmr) by 2002:a65:408d:0:b0:52c:999a:fce2 with SMTP id t13-20020a65408d000000b0052c999afce2mr1519992pgp.10.1686177927694; Wed, 07 Jun 2023 15:45:27 -0700 (PDT) Date: Wed, 7 Jun 2023 22:45:17 +0000 In-Reply-To: <20230607224520.4164598-1-aaronlewis@google.com> Mime-Version: 1.0 References: <20230607224520.4164598-1-aaronlewis@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230607224520.4164598-3-aaronlewis@google.com> Subject: [PATCH v3 2/5] KVM: selftests: Add guest_snprintf() to KVM selftests From: Aaron Lewis To: kvm@vger.kernel.org Cc: pbonzini@redhat.com, jmattson@google.com, seanjc@google.com, Aaron Lewis Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add a local version of guest_snprintf() for use in the guest. Having a local copy allows the guest access to string formatting options without dependencies on LIBC. LIBC is problematic because it heavily relies on both AVX-512 instructions and a TLS, neither of which are guaranteed to be set up in the guest. The file guest_sprintf.c was lifted from arch/x86/boot/printf.c and adapted to work in the guest, including the addition of buffer length. I.e. s/sprintf/snprintf/ The functions where prefixed with "guest_" to allow guests to explicitly call them. A string formatted by this function is expected to succeed or die. If something goes wrong during the formatting process a GUEST_ASSERT() will be thrown. Signed-off-by: Aaron Lewis --- tools/testing/selftests/kvm/Makefile | 1 + .../testing/selftests/kvm/include/test_util.h | 3 + .../testing/selftests/kvm/lib/guest_sprintf.c | 307 ++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 tools/testing/selftests/kvm/lib/guest_sprintf.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index adbf94cbc67e..efbe7e6d8f9b 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -23,6 +23,7 @@ LIBKVM += lib/guest_modes.c LIBKVM += lib/io.c LIBKVM += lib/kvm_util.c LIBKVM += lib/memstress.c +LIBKVM += lib/guest_sprintf.c LIBKVM += lib/rbtree.c LIBKVM += lib/sparsebit.c LIBKVM += lib/test_util.c diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index a6e9f215ce70..89ecacec328a 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -186,4 +186,7 @@ static inline uint32_t atoi_non_negative(const char *name, const char *num_str) return num; } +int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args); +int guest_snprintf(char *buf, int n, const char *fmt, ...); + #endif /* SELFTEST_KVM_TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/lib/guest_sprintf.c b/tools/testing/selftests/kvm/lib/guest_sprintf.c new file mode 100644 index 000000000000..c4a69d8aeb68 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/guest_sprintf.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "test_util.h" +#include "kvm_util.h" +#include "ucall_common.h" + +#define APPEND_BUFFER_SAFE(str, end, v) \ +do { \ + GUEST_ASSERT(str < end); \ + *str++ = (v); \ +} while (0) + +static int isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +static int skip_atoi(const char **s) +{ + int i = 0; + + while (isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SMALL 32 /* Must be 32 == 0x20 */ +#define SPECIAL 64 /* 0x */ + +#define __do_div(n, base) \ +({ \ + int __res; \ + \ + __res = ((uint64_t) n) % (uint32_t) base; \ + n = ((uint64_t) n) / (uint32_t) base; \ + __res; \ +}) + +static char *number(char *str, const char *end, long num, int base, int size, + int precision, int type) +{ + /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ + static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ + + char tmp[66]; + char c, sign, locase; + int i; + + /* + * locase = 0 or 0x20. ORing digits or letters with 'locase' + * produces same digits or (maybe lowercased) letters + */ + locase = (type & SMALL); + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 16) + return NULL; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++] = '0'; + else + while (num != 0) + tmp[i++] = (digits[__do_div(num, base)] | locase); + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + if (sign) + APPEND_BUFFER_SAFE(str, end, sign); + if (type & SPECIAL) { + if (base == 8) + APPEND_BUFFER_SAFE(str, end, '0'); + else if (base == 16) { + APPEND_BUFFER_SAFE(str, end, '0'); + APPEND_BUFFER_SAFE(str, end, 'x'); + } + } + if (!(type & LEFT)) + while (size-- > 0) + APPEND_BUFFER_SAFE(str, end, c); + while (i < precision--) + APPEND_BUFFER_SAFE(str, end, '0'); + while (i-- > 0) + APPEND_BUFFER_SAFE(str, end, tmp[i]); + while (size-- > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + + return str; +} + +int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args) +{ + char *str, *end; + const char *s; + uint64_t num; + int i, base; + int len; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* + * min. # of digits for integers; max + * number of chars for from string + */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + end = buf + n; + GUEST_ASSERT(buf < end); + GUEST_ASSERT(n > 0); + + for (str = buf; *fmt; ++fmt) { + if (*fmt != '%') { + APPEND_BUFFER_SAFE(str, end, *fmt); + continue; + } + + /* process flags */ + flags = 0; +repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + APPEND_BUFFER_SAFE(str, end, + (uint8_t)va_arg(args, int)); + while (--field_width > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + APPEND_BUFFER_SAFE(str, end, ' '); + for (i = 0; i < len; ++i) + APPEND_BUFFER_SAFE(str, end, *s++); + while (len < field_width--) + APPEND_BUFFER_SAFE(str, end, ' '); + continue; + + case 'p': + if (field_width == -1) { + field_width = 2 * sizeof(void *); + flags |= SPECIAL | SMALL | ZEROPAD; + } + str = number(str, end, + (uint64_t)va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + case 'n': + if (qualifier == 'l') { + long *ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int *ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + APPEND_BUFFER_SAFE(str, end, '%'); + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'x': + flags |= SMALL; + case 'X': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + APPEND_BUFFER_SAFE(str, end, '%'); + if (*fmt) + APPEND_BUFFER_SAFE(str, end, *fmt); + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, uint64_t); + else if (qualifier == 'h') { + num = (uint16_t)va_arg(args, int); + if (flags & SIGN) + num = (int16_t)num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, uint32_t); + str = number(str, end, num, base, field_width, precision, flags); + } + + GUEST_ASSERT(str < end); + *str = '\0'; + return str - buf; +} + +int guest_snprintf(char *buf, int n, const char *fmt, ...) +{ + va_list va; + int len; + + va_start(va, fmt); + len = guest_vsnprintf(buf, n, fmt, va); + va_end(va); + + return len; +} From patchwork Wed Jun 7 22:45:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lewis X-Patchwork-Id: 13271437 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 119E1C7EE25 for ; Wed, 7 Jun 2023 22:45:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233007AbjFGWpd (ORCPT ); Wed, 7 Jun 2023 18:45:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50800 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232995AbjFGWpb (ORCPT ); Wed, 7 Jun 2023 18:45:31 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1026B1BCE for ; Wed, 7 Jun 2023 15:45:30 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id 41be03b00d2f7-53feeb13975so3104497a12.0 for ; Wed, 07 Jun 2023 15:45:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1686177929; x=1688769929; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=vHN1EB9Pz0wYRGAClVk5phIwLmb5scjxhf2nuPTbv8E=; b=UZb133IrKwO1aXFhHgSOeibmNQGQhT29PTXfI5vi18qVzF14egC/FKhZUCGdfig5pD qRS6jQT/ny+83XL04h+D6VMidCSZaLT+j6M/JqZDFywOmZLtGdsCLOapT3srnna1o9Sy D3RMSMm7f6PYMRhBvNbRfUjaiEzX0x7qDSrv4daFSYvAz9RbwExdn4cNCV+uroZPHEZk jXZz93gZZ41Dn/YjEG+oD3fpy4N1OzRdvUjfvQHUt/bSdLeSUQl+i2+SFahavugthstE hoABwHnZOHFnoxEHL/S4SMdlObXdbCWV2f3MfyxfMSTiPqW5/brQIFxEAHgCBiyi9+vu oCKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686177929; x=1688769929; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=vHN1EB9Pz0wYRGAClVk5phIwLmb5scjxhf2nuPTbv8E=; b=RSRKtB5q7taHxZptmjd/UYQRSg4hrnpKdDEP51wDOcSLyrEodKbRZ01r6rRAfRU3ic wNPMsmCs704HNcNPBke1VwYEixBtnSFIG4//OpU7faZD588KEfKAtlg4A7TYdVSAjvn9 oZf++Md6LOlJB46/+/EnqcGiYv3isWfjzrHxfP/WOcUiYN8oQI3SdkjxJXNV/cXDImt0 4Xy9Y6yIPWscIR7yoKjo8BUrpn3Q45uqEU1OeMmEU3/NGW6+xOJJUJ4ct7ZbpOp0wME8 vD5LEBHk9xIac/t1g1SSHv6wGHvvzVmeqOB8A8j8FgTB35uNOO1jZvyjXc/d4i1sIU8b awyg== X-Gm-Message-State: AC+VfDx9BOKeD3iJoR+TH01dGLq+JPdEyN1DNi+8lmRQuYUjLU3bj/EI i9HrZ6r59SMcns/VPDE7QmGlhoOjggNi75EoJgsxxIWSliFNxOcQYJaBuGxF8Vm6xuNSODhIdZ5 z8eLj2ucBf+1dXHMdKh1hYr3OsUzXMmVZetaYIs40afTtD3SFU8/gGrdZaekGLoTYjsM8 X-Google-Smtp-Source: ACHHUZ6wEY7C9rr6apdqE1PzgttrSSN31BGvYJ1zy2VlsMN2QMpbRrS5gCqp3yyujUCtVyDmFxBkZHH/Ix7M2dY0 X-Received: from aaronlewis-2.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:519c]) (user=aaronlewis job=sendgmr) by 2002:a63:4c1b:0:b0:530:3a44:1581 with SMTP id z27-20020a634c1b000000b005303a441581mr1522106pga.9.1686177929443; Wed, 07 Jun 2023 15:45:29 -0700 (PDT) Date: Wed, 7 Jun 2023 22:45:18 +0000 In-Reply-To: <20230607224520.4164598-1-aaronlewis@google.com> Mime-Version: 1.0 References: <20230607224520.4164598-1-aaronlewis@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230607224520.4164598-4-aaronlewis@google.com> Subject: [PATCH v3 3/5] KVM: selftests: Add additional pages to the guest to accommodate ucall From: Aaron Lewis To: kvm@vger.kernel.org Cc: pbonzini@redhat.com, jmattson@google.com, seanjc@google.com, Aaron Lewis Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add additional pages to the guest to account for the number of pages the ucall headers need. The only reason things worked before is the ucall headers are fairly small. If they were ever to increase in size the guest could run out of memory. This is done in preparation for adding string formatting options to the guest through the ucall framework which increases the size of the ucall headers. Fixes: 426729b2cf2e ("KVM: selftests: Add ucall pool based implementation") Signed-off-by: Aaron Lewis --- tools/testing/selftests/kvm/include/ucall_common.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 4 ++++ tools/testing/selftests/kvm/lib/ucall_common.c | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 1a6aaef5ccae..bcbb362aa77f 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -34,6 +34,7 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu); void ucall(uint64_t cmd, int nargs, ...); uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc); void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa); +int ucall_nr_pages_required(uint64_t page_size); /* * Perform userspace call without any associated data. This bare call avoids diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 298c4372fb1a..80b3df2a79e6 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -312,6 +312,7 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus, uint64_t extra_mem_pages) { + uint64_t page_size = vm_guest_mode_params[mode].page_size; uint64_t nr_pages; TEST_ASSERT(nr_runnable_vcpus, @@ -340,6 +341,9 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, */ nr_pages += (nr_pages + extra_mem_pages) / PTES_PER_MIN_PAGE * 2; + /* Account for the number of pages needed by ucall. */ + nr_pages += ucall_nr_pages_required(page_size); + return vm_adjust_num_guest_pages(mode, nr_pages); } diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c index 2f0e2ea941cc..77ada362273d 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -11,6 +11,11 @@ struct ucall_header { struct ucall ucalls[KVM_MAX_VCPUS]; }; +int ucall_nr_pages_required(uint64_t page_size) +{ + return align_up(sizeof(struct ucall_header), page_size) / page_size; +} + /* * ucall_pool holds per-VM values (global data is duplicated by each VM), it * must not be accessed from host code. From patchwork Wed Jun 7 22:45:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lewis X-Patchwork-Id: 13271438 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C00BC7EE29 for ; Wed, 7 Jun 2023 22:45:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233018AbjFGWpe (ORCPT ); Wed, 7 Jun 2023 18:45:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50830 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233006AbjFGWpd (ORCPT ); Wed, 7 Jun 2023 18:45:33 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D453119AC for ; Wed, 7 Jun 2023 15:45:31 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-bb3855c34deso64831276.2 for ; Wed, 07 Jun 2023 15:45:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1686177931; x=1688769931; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=5rEtSIdYhwqCu9OuuuihNc8Xe1CSgOswix6v9nvhvk8=; b=L/Lfn0l4B3zv0mEaPgQpTGDF0klTBOu0dHp2wJsdgAVRzx2HVT6MHZ23MofMUCfgqq 9lugGsaNbp9aB4CVNCgT5U97p76JcSkYzAUvHaF+5KHbNLQf1urZMGPUSEOiXcGgXyFs G6h5LOK1cKe3hDNx7SaozhV3V53hPyrR+k9bOoTP6C8ixgpJoZnaqGrD7bnqHZKDFuW2 axSfKjkj7J3odt8cn0lefw4+yZqcFBALqYkPvuH6DbyH7qEem07Yj8ngsPa91+xu8jL2 i8TAlGaePYy1Oc9DOPbK/6IYfj164UMv8eFQ1d+FNc2zRkxt69nZaj5ZCDxLA+k4MAbX 0ClA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686177931; x=1688769931; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=5rEtSIdYhwqCu9OuuuihNc8Xe1CSgOswix6v9nvhvk8=; b=C1pC6Zhlf5lkwZl2LZDVHzJzKsAw+UvDDxC6jTHUqoBjupuFvUbEm54E97RysDRFgm L0rPq0kMbdxwv4orJz609UIqbXbpAiXXlI56jJTacC8XKfvQvcyS6FRQwMEjwmdkrs3g 7OuqCTE13A5xXgWHc/78IcdjaHr8i3yzz0nXHmnUGYacN6L8B8tNZsZhbY9hg18KkdgH wgMQHpgottV8xW8aQM/7Ct85PaKAIpuN86LISqYqEgOHtewK+v8uXRbceqtME/viWDH2 rMiF+BLq8dYTMQ8mBd2OImsF8hv0yWukxIMc5nuoutkP8eJUD/tijo127ZVPTfNQDyoW KRiw== X-Gm-Message-State: AC+VfDyaw3aQyA7t3vZ9ctDIlqpXz1SpybrI+XLKcbrtoBa6cvYBBI1K +jXxsVfpk1ZNAT/BvqA4yvnULEPv/0TKygd0S9AMpNsssKHDWYYF3RiceCy5xWCjA2hyXmf2/5l BENikX41DxCiolR96xzpaHr4lxSF+Jnp/cR/pawHVsnmdZ33VqTgRStrbdItmIvw6ilbf X-Google-Smtp-Source: ACHHUZ7XVbL8ikk3YBF/pBWsCukxBZxYsBANlVjVrz2Eru7Hqlo+AJlTC7nK6MDJb3r1EOPQiXFDoyyQz3eHvatn X-Received: from aaronlewis-2.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:519c]) (user=aaronlewis job=sendgmr) by 2002:a05:6902:1823:b0:bb1:446f:1d00 with SMTP id cf35-20020a056902182300b00bb1446f1d00mr3856521ybb.10.1686177931082; Wed, 07 Jun 2023 15:45:31 -0700 (PDT) Date: Wed, 7 Jun 2023 22:45:19 +0000 In-Reply-To: <20230607224520.4164598-1-aaronlewis@google.com> Mime-Version: 1.0 References: <20230607224520.4164598-1-aaronlewis@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230607224520.4164598-5-aaronlewis@google.com> Subject: [PATCH v3 4/5] KVM: selftests: Add string formatting options to ucall From: Aaron Lewis To: kvm@vger.kernel.org Cc: pbonzini@redhat.com, jmattson@google.com, seanjc@google.com, Aaron Lewis Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add more flexibility to guest debugging and testing by adding GUEST_PRINTF() and GUEST_ASSERT_FMT() to the ucall framework. A buffer to hold the formatted string was added to the ucall struct. That allows the guest/host to avoid the problem of passing an arbitrary number of parameters between themselves when resolving the string. Instead, the string is resolved in the guest then passed back to the host to be logged. The formatted buffer is set to 1024 bytes which increases the size of the ucall struct. As a result, this will increase the number of pages requested for the guest. The buffer size was chosen to accommodate most use cases, and based on similar usage. E.g. printf() uses the same size buffer in arch/x86/boot/printf.c. Signed-off-by: Aaron Lewis --- .../selftests/kvm/include/ucall_common.h | 23 +++++++++++++++++++ .../testing/selftests/kvm/lib/ucall_common.c | 17 ++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index bcbb362aa77f..b4f4c88e8d84 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -13,15 +13,18 @@ enum { UCALL_NONE, UCALL_SYNC, UCALL_ABORT, + UCALL_PRINTF, UCALL_DONE, UCALL_UNHANDLED, }; #define UCALL_MAX_ARGS 7 +#define UCALL_BUFFER_LEN 1024 struct ucall { uint64_t cmd; uint64_t args[UCALL_MAX_ARGS]; + char buffer[UCALL_BUFFER_LEN]; /* Host virtual address of this struct. */ struct ucall *hva; @@ -32,6 +35,7 @@ void ucall_arch_do_ucall(vm_vaddr_t uc); void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu); void ucall(uint64_t cmd, int nargs, ...); +void ucall_fmt(uint64_t cmd, const char *fmt, ...); uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc); void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa); int ucall_nr_pages_required(uint64_t page_size); @@ -47,8 +51,11 @@ int ucall_nr_pages_required(uint64_t page_size); #define GUEST_SYNC_ARGS(stage, arg1, arg2, arg3, arg4) \ ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4) #define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage) +#define GUEST_PRINTF(_fmt, _args...) ucall_fmt(UCALL_PRINTF, _fmt, ##_args) #define GUEST_DONE() ucall(UCALL_DONE, 0) +#define REPORT_GUEST_PRINTF(_ucall) pr_info("%s", _ucall.buffer) + enum guest_assert_builtin_args { GUEST_ERROR_STRING, GUEST_FILE, @@ -56,6 +63,20 @@ enum guest_assert_builtin_args { GUEST_ASSERT_BUILTIN_NARGS }; +#define __GUEST_ASSERT_FMT(_condition, _str, _fmt, _args...) \ +do { \ + char fmt[UCALL_BUFFER_LEN]; \ + \ + if (!(_condition)) { \ + guest_snprintf(fmt, sizeof(fmt), "%s\n %s", \ + "Failed guest assert: " _str " at %s:%ld", _fmt); \ + ucall_fmt(UCALL_ABORT, fmt, __FILE__, __LINE__, ##_args); \ + } \ +} while (0) + +#define GUEST_ASSERT_FMT(_condition, _fmt, _args...) \ + __GUEST_ASSERT_FMT(_condition, #_condition, _fmt, ##_args) + #define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) \ do { \ if (!(_condition)) \ @@ -81,6 +102,8 @@ do { \ #define GUEST_ASSERT_EQ(a, b) __GUEST_ASSERT((a) == (b), #a " == " #b, 2, a, b) +#define REPORT_GUEST_ASSERT_FMT(_ucall) TEST_FAIL("%s", _ucall.buffer) + #define __REPORT_GUEST_ASSERT(_ucall, fmt, _args...) \ TEST_FAIL("%s at %s:%ld\n" fmt, \ (const char *)(_ucall).args[GUEST_ERROR_STRING], \ diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c index 77ada362273d..b507db91139b 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -75,6 +75,23 @@ static void ucall_free(struct ucall *uc) clear_bit(uc - ucall_pool->ucalls, ucall_pool->in_use); } +void ucall_fmt(uint64_t cmd, const char *fmt, ...) +{ + struct ucall *uc; + va_list va; + + uc = ucall_alloc(); + uc->cmd = cmd; + + va_start(va, fmt); + guest_vsnprintf(uc->buffer, UCALL_BUFFER_LEN, fmt, va); + va_end(va); + + ucall_arch_do_ucall((vm_vaddr_t)uc->hva); + + ucall_free(uc); +} + void ucall(uint64_t cmd, int nargs, ...) { struct ucall *uc; From patchwork Wed Jun 7 22:45:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lewis X-Patchwork-Id: 13271439 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D8A27C7EE23 for ; Wed, 7 Jun 2023 22:45:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232995AbjFGWpg (ORCPT ); Wed, 7 Jun 2023 18:45:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233006AbjFGWpf (ORCPT ); Wed, 7 Jun 2023 18:45:35 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9E13719AC for ; Wed, 7 Jun 2023 15:45:33 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-5618857518dso99428057b3.2 for ; Wed, 07 Jun 2023 15:45:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1686177932; x=1688769932; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=PbLYX85Jw4PTnvI11+u9XMaO08Dmwhv2XueYByO8/58=; b=el9pUpgeYZJobuUfgNS1qiQJbL5h/Clv9lYkF0ovsbnHQ6Ue1ZrkTDSfOUubMXp3an TxJ3dNT9Y7fq2Vl8QTRuHk2oatgELR30nqbGRBFhhOsZkF+ty+lQcSl/nc4pe+n4gZeB Vgx/KewUAzUzD5Fr61ulYaXa5fv+zU8zWHN7DlkO1E8CdJdy59yQzBJvPcmp0c57WzH6 mNV+dgFZlg/q8+Ef9gRqp0UvNejdELbMF+a82XGXdE1oHjoM6WTB6XqdEVIWAsgQvFmS JDt5P2brqPWmQl39fHSdtTZzC1Z/vf0gokIRAfCTItT7fD3aiM+HJG2Cy62JSnLKJtpA 0q8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686177932; x=1688769932; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=PbLYX85Jw4PTnvI11+u9XMaO08Dmwhv2XueYByO8/58=; b=P3J+WmhYjFR4Ktn1np87qpAGfKPGobTQXkabBnl08NXXkLOc+EtY59D/RdjVEthUvn 6OiWMrz1NUnLjforgMGcx6PPgt3bUVLl4BdY25olvAeYk8zf/QGZYqhHZmmV3NqKpyYk LgpH1Vi/FsVMu60kAGmzGiS2wZjj7h1wTFqL6PDVj8qXXwU/7xVJeGdDIEfWv9kKzyuA kVXg4iEPUhYPnd3F7eygaVsSP/rdiJIE5sTSBBMh5vH2BtM3t4zXd8Ax3Uky2bg37KQK t0q7uGESlWaA+6pHxpzf3JTgHqtzKj0gSAgbk1jlvfR85d4BcRr4+SIDVni57VN+l6re AGlw== X-Gm-Message-State: AC+VfDxQria+ko1zKvdt4XD3NzO6s+8nJ9M1XGWVm6XcxCmeqKTCcUcc GhrdyPAk+CJ67gVv9PotpywNmZxx2YOe4KJ/EtbcthPQf7x1nBK3Ow3mKz4ghZRR3qNUZ2omaVm rLRZFwvNI8AcUCz1h9Bso0yiqLY1VNVOgE/LkMyfuGb3z9VgujRckugtZTj7er3mdQIY4 X-Google-Smtp-Source: ACHHUZ7AIIiAaYVMmlx33UJz7xyCMgqoe4mlFT+fTi1IhhlRSMEMUjKkLSC4MXaS5PnsTY6Lnr1MIH34v8iVwFd4 X-Received: from aaronlewis-2.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:519c]) (user=aaronlewis job=sendgmr) by 2002:a05:6902:1003:b0:ba8:2e69:9e06 with SMTP id w3-20020a056902100300b00ba82e699e06mr4018591ybt.1.1686177932688; Wed, 07 Jun 2023 15:45:32 -0700 (PDT) Date: Wed, 7 Jun 2023 22:45:20 +0000 In-Reply-To: <20230607224520.4164598-1-aaronlewis@google.com> Mime-Version: 1.0 References: <20230607224520.4164598-1-aaronlewis@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230607224520.4164598-6-aaronlewis@google.com> Subject: [PATCH v3 5/5] KVM: selftests: Add a selftest for guest prints and formatted asserts From: Aaron Lewis To: kvm@vger.kernel.org Cc: pbonzini@redhat.com, jmattson@google.com, seanjc@google.com, Aaron Lewis Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The purpose of this test is to exercise the various features in KVM's local snprintf() and compare them to LIBC's snprintf() to ensure they behave the same. This is not an exhaustive test. KVM's local snprintf() does not implement all the features LIBC does, e.g. KVM's local snprintf() does not support floats or doubles, so testing for those features were excluded. Testing was added for the features that are expected to work to support a minimal version of printf() in the guest. Signed-off-by: Aaron Lewis --- tools/testing/selftests/kvm/Makefile | 1 + .../testing/selftests/kvm/guest_print_test.c | 222 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 tools/testing/selftests/kvm/guest_print_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index efbe7e6d8f9b..85c35ea10ffd 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -122,6 +122,7 @@ TEST_GEN_PROGS_x86_64 += access_tracking_perf_test TEST_GEN_PROGS_x86_64 += demand_paging_test TEST_GEN_PROGS_x86_64 += dirty_log_test TEST_GEN_PROGS_x86_64 += dirty_log_perf_test +TEST_GEN_PROGS_x86_64 += guest_print_test TEST_GEN_PROGS_x86_64 += hardware_disable_test TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus TEST_GEN_PROGS_x86_64 += kvm_page_table_test diff --git a/tools/testing/selftests/kvm/guest_print_test.c b/tools/testing/selftests/kvm/guest_print_test.c new file mode 100644 index 000000000000..7dd0a36e23c2 --- /dev/null +++ b/tools/testing/selftests/kvm/guest_print_test.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A test for GUEST_PRINTF + * + * Copyright 2022, Google, Inc. and/or its affiliates. + */ + +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +struct guest_vals { + uint64_t a; + uint64_t b; + uint64_t type; +}; + +struct guest_vals vals; + +/* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */ +#define TYPE_LIST \ +TYPE(test_type_i64, I64, "%ld", int64_t) \ +TYPE(test_type_u64, U64u, "%lu", uint64_t) \ +TYPE(test_type_x64, U64x, "0x%lx", uint64_t) \ +TYPE(test_type_X64, U64X, "0x%lX", uint64_t) \ +TYPE(test_type_u32, U32u, "%u", uint32_t) \ +TYPE(test_type_x32, U32x, "0x%x", uint32_t) \ +TYPE(test_type_X32, U32X, "0x%X", uint32_t) \ +TYPE(test_type_int, INT, "%d", int) \ +TYPE(test_type_char, CHAR, "%c", char) \ +TYPE(test_type_str, STR, "'%s'", const char *) \ +TYPE(test_type_ptr, PTR, "%p", uintptr_t) + +enum args_type { +#define TYPE(fn, ext, fmt_t, T) TYPE_##ext, + TYPE_LIST +#undef TYPE +}; + +static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf, + const char *expected_assert); + +#define BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T) \ +const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t; \ +const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead"; \ +static void fn(struct kvm_vcpu *vcpu, T a, T b) \ +{ \ + char expected_printf[UCALL_BUFFER_LEN]; \ + char expected_assert[UCALL_BUFFER_LEN]; \ + \ + snprintf(expected_printf, UCALL_BUFFER_LEN, PRINTF_FMT_##ext, a, b); \ + snprintf(expected_assert, UCALL_BUFFER_LEN, ASSERT_FMT_##ext, a, b); \ + vals = (struct guest_vals){ (uint64_t)a, (uint64_t)b, TYPE_##ext }; \ + sync_global_to_guest(vcpu->vm, vals); \ + run_test(vcpu, expected_printf, expected_assert); \ +} + +#define TYPE(fn, ext, fmt_t, T) \ + BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T) + TYPE_LIST +#undef TYPE + +static void guest_code(void) +{ + while (1) { + switch (vals.type) { +#define TYPE(fn, ext, fmt_t, T) \ + case TYPE_##ext: \ + GUEST_PRINTF(PRINTF_FMT_##ext, vals.a, vals.b); \ + GUEST_ASSERT_FMT(vals.a == vals.b, \ + ASSERT_FMT_##ext, vals.a, vals.b); \ + break; + TYPE_LIST +#undef TYPE + default: + GUEST_SYNC(vals.type); + } + + GUEST_DONE(); + } +} + +/* + * Unfortunately this gets a little messy because 'assert_msg' doesn't + * just contains the matching string, it also contains additional assert + * info. Fortunately the part that matches should be at the very end of + * 'assert_msg'. + */ +static void ucall_abort(const char *assert_msg, const char *expected_assert_msg) +{ + int len_str = strlen(assert_msg); + int len_substr = strlen(expected_assert_msg); + int offset = len_str - len_substr; + + TEST_ASSERT(len_substr <= len_str, + "Expected to find a substring, len_str: %d, len_substr: %d", + len_str, len_substr); + + TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0, + "Unexpected mismatch. Expected: '%s', got: '%s'", + expected_assert_msg, &assert_msg[offset]); +} + +static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf, + const char *expected_assert) +{ + struct kvm_run *run = vcpu->run; + struct ucall uc; + + while (1) { + vcpu_run(vcpu); + + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]); + break; + case UCALL_PRINTF: + TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0, + "Unexpected mismatch. Expected: '%s', got: '%s'", + expected_printf, uc.buffer); + break; + case UCALL_ABORT: + ucall_abort(uc.buffer, expected_assert); + break; + case UCALL_DONE: + return; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + } +} + +static void guest_code_limits(void) +{ + char test_str[UCALL_BUFFER_LEN + 10]; + + memset(test_str, 'a', sizeof(test_str)); + test_str[sizeof(test_str) - 1] = 0; + + GUEST_PRINTF("%s", test_str); +} + +static void test_limits(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_run *run; + struct kvm_vm *vm; + struct ucall uc; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits); + run = vcpu->run; + vcpu_run(vcpu); + + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT, + "Unexpected ucall command: %lu, Expected: %u (UCALL_ABORT)\n", + uc.cmd, UCALL_ABORT); + + kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + + test_type_i64(vcpu, -1, -1); + test_type_i64(vcpu, -1, 1); + test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + + test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + + test_type_u32(vcpu, 0x90abcdef, 0x90abcdef); + test_type_u32(vcpu, 0x90abcdef, 0x90abcdee); + test_type_x32(vcpu, 0x90abcdef, 0x90abcdef); + test_type_x32(vcpu, 0x90abcdef, 0x90abcdee); + test_type_X32(vcpu, 0x90abcdef, 0x90abcdef); + test_type_X32(vcpu, 0x90abcdef, 0x90abcdee); + + test_type_int(vcpu, -1, -1); + test_type_int(vcpu, -1, 1); + test_type_int(vcpu, 1, 1); + + test_type_char(vcpu, 'a', 'a'); + test_type_char(vcpu, 'a', 'A'); + test_type_char(vcpu, 'a', 'b'); + + test_type_str(vcpu, "foo", "foo"); + test_type_str(vcpu, "foo", "bar"); + + test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + + kvm_vm_free(vm); + + test_limits(); + + return 0; +}