Received: by 2002:ab2:69cc:0:b0:1fd:c486:4f03 with SMTP id n12csp45964lqp; Mon, 10 Jun 2024 17:52:06 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCWxshI44eRAXb8LFxuLQ7ptsjJO8TfVYgcEmCqcztC5FkEnAVRO1LPjCgM+s3g+mCiMETP8/NUSt4xobKNhScslKCyzP2JMagN3gQ1ZEQ== X-Google-Smtp-Source: AGHT+IGEIhRwyF2hZ6c2A/JxrpfYQ5Lc6zjFIMfj/CWBBD2rD4cXyinzPf5vvROCIg21imX21kO5 X-Received: by 2002:a17:90b:3014:b0:2c2:f052:a24a with SMTP id 98e67ed59e1d1-2c2f052a2ddmr4864775a91.24.1718067126092; Mon, 10 Jun 2024 17:52:06 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718067126; cv=pass; d=google.com; s=arc-20160816; b=nnCdboaOk4Rhq2bV2D99P9H/hA1ck1wckWU3seB+jvLOnvnsM+SyD4O5PPCHyStdHR /AHsZxJHR2jsXeK9qCWhiYU8kx5X+GUaPVY83NGRfCXJVXLY/5xipEP6GQes5hgl3Z6s azWc5ePt6A7fmgtn+QlsBDV7cEKbrEnQ1tczlkYLClJ1uJdGkhF/oAvCIlvMIiLiaHHm 7VtjHjq0/igFLnEx0UKiHtCHhvxa/9+eDsKP/hpUODjvGxi+4u9IpwRN3bcxo0nFViEQ P/FskjAcrr1ICovq3/vSvMbRhO2OVs7YLbc/O4NGc0r3020lznjNwm8W9OErvygFM6gv yjOw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:from:subject:message-id:references:mime-version :list-unsubscribe:list-subscribe:list-id:precedence:in-reply-to:date :dkim-signature; bh=ngaY7gpQRpIirX5s53yfK0/qc/j88qyKxzdVZ+iIXkA=; fh=0aT4HqAhDa+/xMVV5A7JT2LoM/BcjLHCRLg7nIdUrVk=; b=eagfDriqmz0WdzS8ZpJ6QdbmmUkJ6PQTSFH+Ce10NatYmtO60TC8j2chgEjFcCZPjk H/8K73KcmlmigZo1A7aeg4lHGF01wEIyiRp8OBhQj9TTaGqyZf8RgNtJcnwfcR3UBXDy 0sDQs2Ubt6cXO0xd2Duid2Rm0fS8IKEMOo0QrCTykAdibZAt8Hm//tY5Eb46EfMO6wLi nezwtl3h4Ml58tv/PhtHA/2XnQRqfaxehGYnRgOZFB16CqOu4AdE0caRk/m5Ad0payJD TASQQUY5LZT+1JnhZ3rciVt7kPtqPrKsCopa16/I5AYgcCL5eTD9Jv4HJJWdCluThYJ6 HvrA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=Ii0A2SFr; arc=pass (i=1 spf=pass spfdomain=flex--seanjc.bounces.google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-209138-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-209138-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id 98e67ed59e1d1-2c2d0e7968csi4200480a91.86.2024.06.10.17.52.05 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Jun 2024 17:52:06 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-209138-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=Ii0A2SFr; arc=pass (i=1 spf=pass spfdomain=flex--seanjc.bounces.google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-209138-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-209138-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id 2153D281A7F for ; Tue, 11 Jun 2024 00:51:59 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 34A5BBA5E; Tue, 11 Jun 2024 00:51:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Ii0A2SFr" Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F0426FCC for ; Tue, 11 Jun 2024 00:51:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718067091; cv=none; b=BTmNlXA4ICltCgjHn554N++DBRjpgz1ZQEsWJvrcErMvMh14ccWCcJZK8kvurJYxTzR8cJOQc8i0zja9MvqQo4yGcYGdr6YgHsAsBuPA4Zv18LkK+nXMRtHTG/4JUTisnX/waZZmQuLjZ1e50eBLeizrNOYlAJibuGCwWGyDQd8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718067091; c=relaxed/simple; bh=4tGsZXuoCnAYaQks7DUaHqHmrE2xVhNvtR6tBHdIssQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=mmwWOkrLJZjYLWoovQAq3y+J7wrSi5MttSsGEllOBcho8ZSMUbCtEZb8pYiZNQ6edfevl4O9k7IYY4KLaqycz9zjEU4F7vaaL6MxpWiPOpAHykwR8gtMrxvG+Dl+sBiAe4Zh6yz/Fj1GalyqgRCIa3K8FcEbrAaT4Qgi2j8W9/A= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Ii0A2SFr; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-2c2d89be34cso474364a91.2 for ; Mon, 10 Jun 2024 17:51:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1718067089; x=1718671889; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=ngaY7gpQRpIirX5s53yfK0/qc/j88qyKxzdVZ+iIXkA=; b=Ii0A2SFr7vXeUEFqjuMnASfs96nwEXd4dmzN59Gj0oFdZ4d6D+qLZvPwZEWjM7XRII WVBLaPRxF7lH6t08Gl90ltosKAaU5IlD/Q/85VnFXUAoT3viJjmMHbi/rg83oupWW5sj ClxMpV7OuV8hlBaVp/m8DhzYXSYVYvtpHQdA2MtbyyfegkTGvDBvuZ7Rmxme0anevB12 dzTNIazbg6djOjD7BXVA7J+uOAJpL9qNvhA0+EX+1W3H+whGgq8J6QB02EHH9CgZ9Kt7 WzejXlNjSxAlLqYkAkJJbqrhqUg/T6wcOS6ZF4rdQ6bore33ItQKUSZWbc/sT18JQYVg pkTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718067089; x=1718671889; 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=ngaY7gpQRpIirX5s53yfK0/qc/j88qyKxzdVZ+iIXkA=; b=D2k7dXO8Rdaj4ti+BFDBAZLh/k5Vk4Jc+yBswUElRhQEjnHeo78R7LqWfTFEBNQ3zQ vtfuC62hKXOGjWnmnuZ38+VYKqKR8qasepRPvtseWPB6wt5+cpU3OP/img71y3eu4PLw j4gyIDoayhnsbew0vmUdc46aosmvvGH8rA6J+zY7bQ++3HM1nuqTWdnCLckkZcvypJVa INF0UTkzpoW1gOyb3IcjO+dwjBtv52xCbO4rJZ5QwM8k/wO1TGP1WvQ1EkcZJuRbT2VM DAF87a2WTEYsZ++lW4yUdEYLl3OXRw0YydPqxF1/iBkGdKvvrsvGDJmBsYnSgUpoIQlm Kaow== X-Forwarded-Encrypted: i=1; AJvYcCUS5iGEH15RXi9L8PIpRZPDmw7JJ/ToJkDM9OeKGI0lcmM7TkbMSkWvpdOjuvX+xz8/QwE6l73AmD6yWH0fJNV8Z1ZaZUUbWTcoJa2i X-Gm-Message-State: AOJu0YzeG+XuqUmPe4106EGmxgME25qQD4H7+6kPTYVYq8Ou2J86N9Ey mtjZ4LZvSaWL6Bt9waz/SB6CegYtij8iWNRw8dgopVGq5foIEo2afyX5uccnL0H/qK39etem+QT VVg== X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a17:90a:bb08:b0:2c2:dd50:a0b5 with SMTP id 98e67ed59e1d1-2c2dd50a22bmr104092a91.0.1718067088517; Mon, 10 Jun 2024 17:51:28 -0700 (PDT) Date: Mon, 10 Jun 2024 17:51:26 -0700 In-Reply-To: <09b11d24e957056c621e3bf2d6c9d78bd4f7461b.1718043121.git.reinette.chatre@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <09b11d24e957056c621e3bf2d6c9d78bd4f7461b.1718043121.git.reinette.chatre@intel.com> Message-ID: Subject: Re: [PATCH V8 2/2] KVM: selftests: Add test for configure of x86 APIC bus frequency From: Sean Christopherson To: Reinette Chatre Cc: isaku.yamahata@intel.com, pbonzini@redhat.com, erdemaktas@google.com, vkuznets@redhat.com, vannapurve@google.com, jmattson@google.com, mlevitsk@redhat.com, xiaoyao.li@intel.com, chao.gao@intel.com, rick.p.edgecombe@intel.com, yuan.yao@intel.com, kvm@vger.kernel.org, linux-kernel@vger.kernel.org Content-Type: text/plain; charset="us-ascii" On Mon, Jun 10, 2024, Reinette Chatre wrote: > diff --git a/tools/testing/selftests/kvm/x86_64/apic_bus_clock_test.c b/tools/testing/selftests/kvm/x86_64/apic_bus_clock_test.c > new file mode 100644 > index 000000000000..602cec91d8ee > --- /dev/null > +++ b/tools/testing/selftests/kvm/x86_64/apic_bus_clock_test.c > @@ -0,0 +1,219 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2024 Intel Corporation > + * > + * Verify KVM correctly emulates the APIC bus frequency when the VMM configures > + * the frequency via KVM_CAP_X86_APIC_BUS_CYCLES_NS. Start the APIC timer by > + * programming TMICT (timer initial count) to the largest value possible (so > + * that the timer will not expire during the test). Then, after an arbitrary > + * amount of time has elapsed, verify TMCCT (timer current count) is within 1% > + * of the expected value based on the time elapsed, the APIC bus frequency, and > + * the programmed TDCR (timer divide configuration register). > + */ > + > +#include "apic.h" > +#include "test_util.h" > + > +/* > + * Pick 25MHz for APIC bus frequency. Different enough from the default 1GHz. > + * User can override via command line. > + */ > +unsigned long apic_hz = 25 * 1000 * 1000; static, and maybe a uint64_t to match the other stuff? > +/* > + * Possible TDCR values with matching divide count. Used to modify APIC > + * timer frequency. > + */ > +struct { > + uint32_t tdcr; > + uint32_t divide_count; > +} tdcrs[] = { > + {0x0, 2}, > + {0x1, 4}, > + {0x2, 8}, > + {0x3, 16}, > + {0x8, 32}, > + {0x9, 64}, > + {0xa, 128}, > + {0xb, 1}, > +}; > + > +void guest_verify(uint64_t tsc_cycles, uint32_t apic_cycles, uint32_t divide_count) uin64_t for apic_cycles? And maybe something like guest_check_apic_count(), to make it more obvious what is being verified? Actually, it should be quite easy to have the two flavors share the bulk of the code. > +{ > + unsigned long tsc_hz = tsc_khz * 1000; > + uint64_t freq; > + > + GUEST_ASSERT(tsc_cycles > 0); Is this necessary? Won't the "freq < ..." check fail? I love me some paranoia, but this seems unnecessary. > + freq = apic_cycles * divide_count * tsc_hz / tsc_cycles; > + /* Check if measured frequency is within 1% of configured frequency. */ > + GUEST_ASSERT(freq < apic_hz * 101 / 100); > + GUEST_ASSERT(freq > apic_hz * 99 / 100); > +} > + > +void x2apic_guest_code(void) > +{ > + uint32_t tmict, tmcct; > + uint64_t tsc0, tsc1; > + int i; > + > + x2apic_enable(); > + > + /* > + * Setup one-shot timer. The vector does not matter because the > + * interrupt should not fire. > + */ > + x2apic_write_reg(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | APIC_LVT_MASKED); > + > + for (i = 0; i < ARRAY_SIZE(tdcrs); i++) { > + x2apic_write_reg(APIC_TDCR, tdcrs[i].tdcr); > + > + /* Set the largest value to not trigger the interrupt. */ Nit, the goal isn't to avoid triggering the interrupt, e.g. the above masking takes care of that. The goal is to prevent the timer from expiring, because if the timer expires it stops counting and will trigger a false failure because the TSC doesn't stop counting. Honestly, I would just delete the comment. Same with the "busy wait for 100 msec" and "Read APIC timer and TSC" comments. They state the obvious. Loading the max TMICT is mildly interesting, but that's covered by the file-level comment. > + tmict = ~0; This really belongs outside of the loop, e.g. const uint32_t tmict = ~0u; > + x2apic_write_reg(APIC_TMICT, tmict); > + > + /* Busy wait for 100 msec. */ Hmm, should this be configurable? > + tsc0 = rdtsc(); > + udelay(100000); > + /* Read APIC timer and TSC. */ > + tmcct = x2apic_read_reg(APIC_TMCCT); > + tsc1 = rdtsc(); > + > + /* Stop timer. */ This comment is a bit more interesting, as readers might not know writing '0' stops the timer. But that's even more interesting is the ordering, e.g. it's not at all unreasonable to think that the timer should be stopped _before_ reading the current count. E.g. something like: /* * Stop the timer _after_ reading the current, final count, as * writing the initial counter also modifies the current count. */ > + x2apic_write_reg(APIC_TMICT, 0); > + > + guest_verify(tsc1 - tsc0, tmict - tmcct, tdcrs[i].divide_count); > + } > + > + GUEST_DONE(); > +} > + > +void xapic_guest_code(void) > +{ > + uint32_t tmict, tmcct; > + uint64_t tsc0, tsc1; > + int i; > + > + xapic_enable(); > + > + /* > + * Setup one-shot timer. The vector does not matter because the > + * interrupt should not fire. > + */ > + xapic_write_reg(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | APIC_LVT_MASKED); > + > + for (i = 0; i < ARRAY_SIZE(tdcrs); i++) { > + xapic_write_reg(APIC_TDCR, tdcrs[i].tdcr); > + > + /* Set the largest value to not trigger the interrupt. */ > + tmict = ~0; > + xapic_write_reg(APIC_TMICT, tmict); > + > + /* Busy wait for 100 msec. */ > + tsc0 = rdtsc(); > + udelay(100000); > + /* Read APIC timer and TSC. */ > + tmcct = xapic_read_reg(APIC_TMCCT); > + tsc1 = rdtsc(); > + > + /* Stop timer. */ > + xapic_write_reg(APIC_TMICT, 0); > + > + guest_verify(tsc1 - tsc0, tmict - tmcct, tdcrs[i].divide_count); That's some nice copy+paste :-) This test isn't writing ICR, so the whole 32-bit vs. 64-bit weirdness with xAPIC vs X2APIC is irrevelant. Two tiny helpers, a global flag, and you can avoid a pile of copy+paste, and the need to find a better name than guest_verify(). static bool is_x2apic; static uint32_t apic_read_reg(unsigned int reg) { return is_x2apic ? x2apic_read_reg(reg) : xapic_read_reg(reg); } static void apic_read_write(unsigned int reg, uint32_t val) { if (is_x2apic) x2apic_write_reg(reg, val); else xapic_write_reg(reg, val); return is_x2apic ? x2apic_read_reg(reg) : xapic_read_reg(reg); } > + } > + > + GUEST_DONE(); > +} > + > +void test_apic_bus_clock(struct kvm_vcpu *vcpu) > +{ > + bool done = false; > + struct ucall uc; > + > + while (!done) { > + vcpu_run(vcpu); > + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); > + > + switch (get_ucall(vcpu, &uc)) { > + case UCALL_DONE: > + done = true; > + break; > + case UCALL_ABORT: > + REPORT_GUEST_ASSERT(uc); > + break; > + default: > + TEST_FAIL("Unknown ucall %lu", uc.cmd); > + break; > + } > + } > +} > + > +void run_apic_bus_clock_test(bool xapic) > +{ > + struct kvm_vcpu *vcpu; > + struct kvm_vm *vm; > + int ret; > + > + vm = vm_create(1); > + > + sync_global_to_guest(vm, apic_hz); > + > + vm_enable_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS, > + NSEC_PER_SEC / apic_hz); > + > + vcpu = vm_vcpu_add(vm, 0, xapic ? xapic_guest_code : x2apic_guest_code); > + > + ret = __vm_enable_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS, > + NSEC_PER_SEC / apic_hz); > + TEST_ASSERT(ret < 0 && errno == EINVAL, > + "Setting of APIC bus frequency after vCPU is created should fail."); > + > + if (xapic) > + virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); > + > + test_apic_bus_clock(vcpu); > + kvm_vm_free(vm); > +} > + > +void run_xapic_bus_clock_test(void) > +{ > + run_apic_bus_clock_test(true); > +} > + > +void run_x2apic_bus_clock_test(void) > +{ > + run_apic_bus_clock_test(false); > +} > + > +void help(char *name) > +{ > + puts(""); > + printf("usage: %s [-h] [-a APIC bus freq]\n", name); > + puts(""); > + printf("-a: The APIC bus frequency (in Hz) to be configured for the guest.\n"); > + puts(""); > +} > + > +int main(int argc, char *argv[]) > +{ > + int opt; > + > + TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_APIC_BUS_CYCLES_NS)); > + TEST_REQUIRE(kvm_has_cap(KVM_CAP_GET_TSC_KHZ)); > + > + while ((opt = getopt(argc, argv, "a:h")) != -1) { > + switch (opt) { > + case 'a': Maybe -f for frequency instead of -a for APIC? And if we make the delay configurable, -d (delay)? > + apic_hz = atol(optarg); > + break; > + case 'h': > + help(argv[0]); > + exit(0); > + default: > + help(argv[0]); > + exit(1); > + } > + } > + > + run_xapic_bus_clock_test(); > + run_x2apic_bus_clock_test(); > +} > -- > 2.34.1 >