From patchwork Tue Jul 30 10:01:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Huth X-Patchwork-Id: 11065475 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 696741395 for ; Tue, 30 Jul 2019 10:01:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5ADF32878E for ; Tue, 30 Jul 2019 10:01:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4E7C128508; Tue, 30 Jul 2019 10:01:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4A3D52878E for ; Tue, 30 Jul 2019 10:01:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732127AbfG3KB1 (ORCPT ); Tue, 30 Jul 2019 06:01:27 -0400 Received: from mx1.redhat.com ([209.132.183.28]:35820 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727770AbfG3KB0 (ORCPT ); Tue, 30 Jul 2019 06:01:26 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6FA843CA05; Tue, 30 Jul 2019 10:01:26 +0000 (UTC) Received: from thuth.com (dhcp-200-228.str.redhat.com [10.33.200.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3B7CD19C67; Tue, 30 Jul 2019 10:01:24 +0000 (UTC) From: Thomas Huth To: kvm@vger.kernel.org, Christian Borntraeger , Janosch Frank Cc: linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org, David Hildenbrand , Cornelia Huck , Paolo Bonzini , =?utf-8?b?UmFkaW0gS3LEjW3DocWZ?= , Shuah Khan , Peter Xu Subject: [PATCH 1/2] KVM: selftests: Implement ucall() for s390x Date: Tue, 30 Jul 2019 12:01:11 +0200 Message-Id: <20190730100112.18205-2-thuth@redhat.com> In-Reply-To: <20190730100112.18205-1-thuth@redhat.com> References: <20190730100112.18205-1-thuth@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 30 Jul 2019 10:01:26 +0000 (UTC) Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On s390x, we can neither exit via PIO nor MMIO, but have to use an instruction like DIAGNOSE. While we're at it, rename UCALL_PIO to UCALL_DEFAULT, since PIO only works on x86 anyway, and this way we can re-use the "default" type for the DIAGNOSE exit on s390x. Now that ucall() is implemented, we can use it in the sync_reg_test on s390x, too. Signed-off-by: Thomas Huth --- .../testing/selftests/kvm/include/kvm_util.h | 2 +- tools/testing/selftests/kvm/lib/ucall.c | 34 +++++++++++++++---- .../selftests/kvm/s390x/sync_regs_test.c | 6 ++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index e0e66b115ef2..c37aea2e33e5 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -167,7 +167,7 @@ int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); /* ucall implementation types */ typedef enum { - UCALL_PIO, + UCALL_DEFAULT, UCALL_MMIO, } ucall_type_t; diff --git a/tools/testing/selftests/kvm/lib/ucall.c b/tools/testing/selftests/kvm/lib/ucall.c index dd9a66700f96..55534dd014dc 100644 --- a/tools/testing/selftests/kvm/lib/ucall.c +++ b/tools/testing/selftests/kvm/lib/ucall.c @@ -30,7 +30,7 @@ void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg) ucall_type = type; sync_global_to_guest(vm, ucall_type); - if (type == UCALL_PIO) + if (type == UCALL_DEFAULT) return; if (type == UCALL_MMIO) { @@ -84,11 +84,18 @@ void ucall_uninit(struct kvm_vm *vm) sync_global_to_guest(vm, ucall_exit_mmio_addr); } -static void ucall_pio_exit(struct ucall *uc) +static void ucall_default_exit(struct ucall *uc) { -#ifdef __x86_64__ +#if defined(__x86_64__) + /* Exit via PIO */ asm volatile("in %[port], %%al" : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax"); +#elif defined(__s390x__) + /* Exit via DIAGNOSE 0x501 (normally used for breakpoints) */ + asm volatile ("diag 0,%0,0x501" : : "a"(uc) : "memory"); +#else + fprintf(stderr, "No default ucall available on this architecture.\n"); + exit(1); #endif } @@ -113,8 +120,8 @@ void ucall(uint64_t cmd, int nargs, ...) va_end(va); switch (ucall_type) { - case UCALL_PIO: - ucall_pio_exit(&uc); + case UCALL_DEFAULT: + ucall_default_exit(&uc); break; case UCALL_MMIO: ucall_mmio_exit(&uc); @@ -128,15 +135,28 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) struct ucall ucall = {}; bool got_ucall = false; -#ifdef __x86_64__ - if (ucall_type == UCALL_PIO && run->exit_reason == KVM_EXIT_IO && +#if defined(__x86_64__) + if (ucall_type == UCALL_DEFAULT && run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) { struct kvm_regs regs; vcpu_regs_get(vm, vcpu_id, ®s); memcpy(&ucall, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), sizeof(ucall)); got_ucall = true; } +#elif defined(__s390x__) + if (ucall_type == UCALL_DEFAULT && + run->exit_reason == KVM_EXIT_S390_SIEIC && + run->s390_sieic.icptcode == 4 && + (run->s390_sieic.ipa >> 8) == 0x83 && /* 0x83 means DIAGNOSE */ + (run->s390_sieic.ipb >> 16) == 0x501) { + int reg = run->s390_sieic.ipa & 0xf; + + memcpy(&ucall, addr_gva2hva(vm, run->s.regs.gprs[reg]), + sizeof(ucall)); + got_ucall = true; + } #endif + if (ucall_type == UCALL_MMIO && run->exit_reason == KVM_EXIT_MMIO && run->mmio.phys_addr == (uint64_t)ucall_exit_mmio_addr) { vm_vaddr_t gva; diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c index e85ff0d69548..bbc93094519b 100644 --- a/tools/testing/selftests/kvm/s390x/sync_regs_test.c +++ b/tools/testing/selftests/kvm/s390x/sync_regs_test.c @@ -25,9 +25,11 @@ static void guest_code(void) { + register u64 stage asm("11") = 0; + for (;;) { - asm volatile ("diag 0,0,0x501"); - asm volatile ("ahi 11,1"); + GUEST_SYNC(0); + asm volatile ("ahi %0,1" : : "r"(stage)); } } From patchwork Tue Jul 30 10:01:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Huth X-Patchwork-Id: 11065469 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AFC0B1395 for ; Tue, 30 Jul 2019 10:01:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9F9CC28786 for ; Tue, 30 Jul 2019 10:01:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 93E0E287A0; Tue, 30 Jul 2019 10:01:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 17C4828786 for ; Tue, 30 Jul 2019 10:01:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732144AbfG3KBb (ORCPT ); Tue, 30 Jul 2019 06:01:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54332 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727770AbfG3KB3 (ORCPT ); Tue, 30 Jul 2019 06:01:29 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D51B530A7C7B; Tue, 30 Jul 2019 10:01:28 +0000 (UTC) Received: from thuth.com (dhcp-200-228.str.redhat.com [10.33.200.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id ABF9A19C67; Tue, 30 Jul 2019 10:01:26 +0000 (UTC) From: Thomas Huth To: kvm@vger.kernel.org, Christian Borntraeger , Janosch Frank Cc: linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org, David Hildenbrand , Cornelia Huck , Paolo Bonzini , =?utf-8?b?UmFkaW0gS3LEjW3DocWZ?= , Shuah Khan , Peter Xu Subject: [PATCH 2/2] KVM: selftests: Enable dirty_log_test on s390x Date: Tue, 30 Jul 2019 12:01:12 +0200 Message-Id: <20190730100112.18205-3-thuth@redhat.com> In-Reply-To: <20190730100112.18205-1-thuth@redhat.com> References: <20190730100112.18205-1-thuth@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Tue, 30 Jul 2019 10:01:28 +0000 (UTC) Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP To run the dirty_log_test on s390x, we have to make sure that we access the dirty log bitmap with little endian byte ordering and we have to properly align the memslot of the guest. Also all dirty bits of a segment are set once on s390x when one of the pages of a segment are written to for the first time, so we have to make sure that we touch all pages during the first iteration to keep the test in sync here. Signed-off-by: Thomas Huth --- tools/testing/selftests/kvm/Makefile | 1 + tools/testing/selftests/kvm/dirty_log_test.c | 70 ++++++++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index ba7849751989..ac7e63e00fee 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -33,6 +33,7 @@ TEST_GEN_PROGS_aarch64 += dirty_log_test TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus TEST_GEN_PROGS_s390x += s390x/sync_regs_test +TEST_GEN_PROGS_s390x += dirty_log_test TEST_GEN_PROGS_s390x += kvm_create_max_vcpus TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index ceb52b952637..7a1223ad0ff3 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -26,9 +26,22 @@ /* The memory slot index to track dirty pages */ #define TEST_MEM_SLOT_INDEX 1 +#ifdef __s390x__ + +/* + * On s390x, the ELF program is sometimes linked at 0x80000000, so we can + * not use 0x40000000 here without overlapping into that region. Thus let's + * use 0xc0000000 as base address there instead. + */ +#define DEFAULT_GUEST_TEST_MEM 0xc0000000 + +#else + /* Default guest test memory offset, 1G */ #define DEFAULT_GUEST_TEST_MEM 0x40000000 +#endif + /* How many pages to dirty for each guest loop */ #define TEST_PAGES_PER_LOOP 1024 @@ -38,6 +51,27 @@ /* Interval for each host loop (ms) */ #define TEST_HOST_LOOP_INTERVAL 10UL +/* Dirty bitmaps are always little endian, so we need to swap on big endian */ +#if defined(__s390x__) +# define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) +# define test_bit_le(nr, addr) \ + test_bit((nr) ^ BITOP_LE_SWIZZLE, addr) +# define set_bit_le(nr, addr) \ + set_bit((nr) ^ BITOP_LE_SWIZZLE, addr) +# define clear_bit_le(nr, addr) \ + clear_bit((nr) ^ BITOP_LE_SWIZZLE, addr) +# define test_and_set_bit_le(nr, addr) \ + test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, addr) +# define test_and_clear_bit_le(nr, addr) \ + test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, addr) +#else +# define test_bit_le test_bit +# define set_bit_le set_bit +# define clear_bit_le clear_bit +# define test_and_set_bit_le test_and_set_bit +# define test_and_clear_bit_le test_and_clear_bit +#endif + /* * Guest/Host shared variables. Ensure addr_gva2hva() and/or * sync_global_to/from_guest() are used when accessing from @@ -69,11 +103,25 @@ static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; */ static void guest_code(void) { + uint64_t addr; int i; +#ifdef __s390x__ + /* + * On s390x, all pages of a 1M segment are initially marked as dirty + * when a page of the segment is written to for the very first time. + * To compensate this specialty in this test, we need to touch all + * pages during the first iteration. + */ + for (i = 0; i < guest_num_pages; i++) { + addr = guest_test_virt_mem + i * guest_page_size; + *(uint64_t *)addr = READ_ONCE(iteration); + } +#endif + while (true) { for (i = 0; i < TEST_PAGES_PER_LOOP; i++) { - uint64_t addr = guest_test_virt_mem; + addr = guest_test_virt_mem; addr += (READ_ONCE(random_array[i]) % guest_num_pages) * guest_page_size; addr &= ~(host_page_size - 1); @@ -158,15 +206,15 @@ static void vm_dirty_log_verify(unsigned long *bmap) value_ptr = host_test_mem + page * host_page_size; /* If this is a special page that we were tracking... */ - if (test_and_clear_bit(page, host_bmap_track)) { + if (test_and_clear_bit_le(page, host_bmap_track)) { host_track_next_count++; - TEST_ASSERT(test_bit(page, bmap), + TEST_ASSERT(test_bit_le(page, bmap), "Page %"PRIu64" should have its dirty bit " "set in this iteration but it is missing", page); } - if (test_bit(page, bmap)) { + if (test_bit_le(page, bmap)) { host_dirty_count++; /* * If the bit is set, the value written onto @@ -209,7 +257,7 @@ static void vm_dirty_log_verify(unsigned long *bmap) * should report its dirtyness in the * next run */ - set_bit(page, host_bmap_track); + set_bit_le(page, host_bmap_track); } } } @@ -293,6 +341,10 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, * case where the size is not aligned to 64 pages. */ guest_num_pages = (1ul << (30 - guest_page_shift)) + 16; +#ifdef __s390x__ + /* Round up to multiple of 1M (segment size) */ + guest_num_pages = (guest_num_pages + 0xff) & ~0xffUL; +#endif host_page_size = getpagesize(); host_num_pages = (guest_num_pages * guest_page_size) / host_page_size + !!((guest_num_pages * guest_page_size) % host_page_size); @@ -304,6 +356,11 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, guest_test_phys_mem = phys_offset; } +#ifdef __s390x__ + /* Align to 1M (segment size) */ + guest_test_phys_mem &= ~((1 << 20) - 1); +#endif + DEBUG("guest physical test memory offset: 0x%lx\n", guest_test_phys_mem); bmap = bitmap_alloc(host_num_pages); @@ -454,6 +511,9 @@ int main(int argc, char *argv[]) vm_guest_mode_params_init(VM_MODE_P48V48_64K, true, true); } #endif +#ifdef __s390x__ + vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); +#endif while ((opt = getopt(argc, argv, "hi:I:p:m:")) != -1) { switch (opt) {