From patchwork Sat Jul 29 00:36:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Christopherson X-Patchwork-Id: 13332804 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2E008EB64DD for ; Sat, 29 Jul 2023 00:37:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:Reply-To:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:Message-ID :References:Mime-Version:In-Reply-To:Date:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=9uJOccOAJp90KZ/oCFOGwA+1i4s+IPmOcEKG+U4ckNk=; b=ARM4qt/QWJ/C5K eciKRT7ysU4u37lwAO2eU1XYcY07bV3pYjM5iIHSY4Ym0V6zpS5Cvcc114eRw630wZfs3YOKaqIgc nDdTKEVxR37RdMEKNoL1Bpp2RTdbu1ZQmb8z3g2GUpJK8gG6e6CucAiqWPiNs1tlQ0+LTy0RUZ+Ku 3JWvDbrpP4VSwXdBL5yoMJRRnOYWVJYrBzMNwINHwKhd/8oV7H4uDqqBQGpfDIg93059LQusRCU2w Fg2gQ1EWT7HsXN2QT4ewYKHCp9f8QIU+suEG2usoslNbXxFYW7Aa4yqfQMSvwLzhxEhMFoPEgnt2T 5DzPDQHOPtAoKlhpa/Pg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1qPXxG-005ciT-0o; Sat, 29 Jul 2023 00:37:10 +0000 Received: from mail-pl1-x64a.google.com ([2607:f8b0:4864:20::64a]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1qPXx9-005cdr-24 for linux-arm-kernel@lists.infradead.org; Sat, 29 Jul 2023 00:37:05 +0000 Received: by mail-pl1-x64a.google.com with SMTP id d9443c01a7336-1bb962ada0dso17190025ad.2 for ; Fri, 28 Jul 2023 17:37:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1690591022; x=1691195822; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=jA1UVJV2mTAx+a2Lkx0I6MPmHbvMTggN8U6YXQ/WoPE=; b=K4d3Yo027UjIWQLKdsJ+4pJ5JAFOzUO0KRpjGWvQAJC1C3ucZprPSO1EmmSKjHL5RL mjMb4Wl4ok7XoJJ1UpvXExKrZiS4rMu1JU2JGycw5Xxs2iEvXPyGUoNKsTKzfJGYhbPU LgRlUQInLmq2DH5Uyogf+21W7XUb6ldLqjMT1xd34fC8sn4mYbNS+bx1bJKHKYjbaUdK 7AmwiB3Jjx2+vUvKZ15nrKoZsoW4PVfdu+/S0+ZWTbol8JYhHE2XH87j8WOQEjM0KOrB unEKPbBvWYwlhSNsm+dRFNpapqFmKqvp2geugj636QFuzYT5UZl84xpkYXOlHRd0ByML cS8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690591022; x=1691195822; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=jA1UVJV2mTAx+a2Lkx0I6MPmHbvMTggN8U6YXQ/WoPE=; b=PIPR3EBe6U1PR/PXietbUnGykdKtuHRQMHwJT/mAJQ0uuIu6lzQlwfvrITQ0fgpFdy z1xHX744Gc0PuH81s2xYDtbhyhPfyzmO7a03oIb52BL6lpECI/BzaSQMQHQzh3j1W/gp eNGZatRnb6Y4hFFfCMw3OJhJh2xTEJrxXnLTTGhkZFqmSjdN10vehGZLNdMSNu/JsJ5V mWNQAEjRQs7OF4ELnjDpHnmBqCuyu31nWWKH3MYGPYitSiXMR62kFDoxWajhPYVjNGcU fkRtmLTNGQ96+5B67c+mZokCdr9H70WPbbm0Miay4yObU4qQ9/LdY5TBNnVaFy4yozv+ tygg== X-Gm-Message-State: ABy/qLao8LtwrRY6jh+92AUtIF1nMroWwSDQBKr44GYkEXjOhVW3xwYg B7py/FlNsKUOj+KxjFWYddDZr9LPoKs= X-Google-Smtp-Source: APBJJlHBrL+TeZGSt6drIsgYNE5M3L5vEoG966oFy1TYmHeiItdpMHlHz7MHdTn/QgLjI5xFk+55OLkG/EQ= X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a17:903:2309:b0:1b3:bfa6:d064 with SMTP id d9-20020a170903230900b001b3bfa6d064mr13000plh.1.1690591021464; Fri, 28 Jul 2023 17:37:01 -0700 (PDT) Date: Fri, 28 Jul 2023 17:36:17 -0700 In-Reply-To: <20230729003643.1053367-1-seanjc@google.com> Mime-Version: 1.0 References: <20230729003643.1053367-1-seanjc@google.com> X-Mailer: git-send-email 2.41.0.487.g6d72f3e995-goog Message-ID: <20230729003643.1053367-9-seanjc@google.com> Subject: [PATCH v4 08/34] KVM: selftests: Add formatted guest assert support in ucall framework From: Sean Christopherson To: Paolo Bonzini , Marc Zyngier , Oliver Upton , Christian Borntraeger , Janosch Frank , Claudio Imbrenda Cc: kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, Sean Christopherson , Thomas Huth , " =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= " , Aaron Lewis X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230728_173703_681088_EE0BFE34 X-CRM114-Status: GOOD ( 16.90 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Sean Christopherson Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add printf-based GUEST_ASSERT macros and accompanying host-side support to provide an assert-specific versions of GUEST_PRINTF(). To make it easier to parse assert messages, for humans and bots alike, preserve/use the same layout as host asserts, e.g. in the example below, the reported expression, file, line number, and message are from the guest assertion, not the host reporting of the assertion. The call stack still captures the host reporting, but capturing the guest stack is a less pressing concern, i.e. can be done in the future, and an optimal solution would capture *both* the host and guest stacks, i.e. capturing the host stack isn't an outright bug. Running soft int test ==== Test Assertion Failure ==== x86_64/svm_nested_soft_inject_test.c:39: regs->rip != (unsigned long)l2_guest_code_int pid=214104 tid=214104 errno=4 - Interrupted system call 1 0x0000000000401b35: run_test at svm_nested_soft_inject_test.c:191 2 0x00000000004017d2: main at svm_nested_soft_inject_test.c:212 3 0x0000000000415b03: __libc_start_call_main at libc-start.o:? 4 0x000000000041714f: __libc_start_main_impl at ??:? 5 0x0000000000401660: _start at ??:? Expected IRQ at RIP 0x401e50, received IRQ at 0x401e50 Don't bother sharing code between ucall_assert() and ucall_fmt(), as forwarding the variable arguments would either require using macros or building a va_list, i.e. would make the code less readable and/or require just as much copy+paste code anyways. Gate the new macros with a flag so that tests can more or less be switched over one-by-one. The slow conversion won't be perfect, e.g. library code won't pick up the flag, but the only asserts in library code are of the vanilla GUEST_ASSERT() variety, i.e. don't print out variables. Add a temporary alias to GUEST_ASSERT_1() to fudge around ARM's arch_timer.h header using GUEST_ASSERT_1(), thus thwarting any attempt to convert tests one-by-one. Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/ucall_common.h | 48 +++++++++++++++++++ .../testing/selftests/kvm/lib/ucall_common.c | 22 +++++++++ 2 files changed, 70 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index b5548aeba9f0..4ce11c15285a 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -36,6 +36,8 @@ 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, ...); +void ucall_assert(uint64_t cmd, const char *exp, const char *file, + unsigned int line, 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); @@ -63,6 +65,50 @@ enum guest_assert_builtin_args { GUEST_ASSERT_BUILTIN_NARGS }; +#ifdef USE_GUEST_ASSERT_PRINTF +#define ____GUEST_ASSERT(_condition, _exp, _fmt, _args...) \ +do { \ + if (!(_condition)) \ + ucall_assert(UCALL_ABORT, _exp, __FILE__, __LINE__, _fmt, ##_args); \ +} while (0) + +#define __GUEST_ASSERT(_condition, _fmt, _args...) \ + ____GUEST_ASSERT(_condition, #_condition, _fmt, ##_args) + +#define GUEST_ASSERT(_condition) \ + __GUEST_ASSERT(_condition, #_condition) + +#define GUEST_FAIL(_fmt, _args...) \ + ucall_assert(UCALL_ABORT, "Unconditional guest failure", \ + __FILE__, __LINE__, _fmt, ##_args) + +#define GUEST_ASSERT_EQ(a, b) \ +do { \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + ____GUEST_ASSERT(__a == __b, #a " == " #b, "%#lx != %#lx (%s != %s)", \ + (unsigned long)(__a), (unsigned long)(__b), #a, #b); \ +} while (0) + +#define GUEST_ASSERT_NE(a, b) \ +do { \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + ____GUEST_ASSERT(__a != __b, #a " != " #b, "%#lx == %#lx (%s == %s)", \ + (unsigned long)(__a), (unsigned long)(__b), #a, #b); \ +} while (0) + +#define REPORT_GUEST_ASSERT(ucall) \ + test_assert(false, (const char *)(ucall).args[GUEST_ERROR_STRING], \ + (const char *)(ucall).args[GUEST_FILE], \ + (ucall).args[GUEST_LINE], "%s", (ucall).buffer) + +/* FIXME: Drop this alias once the param-based guest asserts are gone. */ +#define GUEST_ASSERT_1(_condition, arg1) \ + __GUEST_ASSERT(_condition, "arg1 = 0x%lx", arg1) + +#else + #define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) \ do { \ if (!(_condition)) \ @@ -129,4 +175,6 @@ do { \ #define REPORT_GUEST_ASSERT_N(ucall, fmt, args...) \ __REPORT_GUEST_ASSERT((ucall), fmt, ##args) +#endif /* USE_GUEST_ASSERT_PRINTF */ + #endif /* SELFTEST_KVM_UCALL_COMMON_H */ diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c index b507db91139b..816a3fa109bf 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -75,6 +75,28 @@ static void ucall_free(struct ucall *uc) clear_bit(uc - ucall_pool->ucalls, ucall_pool->in_use); } +void ucall_assert(uint64_t cmd, const char *exp, const char *file, + unsigned int line, const char *fmt, ...) +{ + struct ucall *uc; + va_list va; + + uc = ucall_alloc(); + uc->cmd = cmd; + + WRITE_ONCE(uc->args[GUEST_ERROR_STRING], (uint64_t)(exp)); + WRITE_ONCE(uc->args[GUEST_FILE], (uint64_t)(file)); + WRITE_ONCE(uc->args[GUEST_LINE], line); + + 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_fmt(uint64_t cmd, const char *fmt, ...) { struct ucall *uc;