From patchwork Tue Jul 23 14:15:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740123 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 1D330C3DA49 for ; Tue, 23 Jul 2024 14:17:52 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGIp-0003W4-S9; Tue, 23 Jul 2024 10:15:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGIn-0003O4-RE for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:42 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGIl-000761-CL for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744137; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mKFZHRAaNx5SH+JoVPvMhA+txKbl3gPY3EVh/Uef8VU=; b=du+1IeJqsZq3ZwBaiwMGmOYRoXAALqNdc46/wq00S0IJB5cohFoa0gn/ayShXyDM1tNpJC kTnv2qODnDmU8GI3fk0xy7Y+xFDZDj4PY9hjVg8tb+xXg6JEHwFz4ETRBYDfQwkUIZXiHC UxQo4RnWvREGpT3p3wJVf29zGGG58FY= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-85-n4SHEXKOMNa2J8i0M2CyFQ-1; Tue, 23 Jul 2024 10:15:36 -0400 X-MC-Unique: n4SHEXKOMNa2J8i0M2CyFQ-1 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-3688010b3bfso3905477f8f.3 for ; Tue, 23 Jul 2024 07:15:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744135; x=1722348935; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=mKFZHRAaNx5SH+JoVPvMhA+txKbl3gPY3EVh/Uef8VU=; b=aJHzKpanxy9zKxxyu2mirjXqWWrBSQTlOHMHVHCuJ5RGGGb6BFcTGGfoCIgocsY3GI jP9jlMLglPuX396V1/uylV2HgxvkKE/1Ie7lCM1HVvUEr0+PFdYqxc5hECV9ya/dqB97 /RsozR5vgDTpi0o3OJlCW46ypNPS8qCE0pSprmzB8f4l/JGjfOpw4KP6Yg67JEuMtdwt dib4xtBXYWVMFXLvNtN04V/oOzPy7HRL7/bBartzCWF2TC67xe2Wo+78n3DASfeyCrmt U38HNeudmGtTDKrhjvZbkbRdrHON+mIM+g2jfl+Mk5M56hoa1LiVdvxRGAGBAoZBBjlW Rudg== X-Gm-Message-State: AOJu0YzSfag8qlKYIRC9Qvziy5czcja8gWCTA3n+zG1s2Ig8vlGFWduW D13BzWiRq1b+phawx1lt92rEnhp3cVPItQFYN0FcyOVMdBsrQRUT6AdZlcdT9XSGhwmGrrn2IHf 12ivDqtM0aaHdsuFiXwMMztVrUs34lyFU2gPa6mwUDaUnux/h0mLHxiZydjmWQLxuq1b9PfCSsO btArPh9UK59Zi4rWPGTJYDxWqEzWVzPMudUIyi X-Received: by 2002:a5d:5f84:0:b0:368:3f5b:2ae7 with SMTP id ffacd0b85a97d-369bae4ce9bmr9044108f8f.24.1721744134648; Tue, 23 Jul 2024 07:15:34 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHFu03skEy5KoGckN7VOYKRL7fUjzaBpx1R3byVezDDiNsStsAtQ8yP5eG2RT8Csix728vOlw== X-Received: by 2002:a5d:5f84:0:b0:368:3f5b:2ae7 with SMTP id ffacd0b85a97d-369bae4ce9bmr9044075f8f.24.1721744134200; Tue, 23 Jul 2024 07:15:34 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3687868ac48sm11710596f8f.29.2024.07.23.07.15.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:33 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-stable@nongnu.org Subject: [PULL 01/11] target/i386: do not crash if microvm guest uses SGX CPUID leaves Date: Tue, 23 Jul 2024 16:15:19 +0200 Message-ID: <20240723141529.551737-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org sgx_epc_get_section assumes a PC platform is in use: bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); However, sgx_epc_get_section is called by CPUID regardless of whether SGX state has been initialized or which platform is in use. Check whether the machine has the right QOM class and if not behave as if there are no EPC sections. Fixes: 1dec2e1f19f ("i386: Update SGX CPUID info according to hardware/KVM/user input", 2021-09-30) Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2142 Signed-off-by: Paolo Bonzini --- hw/i386/sgx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index a14a84bc6f6..849472a1286 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -268,10 +268,12 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) { - PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PCMachineState *pcms = + (PCMachineState *)object_dynamic_cast(qdev_get_machine(), + TYPE_PC_MACHINE); SGXEPCDevice *epc; - if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) { + if (!pcms || pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) { return true; } From patchwork Tue Jul 23 14:15:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740115 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 A22DEC3DA49 for ; Tue, 23 Jul 2024 14:16:48 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGIu-0003tF-Mg; Tue, 23 Jul 2024 10:15:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGIp-0003ZF-UH for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:43 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGIn-00076c-J9 for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744140; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bBmdKai45m+KPRGpnPmMNJlmmK+aMNov4HIpoz9yWEc=; b=K2zwHlYfgsjpeklKkqK4ADoXkjeZqLNEMwsbisL5SaCSs8XvtUcT5EP6vhGLKixxnLC96E XeS7cgOdK04iy2iba/9hWvKo6hOEt3sHCuPYJ1mxoGfA0RYv271T4XEJDvBzKfWDg3cHl4 8LD4uAiYX1EHdT7ZglYgMFPTWXZuuO4= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-373-t2-ZsSfwNtOO94jifnHmVg-1; Tue, 23 Jul 2024 10:15:38 -0400 X-MC-Unique: t2-ZsSfwNtOO94jifnHmVg-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4266d0183feso44819465e9.0 for ; Tue, 23 Jul 2024 07:15:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744137; x=1722348937; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bBmdKai45m+KPRGpnPmMNJlmmK+aMNov4HIpoz9yWEc=; b=mYWI9MjKKtEi6Kux0oB1URBI5NGBbKjIIz6XBQPiM0rrIOBUXJXiRLfaufPBM7TM8R gBn7ObCeZQZpig7BFsnE9LPFKwkfBeLhwwDajZFMO3jh7bU+UFL2FaiuyS/B8/4seM/w AS0/tgRUhJSxZph6aeUSJLNXnmstHZAc25Rttgmn5f9mzBx7Ysx2BIfZkhjEXI7RVSpm 9BhdciUBqnBLYSRGl3tYPjynsEs/98QKGu4Sq0zmYXPiIeJ7ACloyXKVOqAN5ENMzUuA HogETTZbOAbXl0i3P7Bub0ai9Ch9506SfVOEY0l6FctFm2uh5T70dXR73F9ZauEuZtVK WYTA== X-Gm-Message-State: AOJu0YyEJcuXYcPm8ebEMdKJgITgOuQR6VO29VLlvlB9OQPIDCoAfgFW 7QEPW/RzTNPH8LxeT8m/lJAfIoAg6HpMEvm0Mw+MT674z1uTYGcib60GYLPFjuhOsLFvNhvuJbR Qt6JZEprMOjhuCnmpF/xVUB4uogAhOpbE5o+EUp4KHu3X7jk49sOL7CbQbut+3Lkdy0WbVFmV4m lcJc4xbcpZFdOrc7+nHpfVMp/qsD1VpiOLH86B X-Received: by 2002:a05:600c:3c9d:b0:426:6099:6eaa with SMTP id 5b1f17b1804b1-427daa61cddmr74485865e9.26.1721744136932; Tue, 23 Jul 2024 07:15:36 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG1WmZOVIPFr3SV8Utd6M7VXVHkmQhO8fASyQ0E1GUBvBQ5eNnRgJfZIovOMxeABpGol8Q58g== X-Received: by 2002:a05:600c:3c9d:b0:426:6099:6eaa with SMTP id 5b1f17b1804b1-427daa61cddmr74485685e9.26.1721744136519; Tue, 23 Jul 2024 07:15:36 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-427d2a5c3d4sm202265145e9.17.2024.07.23.07.15.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:36 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: Anthony Harivel Subject: [PULL 02/11] qio: add support for SO_PEERCRED for socket channel Date: Tue, 23 Jul 2024 16:15:20 +0200 Message-ID: <20240723141529.551737-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Anthony Harivel The function qio_channel_get_peercred() returns a pointer to the credentials of the peer process connected to this socket. This credentials structure is defined in as follows: struct ucred { pid_t pid; /* Process ID of the sending process */ uid_t uid; /* User ID of the sending process */ gid_t gid; /* Group ID of the sending process */ }; The use of this function is possible only for connected AF_UNIX stream sockets and for AF_UNIX stream and datagram socket pairs. On platform other than Linux, the function return 0. Signed-off-by: Anthony Harivel Link: https://lore.kernel.org/r/20240522153453.1230389-2-aharivel@redhat.com Signed-off-by: Paolo Bonzini --- include/io/channel.h | 21 +++++++++++++++++++++ io/channel-socket.c | 28 ++++++++++++++++++++++++++++ io/channel.c | 13 +++++++++++++ 3 files changed, 62 insertions(+) diff --git a/include/io/channel.h b/include/io/channel.h index 7986c49c713..bdf0bca92ae 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -160,6 +160,9 @@ struct QIOChannelClass { void *opaque); int (*io_flush)(QIOChannel *ioc, Error **errp); + int (*io_peerpid)(QIOChannel *ioc, + unsigned int *pid, + Error **errp); }; /* General I/O handling functions */ @@ -981,4 +984,22 @@ int coroutine_mixed_fn qio_channel_writev_full_all(QIOChannel *ioc, int qio_channel_flush(QIOChannel *ioc, Error **errp); +/** + * qio_channel_get_peercred: + * @ioc: the channel object + * @pid: pointer to pid + * @errp: pointer to a NULL-initialized error object + * + * Returns the pid of the peer process connected to this socket. + * + * The use of this function is possible only for connected + * AF_UNIX stream sockets and for AF_UNIX stream and datagram + * socket pairs on Linux. + * Return -1 on error with pid -1 for the non-Linux OS. + * + */ +int qio_channel_get_peerpid(QIOChannel *ioc, + unsigned int *pid, + Error **errp); + #endif /* QIO_CHANNEL_H */ diff --git a/io/channel-socket.c b/io/channel-socket.c index 3a899b06085..608bcf066ec 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -841,6 +841,33 @@ qio_channel_socket_set_cork(QIOChannel *ioc, socket_set_cork(sioc->fd, v); } +static int +qio_channel_socket_get_peerpid(QIOChannel *ioc, + unsigned int *pid, + Error **errp) +{ +#ifdef CONFIG_LINUX + QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); + Error *err = NULL; + socklen_t len = sizeof(struct ucred); + + struct ucred cred; + if (getsockopt(sioc->fd, + SOL_SOCKET, SO_PEERCRED, + &cred, &len) == -1) { + error_setg_errno(&err, errno, "Unable to get peer credentials"); + error_propagate(errp, err); + *pid = -1; + return -1; + } + *pid = (unsigned int)cred.pid; + return 0; +#else + error_setg(errp, "Unsupported feature"); + *pid = -1; + return -1; +#endif +} static int qio_channel_socket_close(QIOChannel *ioc, @@ -938,6 +965,7 @@ static void qio_channel_socket_class_init(ObjectClass *klass, #ifdef QEMU_MSG_ZEROCOPY ioc_klass->io_flush = qio_channel_socket_flush; #endif + ioc_klass->io_peerpid = qio_channel_socket_get_peerpid; } static const TypeInfo qio_channel_socket_info = { diff --git a/io/channel.c b/io/channel.c index a1f12f8e909..e3f17c24a00 100644 --- a/io/channel.c +++ b/io/channel.c @@ -548,6 +548,19 @@ void qio_channel_set_cork(QIOChannel *ioc, } } +int qio_channel_get_peerpid(QIOChannel *ioc, + unsigned int *pid, + Error **errp) +{ + QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); + + if (!klass->io_peerpid) { + error_setg(errp, "Channel does not support peer pid"); + return -1; + } + klass->io_peerpid(ioc, pid, errp); + return 0; +} off_t qio_channel_io_seek(QIOChannel *ioc, off_t offset, From patchwork Tue Jul 23 14:15:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740114 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 76954C3DA49 for ; Tue, 23 Jul 2024 14:16:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGIy-0004Av-H8; Tue, 23 Jul 2024 10:15:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGIu-0003sb-8y for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:48 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGIq-000779-Fj for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744143; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nmsnigBLHZ58d8Jt0kJfLbUW1lQaNS19BepeXHulu4Y=; b=Br+UnNb8rQq6Y3b5lrxVhLMf06KKjyi7Yaa+Owt8xKnazoq7Fvxdovj4Ef+tnBaEXEYNxT hDxwDsaahCHWVrXRQXP2KRgvIaMKGNgpDxpAPh0ofp9UptQffvNN7SWXwoCgmlfACpKbtO WzhJHlJ72c57g50cDw0ZvZx0Ti+otR0= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-295-wfW58yyEOc6hsKlmsoIlAg-1; Tue, 23 Jul 2024 10:15:42 -0400 X-MC-Unique: wfW58yyEOc6hsKlmsoIlAg-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-4279837c024so39276495e9.2 for ; Tue, 23 Jul 2024 07:15:41 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744140; x=1722348940; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=nmsnigBLHZ58d8Jt0kJfLbUW1lQaNS19BepeXHulu4Y=; b=o2hejDb5aUurYYIoctBDuPsN1e7pjbNTd4WyzAnXjpfN6LGQAa6q0cRfNtlZFuik2g 1DrKIUxWiV9TihdjFS4Aii+axP+YWqcvGBhFvFQYv42uVUJTH9C30jWFsK+vQG3ldCB0 C163660zNl2dvABsvoowmpxLg31whaR+OjsUhgo8oE27mju9c0b4fI6FVQ3hk3jRT/zO edW8YAXGI0057XRIS+tMHkMbFxMY9qlA21RzMpmBoWZRUrgdMuXcvYGcAZV5kHjgSjXm yvyLqjbEhjQhv2Jr1L4WAe57TDyIx/1e5S3Io8mguoy8g2L7kZI3+QwMT4Ps9YvuiBod CRDg== X-Gm-Message-State: AOJu0YwOG6wZiO+cLwnT2A31gTtFB/Aw7hPKm8+OWwz1tUz+XJksGLgt MfUY+GXok+394d7E6oJcakbZmT7Cj8xUXG92f1Z+0XpKvOI4oejhsPSjsffG3QWaCtJ1QxoAfEX TX6HdwiGwp/4K4ED3LtyNCqpBLBfGgczsK8BjHKuno55TyPE8tcaRCcT4WtnkFkIateqTTIjTU5 amZCr9Yc+hE9XW2G8GzN/NMOJpOT8Ce28bSrkW X-Received: by 2002:adf:e609:0:b0:368:6d75:1bde with SMTP id ffacd0b85a97d-369dec0aa0cmr2207902f8f.15.1721744139807; Tue, 23 Jul 2024 07:15:39 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF29du2kCFZ2ger7lUlYM3B1xor4I1VbCZzZsYb58tE5id/gX9wWkTWVENphrSdOVbC7JictQ== X-Received: by 2002:adf:e609:0:b0:368:6d75:1bde with SMTP id ffacd0b85a97d-369dec0aa0cmr2207874f8f.15.1721744139135; Tue, 23 Jul 2024 07:15:39 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3687868bc21sm11628664f8f.39.2024.07.23.07.15.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:38 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: Anthony Harivel Subject: [PULL 03/11] tools: build qemu-vmsr-helper Date: Tue, 23 Jul 2024 16:15:21 +0200 Message-ID: <20240723141529.551737-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Anthony Harivel Introduce a privileged helper to access RAPL MSR. The privileged helper tool, qemu-vmsr-helper, is designed to provide virtual machines with the ability to read specific RAPL (Running Average Power Limit) MSRs without requiring CAP_SYS_RAWIO privileges or relying on external, out-of-tree patches. The helper tool leverages Unix permissions and SO_PEERCRED socket options to enforce access control, ensuring that only processes explicitly requesting read access via readmsr() from a valid Thread ID can access these MSRs. The list of RAPL MSRs that are allowed to be read by the helper tool is defined in rapl-msr-index.h. This list corresponds to the RAPL MSRs that will be supported in the next commit titled "Add support for RAPL MSRs in KVM/QEMU." The tool is intentionally designed to run on the Linux x86 platform. This initial implementation is tailored for Intel CPUs but can be extended to support AMD CPUs in the future. Signed-off-by: Anthony Harivel Link: https://lore.kernel.org/r/20240522153453.1230389-3-aharivel@redhat.com Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + docs/tools/index.rst | 1 + docs/tools/qemu-vmsr-helper.rst | 89 ++++ meson.build | 7 + tools/i386/rapl-msr-index.h | 28 ++ tools/i386/qemu-vmsr-helper.c | 530 +++++++++++++++++++++++ contrib/systemd/qemu-vmsr-helper.service | 15 + contrib/systemd/qemu-vmsr-helper.socket | 9 + 8 files changed, 680 insertions(+) create mode 100644 docs/tools/qemu-vmsr-helper.rst create mode 100644 tools/i386/rapl-msr-index.h create mode 100644 tools/i386/qemu-vmsr-helper.c create mode 100644 contrib/systemd/qemu-vmsr-helper.service create mode 100644 contrib/systemd/qemu-vmsr-helper.socket diff --git a/MAINTAINERS b/MAINTAINERS index 7d9811458cb..f8df6940fad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -140,6 +140,7 @@ F: docs/system/target-i386* F: target/i386/*.[ch] F: target/i386/Kconfig F: target/i386/meson.build +F: tools/i386/ Guest CPU cores (TCG) --------------------- diff --git a/docs/tools/index.rst b/docs/tools/index.rst index 8e65ce0dfc7..33ad438e86f 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -16,3 +16,4 @@ command line utilities and other standalone programs. qemu-pr-helper qemu-trace-stap virtfs-proxy-helper + qemu-vmsr-helper diff --git a/docs/tools/qemu-vmsr-helper.rst b/docs/tools/qemu-vmsr-helper.rst new file mode 100644 index 00000000000..6ec87b49d96 --- /dev/null +++ b/docs/tools/qemu-vmsr-helper.rst @@ -0,0 +1,89 @@ +================================== +QEMU virtual RAPL MSR helper +================================== + +Synopsis +-------- + +**qemu-vmsr-helper** [*OPTION*] + +Description +----------- + +Implements the virtual RAPL MSR helper for QEMU. + +Accessing the RAPL (Running Average Power Limit) MSR enables the RAPL powercap +driver to advertise and monitor the power consumption or accumulated energy +consumption of different power domains, such as CPU packages, DRAM, and other +components when available. + +However those register are accesible under priviliged access (CAP_SYS_RAWIO). +QEMU can use an external helper to access those priviliged register. + +:program:`qemu-vmsr-helper` is that external helper; it creates a listener +socket which will accept incoming connections for communication with QEMU. + +If you want to run VMs in a setup like this, this helper should be started as a +system service, and you should read the QEMU manual section on "RAPL MSR +support" to find out how to configure QEMU to connect to the socket created by +:program:`qemu-vmsr-helper`. + +After connecting to the socket, :program:`qemu-vmsr-helper` can +optionally drop root privileges, except for those capabilities that +are needed for its operation. + +:program:`qemu-vmsr-helper` can also use the systemd socket activation +protocol. In this case, the systemd socket unit should specify a +Unix stream socket, like this:: + + [Socket] + ListenStream=/var/run/qemu-vmsr-helper.sock + +Options +------- + +.. program:: qemu-vmsr-helper + +.. option:: -d, --daemon + + run in the background (and create a PID file) + +.. option:: -q, --quiet + + decrease verbosity + +.. option:: -v, --verbose + + increase verbosity + +.. option:: -f, --pidfile=PATH + + PID file when running as a daemon. By default the PID file + is created in the system runtime state directory, for example + :file:`/var/run/qemu-vmsr-helper.pid`. + +.. option:: -k, --socket=PATH + + path to the socket. By default the socket is created in + the system runtime state directory, for example + :file:`/var/run/qemu-vmsr-helper.sock`. + +.. option:: -T, --trace [[enable=]PATTERN][,events=FILE][,file=FILE] + + .. include:: ../qemu-option-trace.rst.inc + +.. option:: -u, --user=USER + + user to drop privileges to + +.. option:: -g, --group=GROUP + + group to drop privileges to + +.. option:: -h, --help + + Display a help message and exit. + +.. option:: -V, --version + + Display version information and exit. diff --git a/meson.build b/meson.build index a1e51277b09..9d3e2d2ddbe 100644 --- a/meson.build +++ b/meson.build @@ -4073,6 +4073,13 @@ if have_tools dependencies: [authz, crypto, io, qom, qemuutil, libcap_ng, mpathpersist], install: true) + + if cpu in ['x86', 'x86_64'] + executable('qemu-vmsr-helper', files('tools/i386/qemu-vmsr-helper.c'), + dependencies: [authz, crypto, io, qom, qemuutil, + libcap_ng, mpathpersist], + install: true) + endif endif if have_ivshmem diff --git a/tools/i386/rapl-msr-index.h b/tools/i386/rapl-msr-index.h new file mode 100644 index 00000000000..9a7118639ae --- /dev/null +++ b/tools/i386/rapl-msr-index.h @@ -0,0 +1,28 @@ +/* + * Allowed list of MSR for Privileged RAPL MSR helper commands for QEMU + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Anthony Harivel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/* + * Should stay in sync with the RAPL MSR + * in target/i386/cpu.h + */ +#define MSR_RAPL_POWER_UNIT 0x00000606 +#define MSR_PKG_POWER_LIMIT 0x00000610 +#define MSR_PKG_ENERGY_STATUS 0x00000611 +#define MSR_PKG_POWER_INFO 0x00000614 diff --git a/tools/i386/qemu-vmsr-helper.c b/tools/i386/qemu-vmsr-helper.c new file mode 100644 index 00000000000..ebf562c3ff8 --- /dev/null +++ b/tools/i386/qemu-vmsr-helper.c @@ -0,0 +1,530 @@ +/* + * Privileged RAPL MSR helper commands for QEMU + * + * Copyright (C) 2024 Red Hat, Inc. + * + * Author: Anthony Harivel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include +#include +#include +#ifdef CONFIG_LIBCAP_NG +#include +#endif +#include +#include + +#include "qemu/help-texts.h" +#include "qapi/error.h" +#include "qemu/cutils.h" +#include "qemu/main-loop.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "qemu/config-file.h" +#include "qemu-version.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qemu/systemd.h" +#include "io/channel.h" +#include "io/channel-socket.h" +#include "trace/control.h" +#include "qemu-version.h" +#include "rapl-msr-index.h" + +#define MSR_PATH_TEMPLATE "/dev/cpu/%u/msr" + +static char *socket_path; +static char *pidfile; +static enum { RUNNING, TERMINATE, TERMINATING } state; +static QIOChannelSocket *server_ioc; +static int server_watch; +static int num_active_sockets = 1; + +#ifdef CONFIG_LIBCAP_NG +static int uid = -1; +static int gid = -1; +#endif + +static void compute_default_paths(void) +{ + g_autofree char *state = qemu_get_local_state_dir(); + + socket_path = g_build_filename(state, "run", "qemu-vmsr-helper.sock", NULL); + pidfile = g_build_filename(state, "run", "qemu-vmsr-helper.pid", NULL); +} + +static int is_intel_processor(void) +{ + int result; + int ebx, ecx, edx; + + /* Execute CPUID instruction with eax=0 (basic identification) */ + asm volatile ( + "cpuid" + : "=b" (ebx), "=c" (ecx), "=d" (edx) + : "a" (0) + ); + + /* + * Check if processor is "GenuineIntel" + * 0x756e6547 = "Genu" + * 0x49656e69 = "ineI" + * 0x6c65746e = "ntel" + */ + result = (ebx == 0x756e6547) && (edx == 0x49656e69) && (ecx == 0x6c65746e); + + return result; +} + +static int is_rapl_enabled(void) +{ + const char *path = "/sys/class/powercap/intel-rapl/enabled"; + FILE *file = fopen(path, "r"); + int value = 0; + + if (file != NULL) { + if (fscanf(file, "%d", &value) != 1) { + error_report("INTEL RAPL not enabled"); + } + fclose(file); + } else { + error_report("Error opening %s", path); + } + + return value; +} + +/* + * Check if the TID that request the MSR read + * belongs to the peer. It be should a TID of a vCPU. + */ +static bool is_tid_present(pid_t pid, pid_t tid) +{ + g_autofree char *tidPath = g_strdup_printf("/proc/%d/task/%d", pid, tid); + + /* Check if the TID directory exists within the PID directory */ + if (access(tidPath, F_OK) == 0) { + return true; + } + + error_report("Failed to open /proc at %s", tidPath); + return false; +} + +/* + * Only the RAPL MSR in target/i386/cpu.h are allowed + */ +static bool is_msr_allowed(uint32_t reg) +{ + switch (reg) { + case MSR_RAPL_POWER_UNIT: + case MSR_PKG_POWER_LIMIT: + case MSR_PKG_ENERGY_STATUS: + case MSR_PKG_POWER_INFO: + return true; + default: + return false; + } +} + +static uint64_t vmsr_read_msr(uint32_t msr_register, unsigned int cpu_id) +{ + int fd; + uint64_t result = 0; + + g_autofree char *path = g_strdup_printf(MSR_PATH_TEMPLATE, cpu_id); + + fd = open(path, O_RDONLY); + if (fd < 0) { + error_report("Failed to open MSR file at %s", path); + return result; + } + + if (pread(fd, &result, sizeof(result), msr_register) != sizeof(result)) { + error_report("Failed to read MSR"); + result = 0; + } + + close(fd); + return result; +} + +static void usage(const char *name) +{ + (printf) ( +"Usage: %s [OPTIONS] FILE\n" +"Virtual RAPL MSR helper program for QEMU\n" +"\n" +" -h, --help display this help and exit\n" +" -V, --version output version information and exit\n" +"\n" +" -d, --daemon run in the background\n" +" -f, --pidfile=PATH PID file when running as a daemon\n" +" (default '%s')\n" +" -k, --socket=PATH path to the unix socket\n" +" (default '%s')\n" +" -T, --trace [[enable=]][,events=][,file=]\n" +" specify tracing options\n" +#ifdef CONFIG_LIBCAP_NG +" -u, --user=USER user to drop privileges to\n" +" -g, --group=GROUP group to drop privileges to\n" +#endif +"\n" +QEMU_HELP_BOTTOM "\n" + , name, pidfile, socket_path); +} + +static void version(const char *name) +{ + printf( +"%s " QEMU_FULL_VERSION "\n" +"Written by Anthony Harivel.\n" +"\n" +QEMU_COPYRIGHT "\n" +"This is free software; see the source for copying conditions. There is NO\n" +"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" + , name); +} + +typedef struct VMSRHelperClient { + QIOChannelSocket *ioc; + Coroutine *co; +} VMSRHelperClient; + +static void coroutine_fn vh_co_entry(void *opaque) +{ + VMSRHelperClient *client = opaque; + Error *local_err = NULL; + unsigned int peer_pid; + uint32_t request[3]; + uint64_t vmsr; + int r; + + qio_channel_set_blocking(QIO_CHANNEL(client->ioc), + false, NULL); + + qio_channel_set_follow_coroutine_ctx(QIO_CHANNEL(client->ioc), true); + + /* + * Check peer credentials + */ + r = qio_channel_get_peerpid(QIO_CHANNEL(client->ioc), + &peer_pid, + &local_err); + if (r < 0) { + error_report_err(local_err); + goto out; + } + + while (r < 0) { + /* + * Read the requested MSR + * Only RAPL MSR in rapl-msr-index.h is allowed + */ + r = qio_channel_read_all(QIO_CHANNEL(client->ioc), + (char *) &request, sizeof(request), &local_err); + if (r < 0) { + error_report_err(local_err); + break; + } + + if (!is_msr_allowed(request[0])) { + error_report("Requested unallowed msr: %d", request[0]); + break; + } + + vmsr = vmsr_read_msr(request[0], request[1]); + + if (!is_tid_present(peer_pid, request[2])) { + error_report("Requested TID not in peer PID: %d %d", + peer_pid, request[2]); + vmsr = 0; + } + + r = qio_channel_write_all(QIO_CHANNEL(client->ioc), + (char *) &vmsr, + sizeof(vmsr), + &local_err); + if (r < 0) { + error_report_err(local_err); + break; + } + } +out: + object_unref(OBJECT(client->ioc)); + g_free(client); +} + +static gboolean accept_client(QIOChannel *ioc, + GIOCondition cond, + gpointer opaque) +{ + QIOChannelSocket *cioc; + VMSRHelperClient *vmsrh; + + cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), + NULL); + if (!cioc) { + return TRUE; + } + + vmsrh = g_new(VMSRHelperClient, 1); + vmsrh->ioc = cioc; + vmsrh->co = qemu_coroutine_create(vh_co_entry, vmsrh); + qemu_coroutine_enter(vmsrh->co); + + return TRUE; +} + +static void termsig_handler(int signum) +{ + qatomic_cmpxchg(&state, RUNNING, TERMINATE); + qemu_notify_event(); +} + +static void close_server_socket(void) +{ + assert(server_ioc); + + g_source_remove(server_watch); + server_watch = -1; + object_unref(OBJECT(server_ioc)); + num_active_sockets--; +} + +#ifdef CONFIG_LIBCAP_NG +static int drop_privileges(void) +{ + /* clear all capabilities */ + capng_clear(CAPNG_SELECT_BOTH); + + if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, + CAP_SYS_RAWIO) < 0) { + return -1; + } + + return 0; +} +#endif + +int main(int argc, char **argv) +{ + const char *sopt = "hVk:f:dT:u:g:vq"; + struct option lopt[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "socket", required_argument, NULL, 'k' }, + { "pidfile", required_argument, NULL, 'f' }, + { "daemon", no_argument, NULL, 'd' }, + { "trace", required_argument, NULL, 'T' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } + }; + int opt_ind = 0; + int ch; + Error *local_err = NULL; + bool daemonize = false; + bool pidfile_specified = false; + bool socket_path_specified = false; + unsigned socket_activation; + + struct sigaction sa_sigterm; + memset(&sa_sigterm, 0, sizeof(sa_sigterm)); + sa_sigterm.sa_handler = termsig_handler; + sigaction(SIGTERM, &sa_sigterm, NULL); + sigaction(SIGINT, &sa_sigterm, NULL); + sigaction(SIGHUP, &sa_sigterm, NULL); + + signal(SIGPIPE, SIG_IGN); + + error_init(argv[0]); + module_call_init(MODULE_INIT_TRACE); + module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_trace_opts); + qemu_init_exec_dir(argv[0]); + + compute_default_paths(); + + /* + * Sanity check + * 1. cpu must be Intel cpu + * 2. RAPL must be enabled + */ + if (!is_intel_processor()) { + error_report("error: CPU is not INTEL cpu"); + exit(EXIT_FAILURE); + } + + if (!is_rapl_enabled()) { + error_report("error: RAPL driver not enable"); + exit(EXIT_FAILURE); + } + + while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { + switch (ch) { + case 'k': + g_free(socket_path); + socket_path = g_strdup(optarg); + socket_path_specified = true; + if (socket_path[0] != '/') { + error_report("socket path must be absolute"); + exit(EXIT_FAILURE); + } + break; + case 'f': + g_free(pidfile); + pidfile = g_strdup(optarg); + pidfile_specified = true; + break; +#ifdef CONFIG_LIBCAP_NG + case 'u': { + unsigned long res; + struct passwd *userinfo = getpwnam(optarg); + if (userinfo) { + uid = userinfo->pw_uid; + } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 && + (uid_t)res == res) { + uid = res; + } else { + error_report("invalid user '%s'", optarg); + exit(EXIT_FAILURE); + } + break; + } + case 'g': { + unsigned long res; + struct group *groupinfo = getgrnam(optarg); + if (groupinfo) { + gid = groupinfo->gr_gid; + } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 && + (gid_t)res == res) { + gid = res; + } else { + error_report("invalid group '%s'", optarg); + exit(EXIT_FAILURE); + } + break; + } +#else + case 'u': + case 'g': + error_report("-%c not supported by this %s", ch, argv[0]); + exit(1); +#endif + case 'd': + daemonize = true; + break; + case 'T': + trace_opt_parse(optarg); + break; + case 'V': + version(argv[0]); + exit(EXIT_SUCCESS); + break; + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + case '?': + error_report("Try `%s --help' for more information.", argv[0]); + exit(EXIT_FAILURE); + } + } + + if (!trace_init_backends()) { + exit(EXIT_FAILURE); + } + trace_init_file(); + qemu_set_log(LOG_TRACE, &error_fatal); + + socket_activation = check_socket_activation(); + if (socket_activation == 0) { + SocketAddress saddr; + saddr = (SocketAddress){ + .type = SOCKET_ADDRESS_TYPE_UNIX, + .u.q_unix.path = socket_path, + }; + server_ioc = qio_channel_socket_new(); + if (qio_channel_socket_listen_sync(server_ioc, &saddr, + 1, &local_err) < 0) { + object_unref(OBJECT(server_ioc)); + error_report_err(local_err); + return 1; + } + } else { + /* Using socket activation - check user didn't use -p etc. */ + if (socket_path_specified) { + error_report("Unix socket can't be set when" + "using socket activation"); + exit(EXIT_FAILURE); + } + + /* Can only listen on a single socket. */ + if (socket_activation > 1) { + error_report("%s does not support socket activation" + "with LISTEN_FDS > 1", + argv[0]); + exit(EXIT_FAILURE); + } + server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD, + &local_err); + if (server_ioc == NULL) { + error_reportf_err(local_err, + "Failed to use socket activation: "); + exit(EXIT_FAILURE); + } + } + + qemu_init_main_loop(&error_fatal); + + server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc), + G_IO_IN, + accept_client, + NULL, NULL); + + if (daemonize) { + if (daemon(0, 0) < 0) { + error_report("Failed to daemonize: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + } + + if (daemonize || pidfile_specified) { + qemu_write_pidfile(pidfile, &error_fatal); + } + +#ifdef CONFIG_LIBCAP_NG + if (drop_privileges() < 0) { + error_report("Failed to drop privileges: %s", strerror(errno)); + exit(EXIT_FAILURE); + } +#endif + + info_report("Listening on %s", socket_path); + + state = RUNNING; + do { + main_loop_wait(false); + if (state == TERMINATE) { + state = TERMINATING; + close_server_socket(); + } + } while (num_active_sockets > 0); + + exit(EXIT_SUCCESS); +} diff --git a/contrib/systemd/qemu-vmsr-helper.service b/contrib/systemd/qemu-vmsr-helper.service new file mode 100644 index 00000000000..8fd397bf79a --- /dev/null +++ b/contrib/systemd/qemu-vmsr-helper.service @@ -0,0 +1,15 @@ +[Unit] +Description=Virtual RAPL MSR Daemon for QEMU + +[Service] +WorkingDirectory=/tmp +Type=simple +ExecStart=/usr/bin/qemu-vmsr-helper +PrivateTmp=yes +ProtectSystem=strict +ReadWritePaths=/var/run +RestrictAddressFamilies=AF_UNIX +Restart=always +RestartSec=0 + +[Install] diff --git a/contrib/systemd/qemu-vmsr-helper.socket b/contrib/systemd/qemu-vmsr-helper.socket new file mode 100644 index 00000000000..183e8304d6e --- /dev/null +++ b/contrib/systemd/qemu-vmsr-helper.socket @@ -0,0 +1,9 @@ +[Unit] +Description=Virtual RAPL MSR helper for QEMU + +[Socket] +ListenStream=/run/qemu-vmsr-helper.sock +SocketMode=0600 + +[Install] +WantedBy=multi-user.target From patchwork Tue Jul 23 14:15:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740117 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 16EC7C3DA49 for ; Tue, 23 Jul 2024 14:17:06 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJ8-0004tk-8g; Tue, 23 Jul 2024 10:16:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ3-0004bS-Qi for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:57 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGIy-00078l-Ac for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:57 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744150; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TR3RRaciA/WoYkHATR1ge4e+98YnIBj9erxRcbo+zIM=; b=Yp4o/yK/NQGNvmyDn3smOrZp/p4iEQ+BYkibUprblkxyUv99mneAWsAAvnFqL3nmZ0B2/C bqXGJ23ELPkbnoLktMn6wwCTDbpaGmvK9bYMPzpYpxiFmNbtGlWTuryeBabdknV6a5SIqA q0OkNi66D3OjFrqfCUWKf//MyzP9NiQ= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-43-JA1FZ-dlOF26J08OFzarXg-1; Tue, 23 Jul 2024 10:15:45 -0400 X-MC-Unique: JA1FZ-dlOF26J08OFzarXg-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-4265464ddc9so25092145e9.1 for ; Tue, 23 Jul 2024 07:15:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744144; x=1722348944; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TR3RRaciA/WoYkHATR1ge4e+98YnIBj9erxRcbo+zIM=; b=H50yUwoetlwqkxq26lL0n0iwrEj+xILlzcXVUAlI5BDMAoFFuIPEc8Svub58VO55rb jyZ2dBWePqKg2WhpAiHMgONDZIOFKagNO8gInwWlIqKiYrgBJSq8RTV6EAch0OmUt7kl U238Y5q9qnd8KSCq2rVwnBydr/hVjabRTp7THMXYE1cEdDyxePwAP1FexskwYRcID5o9 M2B9mAbA+XgWlKTqMrnJqKhzaD6Bzu3VRWGGnaJzHixHuydWSmW0CBOc11YCvp6KWXtd fxVMNbiWgm9wGVZ7zEAZzygirz5u0bmgsG1YFur8Syt2uWm29kMxqp3sD09abQ4b/mkY U6AQ== X-Gm-Message-State: AOJu0YxPPaCeEsLgEqO/uLPQWkalvrYnNeSteLRs4op9pf89D02LUPLM 73GMLXvdhxM1czA/dkxQ0oOQzDXf1Sh1FiNC0IKMwhZe46xq/HfymGlfwK4jA0Hm3kyzh2nqhQ/ wOBbAER+16K41ZQkipuTmnciGsE2EK4bz2zO3vkO8GXhogeRV4Wg0DmeVXo/fv0tucVdNUDomTC hpcjLGsMfNJR3G6Iu9/y4d7rdlceupwJWDYZ6b X-Received: by 2002:a05:600c:3b93:b0:424:8dbe:817d with SMTP id 5b1f17b1804b1-427ef3638f7mr18157725e9.10.1721744143441; Tue, 23 Jul 2024 07:15:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH3zJWLHRmQvgiZCg4IfS1a/MrTfYaQig2YQ+nmwB0zBMQjcGPpCg5J985i3aUKTrlEHjzZIA== X-Received: by 2002:a05:600c:3b93:b0:424:8dbe:817d with SMTP id 5b1f17b1804b1-427ef3638f7mr18157275e9.10.1721744142535; Tue, 23 Jul 2024 07:15:42 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-427f1f52b8dsm16470995e9.1.2024.07.23.07.15.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:41 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: Anthony Harivel Subject: [PULL 04/11] Add support for RAPL MSRs in KVM/Qemu Date: Tue, 23 Jul 2024 16:15:22 +0200 Message-ID: <20240723141529.551737-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Anthony Harivel Starting with the "Sandy Bridge" generation, Intel CPUs provide a RAPL interface (Running Average Power Limit) for advertising the accumulated energy consumption of various power domains (e.g. CPU packages, DRAM, etc.). The consumption is reported via MSRs (model specific registers) like MSR_PKG_ENERGY_STATUS for the CPU package power domain. These MSRs are 64 bits registers that represent the accumulated energy consumption in micro Joules. They are updated by microcode every ~1ms. For now, KVM always returns 0 when the guest requests the value of these MSRs. Use the KVM MSR filtering mechanism to allow QEMU handle these MSRs dynamically in userspace. To limit the amount of system calls for every MSR call, create a new thread in QEMU that updates the "virtual" MSR values asynchronously. Each vCPU has its own vMSR to reflect the independence of vCPUs. The thread updates the vMSR values with the ratio of energy consumed of the whole physical CPU package the vCPU thread runs on and the thread's utime and stime values. All other non-vCPU threads are also taken into account. Their energy consumption is evenly distributed among all vCPUs threads running on the same physical CPU package. To overcome the problem that reading the RAPL MSR requires priviliged access, a socket communication between QEMU and the qemu-vmsr-helper is mandatory. You can specified the socket path in the parameter. This feature is activated with -accel kvm,rapl=true,path=/path/sock.sock Actual limitation: - Works only on Intel host CPU because AMD CPUs are using different MSR adresses. - Only the Package Power-Plane (MSR_PKG_ENERGY_STATUS) is reported at the moment. Signed-off-by: Anthony Harivel Link: https://lore.kernel.org/r/20240522153453.1230389-4-aharivel@redhat.com Signed-off-by: Paolo Bonzini --- docs/specs/index.rst | 1 + docs/specs/rapl-msr.rst | 155 ++++++++++++ include/sysemu/kvm_int.h | 32 +++ target/i386/cpu.h | 8 + target/i386/kvm/vmsr_energy.h | 99 ++++++++ accel/kvm/kvm-all.c | 27 +++ target/i386/kvm/kvm.c | 431 +++++++++++++++++++++++++++++++++- target/i386/kvm/vmsr_energy.c | 345 +++++++++++++++++++++++++++ target/i386/kvm/meson.build | 1 + 9 files changed, 1098 insertions(+), 1 deletion(-) create mode 100644 docs/specs/rapl-msr.rst create mode 100644 target/i386/kvm/vmsr_energy.h create mode 100644 target/i386/kvm/vmsr_energy.c diff --git a/docs/specs/index.rst b/docs/specs/index.rst index 1484e3e7607..e738ea7d102 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -33,3 +33,4 @@ guest hardware that is specific to QEMU. virt-ctlr vmcoreinfo vmgenid + rapl-msr diff --git a/docs/specs/rapl-msr.rst b/docs/specs/rapl-msr.rst new file mode 100644 index 00000000000..1202ee89bee --- /dev/null +++ b/docs/specs/rapl-msr.rst @@ -0,0 +1,155 @@ +================ +RAPL MSR support +================ + +The RAPL interface (Running Average Power Limit) is advertising the accumulated +energy consumption of various power domains (e.g. CPU packages, DRAM, etc.). + +The consumption is reported via MSRs (model specific registers) like +MSR_PKG_ENERGY_STATUS for the CPU package power domain. These MSRs are 64 bits +registers that represent the accumulated energy consumption in micro Joules. + +Thanks to the MSR Filtering patch [#a]_ not all MSRs are handled by KVM. Some +of them can now be handled by the userspace (QEMU). It uses a mechanism called +"MSR filtering" where a list of MSRs is given at init time of a VM to KVM so +that a callback is put in place. The design of this patch uses only this +mechanism for handling the MSRs between guest/host. + +At the moment the following MSRs are involved: + +.. code:: C + + #define MSR_RAPL_POWER_UNIT 0x00000606 + #define MSR_PKG_POWER_LIMIT 0x00000610 + #define MSR_PKG_ENERGY_STATUS 0x00000611 + #define MSR_PKG_POWER_INFO 0x00000614 + +The ``*_POWER_UNIT``, ``*_POWER_LIMIT``, ``*_POWER INFO`` are part of the RAPL +spec and specify the power limit of the package, provide range of parameter(min +power, max power,..) and also the information of the multiplier for the energy +counter to calculate the power. Those MSRs are populated once at the beginning +by reading the host CPU MSRs and are given back to the guest 1:1 when +requested. + +The MSR_PKG_ENERGY_STATUS is a counter; it represents the total amount of +energy consumed since the last time the register was cleared. If you multiply +it with the UNIT provided above you'll get the power in micro-joules. This +counter is always increasing and it increases more or less faster depending on +the consumption of the package. This counter is supposed to overflow at some +point. + +Each core belonging to the same Package reading the MSR_PKG_ENERGY_STATUS (i.e +"rdmsr 0x611") will retrieve the same value. The value represents the energy +for the whole package. Whatever Core reading it will get the same value and a +core that belongs to PKG-0 will not be able to get the value of PKG-1 and +vice-versa. + +High level implementation +------------------------- + +In order to update the value of the virtual MSR, a QEMU thread is created. +The thread is basically just an infinity loop that does: + +1. Snapshot of the time metrics of all QEMU threads (Time spent scheduled in + Userspace and System) + +2. Snapshot of the actual MSR_PKG_ENERGY_STATUS counter of all packages where + the QEMU threads are running on. + +3. Sleep for 1 second - During this pause the vcpu and other non-vcpu threads + will do what they have to do and so the energy counter will increase. + +4. Repeat 2. and 3. and calculate the delta of every metrics representing the + time spent scheduled for each QEMU thread *and* the energy spent by the + packages during the pause. + +5. Filter the vcpu threads and the non-vcpu threads. + +6. Retrieve the topology of the Virtual Machine. This helps identify which + vCPU is running on which virtual package. + +7. The total energy spent by the non-vcpu threads is divided by the number + of vcpu threads so that each vcpu thread will get an equal part of the + energy spent by the QEMU workers. + +8. Calculate the ratio of energy spent per vcpu threads. + +9. Calculate the energy for each virtual package. + +10. The virtual MSRs are updated for each virtual package. Each vCPU that + belongs to the same package will return the same value when accessing the + the MSR. + +11. Loop back to 1. + +Ratio calculation +----------------- + +In Linux, a process has an execution time associated with it. The scheduler is +dividing the time in clock ticks. The number of clock ticks per second can be +found by the sysconf system call. A typical value of clock ticks per second is +100. So a core can run a process at the maximum of 100 ticks per second. If a +package has 4 cores, 400 ticks maximum can be scheduled on all the cores +of the package for a period of 1 second. + +The /proc/[pid]/stat [#b]_ is a sysfs file that can give the executed time of a +process with the [pid] as the process ID. It gives the amount of ticks the +process has been scheduled in userspace (utime) and kernel space (stime). + +By reading those metrics for a thread, one can calculate the ratio of time the +package has spent executing the thread. + +Example: + +A 4 cores package can schedule a maximum of 400 ticks per second with 100 ticks +per second per core. If a thread was scheduled for 100 ticks between a second +on this package, that means my thread has been scheduled for 1/4 of the whole +package. With that, the calculation of the energy spent by the thread on this +package during this whole second is 1/4 of the total energy spent by the +package. + +Usage +----- + +Currently this feature is only working on an Intel CPU that has the RAPL driver +mounted and available in the sysfs. if not, QEMU fails at start-up. + +This feature is activated with -accel +kvm,rapl=true,rapl-helper-socket=/path/sock.sock + +It is important that the socket path is the same as the one +:program:`qemu-vmsr-helper` is listening to. + +qemu-vmsr-helper +---------------- + +The qemu-vmsr-helper is working very much like the qemu-pr-helper. Instead of +making persistent reservation, qemu-vmsr-helper is here to overcome the +CVE-2020-8694 which remove user access to the rapl msr attributes. + +A socket communication is established between QEMU processes that has the RAPL +MSR support activated and the qemu-vmsr-helper. A systemd service and socket +activation is provided in contrib/systemd/qemu-vmsr-helper.(service/socket). + +The systemd socket uses 600, like contrib/systemd/qemu-pr-helper.socket. The +socket can be passed via SCM_RIGHTS by libvirt, or its permissions can be +changed (e.g. 660 and root:kvm for a Debian system for example). Libvirt could +also start a separate helper if needed. All in all, the policy is left to the +user. + +See the qemu-pr-helper documentation or manpage for further details. + +Current Limitations +------------------- + +- Works only on Intel host CPUs because AMD CPUs are using different MSR + addresses. + +- Only the Package Power-Plane (MSR_PKG_ENERGY_STATUS) is reported at the + moment. + +References +---------- + +.. [#a] https://patchwork.kernel.org/project/kvm/patch/20200916202951.23760-7-graf@amazon.com/ +.. [#b] https://man7.org/linux/man-pages/man5/proc.5.html diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 3f3d13f8166..1d8fb1473bd 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -14,6 +14,9 @@ #include "qemu/accel.h" #include "qemu/queue.h" #include "sysemu/kvm.h" +#include "hw/boards.h" +#include "hw/i386/topology.h" +#include "io/channel-socket.h" typedef struct KVMSlot { @@ -50,6 +53,34 @@ typedef struct KVMMemoryListener { #define KVM_MSI_HASHTAB_SIZE 256 +typedef struct KVMHostTopoInfo { + /* Number of package on the Host */ + unsigned int maxpkgs; + /* Number of cpus on the Host */ + unsigned int maxcpus; + /* Number of cpus on each different package */ + unsigned int *pkg_cpu_count; + /* Each package can have different maxticks */ + unsigned int *maxticks; +} KVMHostTopoInfo; + +struct KVMMsrEnergy { + pid_t pid; + bool enable; + char *socket_path; + QIOChannelSocket *sioc; + QemuThread msr_thr; + unsigned int guest_vcpus; + unsigned int guest_vsockets; + X86CPUTopoInfo guest_topo_info; + KVMHostTopoInfo host_topo; + const CPUArchIdList *guest_cpu_list; + uint64_t *msr_value; + uint64_t msr_unit; + uint64_t msr_limit; + uint64_t msr_info; +}; + enum KVMDirtyRingReaperState { KVM_DIRTY_RING_REAPER_NONE = 0, /* The reaper is sleeping */ @@ -117,6 +148,7 @@ struct KVMState bool kvm_dirty_ring_with_bitmap; uint64_t kvm_eager_split_size; /* Eager Page Splitting chunk size */ struct KVMDirtyRingReaper reaper; + struct KVMMsrEnergy msr_energy; NotifyVmexitOption notify_vmexit; uint32_t notify_window; uint32_t xen_version; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 1e121acef54..c6cc035df3d 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -414,6 +414,10 @@ typedef enum X86Seg { #define MSR_IA32_TSX_CTRL 0x122 #define MSR_IA32_TSCDEADLINE 0x6e0 #define MSR_IA32_PKRS 0x6e1 +#define MSR_RAPL_POWER_UNIT 0x00000606 +#define MSR_PKG_POWER_LIMIT 0x00000610 +#define MSR_PKG_ENERGY_STATUS 0x00000611 +#define MSR_PKG_POWER_INFO 0x00000614 #define MSR_ARCH_LBR_CTL 0x000014ce #define MSR_ARCH_LBR_DEPTH 0x000014cf #define MSR_ARCH_LBR_FROM_0 0x00001500 @@ -1880,6 +1884,10 @@ typedef struct CPUArchState { uintptr_t retaddr; + /* RAPL MSR */ + uint64_t msr_rapl_power_unit; + uint64_t msr_pkg_energy_status; + /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; diff --git a/target/i386/kvm/vmsr_energy.h b/target/i386/kvm/vmsr_energy.h new file mode 100644 index 00000000000..16cc1f4814f --- /dev/null +++ b/target/i386/kvm/vmsr_energy.h @@ -0,0 +1,99 @@ +/* + * QEMU KVM support -- x86 virtual energy-related MSR. + * + * Copyright 2024 Red Hat, Inc. 2024 + * + * Author: + * Anthony Harivel + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef VMSR_ENERGY_H +#define VMSR_ENERGY_H + +#include +#include "qemu/osdep.h" +#include "io/channel-socket.h" +#include "hw/i386/topology.h" + +/* + * Define the interval time in micro seconds between 2 samples of + * energy related MSRs + */ +#define MSR_ENERGY_THREAD_SLEEP_US 1000000.0 + +/* + * Thread statistic + * @ thread_id: TID (thread ID) + * @ is_vcpu: true if TID is vCPU thread + * @ cpu_id: CPU number last executed on + * @ pkg_id: package number of the CPU + * @ vcpu_id: vCPU ID + * @ vpkg: virtual package number + * @ acpi_id: APIC id of the vCPU + * @ utime: amount of clock ticks the thread + * has been scheduled in User mode + * @ stime: amount of clock ticks the thread + * has been scheduled in System mode + * @ delta_ticks: delta of utime+stime between + * the two samples (before/after sleep) + */ +struct vmsr_thread_stat { + unsigned int thread_id; + bool is_vcpu; + unsigned int cpu_id; + unsigned int pkg_id; + unsigned int vpkg_id; + unsigned int vcpu_id; + unsigned long acpi_id; + unsigned long long *utime; + unsigned long long *stime; + unsigned long long delta_ticks; +}; + +/* + * Package statistic + * @ e_start: package energy counter before the sleep + * @ e_end: package energy counter after the sleep + * @ e_delta: delta of package energy counter + * @ e_ratio: store the energy ratio of non-vCPU thread + * @ nb_vcpu: number of vCPU running on this package + */ +struct vmsr_package_energy_stat { + uint64_t e_start; + uint64_t e_end; + uint64_t e_delta; + uint64_t e_ratio; + unsigned int nb_vcpu; +}; + +typedef struct vmsr_thread_stat vmsr_thread_stat; +typedef struct vmsr_package_energy_stat vmsr_package_energy_stat; + +char *vmsr_compute_default_paths(void); +void vmsr_read_thread_stat(pid_t pid, + unsigned int thread_id, + unsigned long long *utime, + unsigned long long *stime, + unsigned int *cpu_id); + +QIOChannelSocket *vmsr_open_socket(const char *path); +uint64_t vmsr_read_msr(uint32_t reg, uint32_t cpu_id, + uint32_t tid, QIOChannelSocket *sioc); +void vmsr_delta_ticks(vmsr_thread_stat *thd_stat, int i); +unsigned int vmsr_get_maxcpus(void); +unsigned int vmsr_get_max_physical_package(unsigned int max_cpus); +unsigned int vmsr_count_cpus_per_package(unsigned int *package_count, + unsigned int max_pkgs); +int vmsr_get_physical_package_id(int cpu_id); +pid_t *vmsr_get_thread_ids(pid_t pid, unsigned int *num_threads); +double vmsr_get_ratio(uint64_t e_delta, + unsigned long long delta_ticks, + unsigned int maxticks); +void vmsr_init_topo_info(X86CPUTopoInfo *topo_info, const MachineState *ms); +bool is_host_cpu_intel(void); +int is_rapl_enabled(void); +#endif /* VMSR_ENERGY_H */ diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 64bf47a0330..480c7119d1c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3745,6 +3745,21 @@ static void kvm_set_device(Object *obj, s->device = g_strdup(value); } +static void kvm_set_kvm_rapl(Object *obj, bool value, Error **errp) +{ + KVMState *s = KVM_STATE(obj); + s->msr_energy.enable = value; +} + +static void kvm_set_kvm_rapl_socket_path(Object *obj, + const char *str, + Error **errp) +{ + KVMState *s = KVM_STATE(obj); + g_free(s->msr_energy.socket_path); + s->msr_energy.socket_path = g_strdup(str); +} + static void kvm_accel_instance_init(Object *obj) { KVMState *s = KVM_STATE(obj); @@ -3764,6 +3779,7 @@ static void kvm_accel_instance_init(Object *obj) s->xen_gnttab_max_frames = 64; s->xen_evtchn_max_pirq = 256; s->device = NULL; + s->msr_energy.enable = false; } /** @@ -3808,6 +3824,17 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "device", "Path to the device node to use (default: /dev/kvm)"); + object_class_property_add_bool(oc, "rapl", + NULL, + kvm_set_kvm_rapl); + object_class_property_set_description(oc, "rapl", + "Allow energy related MSRs for RAPL interface in Guest"); + + object_class_property_add_str(oc, "rapl-helper-socket", NULL, + kvm_set_kvm_rapl_socket_path); + object_class_property_set_description(oc, "rapl-helper-socket", + "Socket Path for comminucating with the Virtual MSR helper daemon"); + kvm_arch_accel_class_init(oc); } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index becca2efa5b..b4aab9a410b 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -16,9 +16,12 @@ #include "qapi/qapi-events-run-state.h" #include "qapi/error.h" #include "qapi/visitor.h" +#include #include #include #include +#include +#include #include #include @@ -27,6 +30,7 @@ #include "cpu.h" #include "host-cpu.h" +#include "vmsr_energy.h" #include "sysemu/sysemu.h" #include "sysemu/hw_accel.h" #include "sysemu/kvm_int.h" @@ -2559,7 +2563,8 @@ static int kvm_get_supported_msrs(KVMState *s) return ret; } -static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr, +static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, + uint32_t msr, uint64_t *val) { CPUState *cs = CPU(cpu); @@ -2570,6 +2575,53 @@ static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr, return true; } +static bool kvm_rdmsr_rapl_power_unit(X86CPU *cpu, + uint32_t msr, + uint64_t *val) +{ + + CPUState *cs = CPU(cpu); + + *val = cs->kvm_state->msr_energy.msr_unit; + + return true; +} + +static bool kvm_rdmsr_pkg_power_limit(X86CPU *cpu, + uint32_t msr, + uint64_t *val) +{ + + CPUState *cs = CPU(cpu); + + *val = cs->kvm_state->msr_energy.msr_limit; + + return true; +} + +static bool kvm_rdmsr_pkg_power_info(X86CPU *cpu, + uint32_t msr, + uint64_t *val) +{ + + CPUState *cs = CPU(cpu); + + *val = cs->kvm_state->msr_energy.msr_info; + + return true; +} + +static bool kvm_rdmsr_pkg_energy_status(X86CPU *cpu, + uint32_t msr, + uint64_t *val) +{ + + CPUState *cs = CPU(cpu); + *val = cs->kvm_state->msr_energy.msr_value[cs->cpu_index]; + + return true; +} + static Notifier smram_machine_done; static KVMMemoryListener smram_listener; static AddressSpace smram_address_space; @@ -2604,6 +2656,340 @@ static void register_smram_listener(Notifier *n, void *unused) &smram_address_space, 1, "kvm-smram"); } +static void *kvm_msr_energy_thread(void *data) +{ + KVMState *s = data; + struct KVMMsrEnergy *vmsr = &s->msr_energy; + + g_autofree vmsr_package_energy_stat *pkg_stat = NULL; + g_autofree vmsr_thread_stat *thd_stat = NULL; + g_autofree CPUState *cpu = NULL; + g_autofree unsigned int *vpkgs_energy_stat = NULL; + unsigned int num_threads = 0; + + X86CPUTopoIDs topo_ids; + + rcu_register_thread(); + + /* Allocate memory for each package energy status */ + pkg_stat = g_new0(vmsr_package_energy_stat, vmsr->host_topo.maxpkgs); + + /* Allocate memory for thread stats */ + thd_stat = g_new0(vmsr_thread_stat, 1); + + /* Allocate memory for holding virtual package energy counter */ + vpkgs_energy_stat = g_new0(unsigned int, vmsr->guest_vsockets); + + /* Populate the max tick of each packages */ + for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) { + /* + * Max numbers of ticks per package + * Time in second * Number of ticks/second * Number of cores/package + * ex: 100 ticks/second/CPU, 12 CPUs per Package gives 1200 ticks max + */ + vmsr->host_topo.maxticks[i] = (MSR_ENERGY_THREAD_SLEEP_US / 1000000) + * sysconf(_SC_CLK_TCK) + * vmsr->host_topo.pkg_cpu_count[i]; + } + + while (true) { + /* Get all qemu threads id */ + g_autofree pid_t *thread_ids = + thread_ids = vmsr_get_thread_ids(vmsr->pid, &num_threads); + + if (thread_ids == NULL) { + goto clean; + } + + thd_stat = g_renew(vmsr_thread_stat, thd_stat, num_threads); + /* Unlike g_new0, g_renew0 function doesn't exist yet... */ + memset(thd_stat, 0, num_threads * sizeof(vmsr_thread_stat)); + + /* Populate all the thread stats */ + for (int i = 0; i < num_threads; i++) { + thd_stat[i].utime = g_new0(unsigned long long, 2); + thd_stat[i].stime = g_new0(unsigned long long, 2); + thd_stat[i].thread_id = thread_ids[i]; + vmsr_read_thread_stat(vmsr->pid, + thd_stat[i].thread_id, + thd_stat[i].utime, + thd_stat[i].stime, + &thd_stat[i].cpu_id); + thd_stat[i].pkg_id = + vmsr_get_physical_package_id(thd_stat[i].cpu_id); + } + + /* Retrieve all packages power plane energy counter */ + for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) { + for (int j = 0; j < num_threads; j++) { + /* + * Use the first thread we found that ran on the CPU + * of the package to read the packages energy counter + */ + if (thd_stat[j].pkg_id == i) { + pkg_stat[i].e_start = + vmsr_read_msr(MSR_PKG_ENERGY_STATUS, + thd_stat[j].cpu_id, + thd_stat[j].thread_id, + s->msr_energy.sioc); + break; + } + } + } + + /* Sleep a short period while the other threads are working */ + usleep(MSR_ENERGY_THREAD_SLEEP_US); + + /* + * Retrieve all packages power plane energy counter + * Calculate the delta of all packages + */ + for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) { + for (int j = 0; j < num_threads; j++) { + /* + * Use the first thread we found that ran on the CPU + * of the package to read the packages energy counter + */ + if (thd_stat[j].pkg_id == i) { + pkg_stat[i].e_end = + vmsr_read_msr(MSR_PKG_ENERGY_STATUS, + thd_stat[j].cpu_id, + thd_stat[j].thread_id, + s->msr_energy.sioc); + /* + * Prevent the case we have migrate the VM + * during the sleep period or any other cases + * were energy counter might be lower after + * the sleep period. + */ + if (pkg_stat[i].e_end > pkg_stat[i].e_start) { + pkg_stat[i].e_delta = + pkg_stat[i].e_end - pkg_stat[i].e_start; + } else { + pkg_stat[i].e_delta = 0; + } + break; + } + } + } + + /* Delta of ticks spend by each thread between the sample */ + for (int i = 0; i < num_threads; i++) { + vmsr_read_thread_stat(vmsr->pid, + thd_stat[i].thread_id, + thd_stat[i].utime, + thd_stat[i].stime, + &thd_stat[i].cpu_id); + + if (vmsr->pid < 0) { + /* + * We don't count the dead thread + * i.e threads that existed before the sleep + * and not anymore + */ + thd_stat[i].delta_ticks = 0; + } else { + vmsr_delta_ticks(thd_stat, i); + } + } + + /* + * Identify the vcpu threads + * Calculate the number of vcpu per package + */ + CPU_FOREACH(cpu) { + for (int i = 0; i < num_threads; i++) { + if (cpu->thread_id == thd_stat[i].thread_id) { + thd_stat[i].is_vcpu = true; + thd_stat[i].vcpu_id = cpu->cpu_index; + pkg_stat[thd_stat[i].pkg_id].nb_vcpu++; + thd_stat[i].acpi_id = kvm_arch_vcpu_id(cpu); + break; + } + } + } + + /* Retrieve the virtual package number of each vCPU */ + for (int i = 0; i < vmsr->guest_cpu_list->len; i++) { + for (int j = 0; j < num_threads; j++) { + if ((thd_stat[j].acpi_id == + vmsr->guest_cpu_list->cpus[i].arch_id) + && (thd_stat[j].is_vcpu == true)) { + x86_topo_ids_from_apicid(thd_stat[j].acpi_id, + &vmsr->guest_topo_info, &topo_ids); + thd_stat[j].vpkg_id = topo_ids.pkg_id; + } + } + } + + /* Calculate the total energy of all non-vCPU thread */ + for (int i = 0; i < num_threads; i++) { + if ((thd_stat[i].is_vcpu != true) && + (thd_stat[i].delta_ticks > 0)) { + double temp; + temp = vmsr_get_ratio(pkg_stat[thd_stat[i].pkg_id].e_delta, + thd_stat[i].delta_ticks, + vmsr->host_topo.maxticks[thd_stat[i].pkg_id]); + pkg_stat[thd_stat[i].pkg_id].e_ratio + += (uint64_t)lround(temp); + } + } + + /* Calculate the ratio per non-vCPU thread of each package */ + for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) { + if (pkg_stat[i].nb_vcpu > 0) { + pkg_stat[i].e_ratio = pkg_stat[i].e_ratio / pkg_stat[i].nb_vcpu; + } + } + + /* + * Calculate the energy for each Package: + * Energy Package = sum of each vCPU energy that belongs to the package + */ + for (int i = 0; i < num_threads; i++) { + if ((thd_stat[i].is_vcpu == true) && \ + (thd_stat[i].delta_ticks > 0)) { + double temp; + temp = vmsr_get_ratio(pkg_stat[thd_stat[i].pkg_id].e_delta, + thd_stat[i].delta_ticks, + vmsr->host_topo.maxticks[thd_stat[i].pkg_id]); + vpkgs_energy_stat[thd_stat[i].vpkg_id] += + (uint64_t)lround(temp); + vpkgs_energy_stat[thd_stat[i].vpkg_id] += + pkg_stat[thd_stat[i].pkg_id].e_ratio; + } + } + + /* + * Finally populate the vmsr register of each vCPU with the total + * package value to emulate the real hardware where each CPU return the + * value of the package it belongs. + */ + for (int i = 0; i < num_threads; i++) { + if ((thd_stat[i].is_vcpu == true) && \ + (thd_stat[i].delta_ticks > 0)) { + vmsr->msr_value[thd_stat[i].vcpu_id] = \ + vpkgs_energy_stat[thd_stat[i].vpkg_id]; + } + } + + /* Freeing memory before zeroing the pointer */ + for (int i = 0; i < num_threads; i++) { + g_free(thd_stat[i].utime); + g_free(thd_stat[i].stime); + } + } + +clean: + rcu_unregister_thread(); + return NULL; +} + +static int kvm_msr_energy_thread_init(KVMState *s, MachineState *ms) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + struct KVMMsrEnergy *r = &s->msr_energy; + int ret = 0; + + /* + * Sanity check + * 1. Host cpu must be Intel cpu + * 2. RAPL must be enabled on the Host + */ + if (is_host_cpu_intel()) { + error_report("The RAPL feature can only be enabled on hosts\ + with Intel CPU models"); + ret = 1; + goto out; + } + + if (!is_rapl_enabled()) { + ret = 1; + goto out; + } + + /* Retrieve the virtual topology */ + vmsr_init_topo_info(&r->guest_topo_info, ms); + + /* Retrieve the number of vcpu */ + r->guest_vcpus = ms->smp.cpus; + + /* Retrieve the number of virtual sockets */ + r->guest_vsockets = ms->smp.sockets; + + /* Allocate register memory (MSR_PKG_STATUS) for each vcpu */ + r->msr_value = g_new0(uint64_t, r->guest_vcpus); + + /* Retrieve the CPUArchIDlist */ + r->guest_cpu_list = mc->possible_cpu_arch_ids(ms); + + /* Max number of cpus on the Host */ + r->host_topo.maxcpus = vmsr_get_maxcpus(); + if (r->host_topo.maxcpus == 0) { + error_report("host max cpus = 0"); + ret = 1; + goto out; + } + + /* Max number of packages on the host */ + r->host_topo.maxpkgs = vmsr_get_max_physical_package(r->host_topo.maxcpus); + if (r->host_topo.maxpkgs == 0) { + error_report("host max pkgs = 0"); + ret = 1; + goto out; + } + + /* Allocate memory for each package on the host */ + r->host_topo.pkg_cpu_count = g_new0(unsigned int, r->host_topo.maxpkgs); + r->host_topo.maxticks = g_new0(unsigned int, r->host_topo.maxpkgs); + + vmsr_count_cpus_per_package(r->host_topo.pkg_cpu_count, + r->host_topo.maxpkgs); + for (int i = 0; i < r->host_topo.maxpkgs; i++) { + if (r->host_topo.pkg_cpu_count[i] == 0) { + error_report("cpu per packages = 0 on package_%d", i); + ret = 1; + goto out; + } + } + + /* Get QEMU PID*/ + r->pid = getpid(); + + /* Compute the socket path if necessary */ + if (s->msr_energy.socket_path == NULL) { + s->msr_energy.socket_path = vmsr_compute_default_paths(); + } + + /* Open socket with vmsr helper */ + s->msr_energy.sioc = vmsr_open_socket(s->msr_energy.socket_path); + + if (s->msr_energy.sioc == NULL) { + error_report("vmsr socket opening failed"); + ret = 1; + goto out; + } + + /* Those MSR values should not change */ + r->msr_unit = vmsr_read_msr(MSR_RAPL_POWER_UNIT, 0, r->pid, + s->msr_energy.sioc); + r->msr_limit = vmsr_read_msr(MSR_PKG_POWER_LIMIT, 0, r->pid, + s->msr_energy.sioc); + r->msr_info = vmsr_read_msr(MSR_PKG_POWER_INFO, 0, r->pid, + s->msr_energy.sioc); + if (r->msr_unit == 0 || r->msr_limit == 0 || r->msr_info == 0) { + error_report("can't read any virtual msr"); + ret = 1; + goto out; + } + + qemu_thread_create(&r->msr_thr, "kvm-msr", + kvm_msr_energy_thread, + s, QEMU_THREAD_JOINABLE); +out: + return ret; +} + int kvm_arch_get_default_type(MachineState *ms) { return 0; @@ -2804,6 +3190,49 @@ int kvm_arch_init(MachineState *ms, KVMState *s) strerror(-ret)); exit(1); } + + if (s->msr_energy.enable == true) { + r = kvm_filter_msr(s, MSR_RAPL_POWER_UNIT, + kvm_rdmsr_rapl_power_unit, NULL); + if (!r) { + error_report("Could not install MSR_RAPL_POWER_UNIT \ + handler: %s", + strerror(-ret)); + exit(1); + } + + r = kvm_filter_msr(s, MSR_PKG_POWER_LIMIT, + kvm_rdmsr_pkg_power_limit, NULL); + if (!r) { + error_report("Could not install MSR_PKG_POWER_LIMIT \ + handler: %s", + strerror(-ret)); + exit(1); + } + + r = kvm_filter_msr(s, MSR_PKG_POWER_INFO, + kvm_rdmsr_pkg_power_info, NULL); + if (!r) { + error_report("Could not install MSR_PKG_POWER_INFO \ + handler: %s", + strerror(-ret)); + exit(1); + } + r = kvm_filter_msr(s, MSR_PKG_ENERGY_STATUS, + kvm_rdmsr_pkg_energy_status, NULL); + if (!r) { + error_report("Could not install MSR_PKG_ENERGY_STATUS \ + handler: %s", + strerror(-ret)); + exit(1); + } + r = kvm_msr_energy_thread_init(s, ms); + if (r) { + error_report("kvm : error RAPL feature requirement not meet"); + exit(1); + } + + } } return 0; diff --git a/target/i386/kvm/vmsr_energy.c b/target/i386/kvm/vmsr_energy.c new file mode 100644 index 00000000000..a1d78f2f2ae --- /dev/null +++ b/target/i386/kvm/vmsr_energy.c @@ -0,0 +1,345 @@ +/* + * QEMU KVM support -- x86 virtual RAPL msr + * + * Copyright 2024 Red Hat, Inc. 2024 + * + * Author: + * Anthony Harivel + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "vmsr_energy.h" +#include "io/channel.h" +#include "io/channel-socket.h" +#include "hw/boards.h" +#include "cpu.h" +#include "host-cpu.h" + +char *vmsr_compute_default_paths(void) +{ + g_autofree char *state = qemu_get_local_state_dir(); + + return g_build_filename(state, "run", "qemu-vmsr-helper.sock", NULL); +} + +bool is_host_cpu_intel(void) +{ + int family, model, stepping; + char vendor[CPUID_VENDOR_SZ + 1]; + + host_cpu_vendor_fms(vendor, &family, &model, &stepping); + + return strcmp(vendor, CPUID_VENDOR_INTEL); +} + +int is_rapl_enabled(void) +{ + const char *path = "/sys/class/powercap/intel-rapl/enabled"; + FILE *file = fopen(path, "r"); + int value = 0; + + if (file != NULL) { + if (fscanf(file, "%d", &value) != 1) { + error_report("INTEL RAPL not enabled"); + } + fclose(file); + } else { + error_report("Error opening %s", path); + } + + return value; +} + +QIOChannelSocket *vmsr_open_socket(const char *path) +{ + g_autofree char *socket_path = NULL; + + socket_path = g_strdup(path); + + SocketAddress saddr = { + .type = SOCKET_ADDRESS_TYPE_UNIX, + .u.q_unix.path = socket_path + }; + + QIOChannelSocket *sioc = qio_channel_socket_new(); + Error *local_err = NULL; + + qio_channel_set_name(QIO_CHANNEL(sioc), "vmsr-helper"); + qio_channel_socket_connect_sync(sioc, + &saddr, + &local_err); + if (local_err) { + /* Close socket. */ + qio_channel_close(QIO_CHANNEL(sioc), NULL); + object_unref(OBJECT(sioc)); + sioc = NULL; + goto out; + } + + qio_channel_set_delay(QIO_CHANNEL(sioc), false); +out: + return sioc; +} + +uint64_t vmsr_read_msr(uint32_t reg, uint32_t cpu_id, uint32_t tid, + QIOChannelSocket *sioc) +{ + uint64_t data = 0; + int r = 0; + Error *local_err = NULL; + uint32_t buffer[3]; + /* + * Send the required arguments: + * 1. RAPL MSR register to read + * 2. On which CPU ID + * 3. From which vCPU (Thread ID) + */ + buffer[0] = reg; + buffer[1] = cpu_id; + buffer[2] = tid; + + r = qio_channel_write_all(QIO_CHANNEL(sioc), + (char *)buffer, sizeof(buffer), + &local_err); + if (r < 0) { + goto out_close; + } + + r = qio_channel_read(QIO_CHANNEL(sioc), + (char *)&data, sizeof(data), + &local_err); + if (r < 0) { + data = 0; + goto out_close; + } + +out_close: + return data; +} + +/* Retrieve the max number of physical package */ +unsigned int vmsr_get_max_physical_package(unsigned int max_cpus) +{ + const char *dir = "/sys/devices/system/cpu/"; + const char *topo_path = "topology/physical_package_id"; + g_autofree int *uniquePackages = g_new0(int, max_cpus); + unsigned int packageCount = 0; + FILE *file = NULL; + + for (int i = 0; i < max_cpus; i++) { + g_autofree char *filePath = NULL; + g_autofree char *cpuid = g_strdup_printf("cpu%d", i); + + filePath = g_build_filename(dir, cpuid, topo_path, NULL); + + file = fopen(filePath, "r"); + + if (file == NULL) { + error_report("Error opening physical_package_id file"); + return 0; + } + + char packageId[10]; + if (fgets(packageId, sizeof(packageId), file) == NULL) { + packageCount = 0; + } + + fclose(file); + + int currentPackageId = atoi(packageId); + + bool isUnique = true; + for (int j = 0; j < packageCount; j++) { + if (uniquePackages[j] == currentPackageId) { + isUnique = false; + break; + } + } + + if (isUnique) { + uniquePackages[packageCount] = currentPackageId; + packageCount++; + + if (packageCount >= max_cpus) { + break; + } + } + } + + return (packageCount == 0) ? 1 : packageCount; +} + +/* Retrieve the max number of physical cpu on the host */ +unsigned int vmsr_get_maxcpus(void) +{ + GDir *dir; + const gchar *entry_name; + unsigned int cpu_count = 0; + const char *path = "/sys/devices/system/cpu/"; + + dir = g_dir_open(path, 0, NULL); + if (dir == NULL) { + error_report("Unable to open cpu directory"); + return -1; + } + + while ((entry_name = g_dir_read_name(dir)) != NULL) { + if (g_ascii_strncasecmp(entry_name, "cpu", 3) == 0 && + isdigit(entry_name[3])) { + cpu_count++; + } + } + + g_dir_close(dir); + + return cpu_count; +} + +/* Count the number of physical cpu on each packages */ +unsigned int vmsr_count_cpus_per_package(unsigned int *package_count, + unsigned int max_pkgs) +{ + g_autofree char *file_contents = NULL; + g_autofree char *path = NULL; + g_autofree char *path_name = NULL; + gsize length; + + /* Iterate over cpus and count cpus in each package */ + for (int cpu_id = 0; ; cpu_id++) { + path_name = g_strdup_printf("/sys/devices/system/cpu/cpu%d/" + "topology/physical_package_id", cpu_id); + + path = g_build_filename(path_name, NULL); + + if (!g_file_get_contents(path, &file_contents, &length, NULL)) { + break; /* No more cpus */ + } + + /* Get the physical package ID for this CPU */ + int package_id = atoi(file_contents); + + /* Check if the package ID is within the known number of packages */ + if (package_id >= 0 && package_id < max_pkgs) { + /* If yes, count the cpu for this package*/ + package_count[package_id]++; + } + } + + return 0; +} + +/* Get the physical package id from a given cpu id */ +int vmsr_get_physical_package_id(int cpu_id) +{ + g_autofree char *file_contents = NULL; + g_autofree char *file_path = NULL; + int package_id = -1; + gsize length; + + file_path = g_strdup_printf("/sys/devices/system/cpu/cpu%d" + "/topology/physical_package_id", cpu_id); + + if (!g_file_get_contents(file_path, &file_contents, &length, NULL)) { + goto out; + } + + package_id = atoi(file_contents); + +out: + return package_id; +} + +/* Read the scheduled time for a given thread of a give pid */ +void vmsr_read_thread_stat(pid_t pid, + unsigned int thread_id, + unsigned long long *utime, + unsigned long long *stime, + unsigned int *cpu_id) +{ + g_autofree char *path = NULL; + g_autofree char *path_name = NULL; + + path_name = g_strdup_printf("/proc/%u/task/%d/stat", pid, thread_id); + + path = g_build_filename(path_name, NULL); + + FILE *file = fopen(path, "r"); + if (file == NULL) { + pid = -1; + return; + } + + if (fscanf(file, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u" + " %llu %llu %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %*u" + " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*u %*u %u", + utime, stime, cpu_id) != 3) + { + pid = -1; + return; + } + + fclose(file); + return; +} + +/* Read QEMU stat task folder to retrieve all QEMU threads ID */ +pid_t *vmsr_get_thread_ids(pid_t pid, unsigned int *num_threads) +{ + g_autofree char *task_path = g_strdup_printf("%d/task", pid); + g_autofree char *path = g_build_filename("/proc", task_path, NULL); + + DIR *dir = opendir(path); + if (dir == NULL) { + error_report("Error opening /proc/qemu/task"); + return NULL; + } + + pid_t *thread_ids = NULL; + unsigned int thread_count = 0; + + g_autofree struct dirent *ent = NULL; + while ((ent = readdir(dir)) != NULL) { + if (ent->d_name[0] == '.') { + continue; + } + pid_t tid = atoi(ent->d_name); + if (pid != tid) { + thread_ids = g_renew(pid_t, thread_ids, (thread_count + 1)); + thread_ids[thread_count] = tid; + thread_count++; + } + } + + closedir(dir); + + *num_threads = thread_count; + return thread_ids; +} + +void vmsr_delta_ticks(vmsr_thread_stat *thd_stat, int i) +{ + thd_stat[i].delta_ticks = (thd_stat[i].utime[1] + thd_stat[i].stime[1]) + - (thd_stat[i].utime[0] + thd_stat[i].stime[0]); +} + +double vmsr_get_ratio(uint64_t e_delta, + unsigned long long delta_ticks, + unsigned int maxticks) +{ + return (e_delta / 100.0) * ((100.0 / maxticks) * delta_ticks); +} + +void vmsr_init_topo_info(X86CPUTopoInfo *topo_info, + const MachineState *ms) +{ + topo_info->dies_per_pkg = ms->smp.dies; + topo_info->modules_per_die = ms->smp.modules; + topo_info->cores_per_module = ms->smp.cores; + topo_info->threads_per_core = ms->smp.threads; +} + diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build index e7850981e62..3996cafaf29 100644 --- a/target/i386/kvm/meson.build +++ b/target/i386/kvm/meson.build @@ -3,6 +3,7 @@ i386_kvm_ss = ss.source_set() i386_kvm_ss.add(files( 'kvm.c', 'kvm-cpu.c', + 'vmsr_energy.c', )) i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c')) From patchwork Tue Jul 23 14:15:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740120 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 4BDCBC3DA63 for ; Tue, 23 Jul 2024 14:17:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJ5-0004gv-4L; Tue, 23 Jul 2024 10:15:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ2-0004Vt-S0 for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:57 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ0-00079K-3P for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744152; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hr9BZw+jnnZPYCHU7IVnZQe9pLLjGhNrmHmaZ/LVdfI=; b=KqfH5u4h6YB1D3P8hgRejRkraFhwEzS56DVhOqZjNVMxGmB8qObMQpHYqLuTP1nUhrHwy0 0AN80eGF0LHb5RMNPvteD8HEwiPNEMeoWVAe3+HbrUoaBOwUrkht+kb6q925Yj6eqp/Htc /okqjtddx3NGrGTeTj+Xy7R4PLVwAs0= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-680-EzBQE5EGNDuaci7VYFtvPQ-1; Tue, 23 Jul 2024 10:15:47 -0400 X-MC-Unique: EzBQE5EGNDuaci7VYFtvPQ-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-42674318a4eso57134055e9.1 for ; Tue, 23 Jul 2024 07:15:47 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744146; x=1722348946; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hr9BZw+jnnZPYCHU7IVnZQe9pLLjGhNrmHmaZ/LVdfI=; b=CgTGTMM75JAMWqZlX3KvMlwNRT5a+5sD3ssQC/M1m7BYvjZcoXKzqef5COlT4+RURm suemyRtDYD9fycRmnKv5opb0IMkUqfAIidVuL6TMSkJAHcu8Dvi+MclavMRLyD/WTlzj rtDbjTKex02D1qH8KVJPh1OVT52+IDkZlzair4co7RWp8Y3xYoMC9NRUQNDJYQCL9Bxc fZfTTg6rFUkzPWgDYoE7IIUMsX2st/0J68N3lxzLgNsYgqcCKLt3iPMR0r6zGmnJLAGB v36rMkkkpiVqg3ptiTk3CJExpaeYL1NaMd39wH+UtmwhecwbrkGD488Lk9CzD1A22dRX P2BQ== X-Gm-Message-State: AOJu0YzQpF6Wo2cxy1958oGqsnaKpm/U2CSKwkMNDBeK/NWer+nx89Jy bOJiqWeWYQ2m/KnJ75UPXchjs8fMnmYUJb6oWwSFROXrPYv+yO+bWUzQofjV0sNr/y4Qtv6H3D0 H9Gm41Wo5decEf9QAwtIOBJLDweYZyeYnZhX1cVaLYaKIKNQkEaho2mZ4AMu51uEHZrPPKFWRW8 hNAraNogG4fiYJEMR3FCbNsjVUQ+gJqoW/YXoe X-Received: by 2002:a5d:4005:0:b0:367:9c46:198 with SMTP id ffacd0b85a97d-369bae3a8b6mr8700755f8f.1.1721744146307; Tue, 23 Jul 2024 07:15:46 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEHaENQtffzWAnK/R1Mi7TVGE5ArkofLyJk7cc2MVrvetHi/JxCaVvbdrCIQ+cGDFJUPwXQEg== X-Received: by 2002:a5d:4005:0:b0:367:9c46:198 with SMTP id ffacd0b85a97d-369bae3a8b6mr8700722f8f.1.1721744145762; Tue, 23 Jul 2024 07:15:45 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-427d68fa394sm174019995e9.3.2024.07.23.07.15.44 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:44 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PULL 05/11] hpet: fix and cleanup persistence of interrupt status Date: Tue, 23 Jul 2024 16:15:23 +0200 Message-ID: <20240723141529.551737-6-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org There are several bugs in the handling of the ISR register: - switching level->edge was not lowering the interrupt and clearing ISR - switching on the enable bit was not raising a level-triggered interrupt if the timer had fired - the timer must be kept running even if not enabled, in order to set the ISR flag, so writes to HPET_TN_CFG must not call hpet_del_timer() Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 60 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 4cb5393c0b5..58073df02b5 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -196,21 +196,31 @@ static void update_irq(struct HPETTimer *timer, int set) } s = timer->state; mask = 1 << timer->tn; - if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) { + + if (set && (timer->config & HPET_TN_TYPE_LEVEL)) { + /* + * If HPET_TN_ENABLE bit is 0, "the timer will still operate and + * generate appropriate status bits, but will not cause an interrupt" + */ + s->isr |= mask; + } else { s->isr &= ~mask; + } + + if (set && timer_enabled(timer) && hpet_enabled(s)) { + if (timer_fsb_route(timer)) { + address_space_stl_le(&address_space_memory, timer->fsb >> 32, + timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED, + NULL); + } else if (timer->config & HPET_TN_TYPE_LEVEL) { + qemu_irq_raise(s->irqs[route]); + } else { + qemu_irq_pulse(s->irqs[route]); + } + } else { if (!timer_fsb_route(timer)) { qemu_irq_lower(s->irqs[route]); } - } else if (timer_fsb_route(timer)) { - address_space_stl_le(&address_space_memory, timer->fsb >> 32, - timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED, - NULL); - } else if (timer->config & HPET_TN_TYPE_LEVEL) { - s->isr |= mask; - qemu_irq_raise(s->irqs[route]); - } else { - s->isr &= ~mask; - qemu_irq_pulse(s->irqs[route]); } } @@ -414,8 +424,13 @@ static void hpet_set_timer(HPETTimer *t) static void hpet_del_timer(HPETTimer *t) { + HPETState *s = t->state; timer_del(t->qemu_timer); - update_irq(t, 0); + + if (s->isr & (1 << t->tn)) { + /* For level-triggered interrupt, this leaves ISR set but lowers irq. */ + update_irq(t, 1); + } } static uint64_t hpet_ram_read(void *opaque, hwaddr addr, @@ -515,20 +530,26 @@ static void hpet_ram_write(void *opaque, hwaddr addr, switch ((addr - 0x100) % 0x20) { case HPET_TN_CFG: trace_hpet_ram_write_tn_cfg(); - if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) { + if (deactivating_bit(old_val, new_val, HPET_TN_TYPE_LEVEL)) { + /* + * Do this before changing timer->config; otherwise, if + * HPET_TN_FSB is set, update_irq will not lower the qemu_irq. + */ update_irq(timer, 0); } val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); timer->config = (timer->config & 0xffffffff00000000ULL) | val; + if (activating_bit(old_val, new_val, HPET_TN_ENABLE) + && (s->isr & (1 << timer_id))) { + update_irq(timer, 1); + } + if (new_val & HPET_TN_32BIT) { timer->cmp = (uint32_t)timer->cmp; timer->period = (uint32_t)timer->period; } - if (activating_bit(old_val, new_val, HPET_TN_ENABLE) && - hpet_enabled(s)) { + if (hpet_enabled(s)) { hpet_set_timer(timer); - } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) { - hpet_del_timer(timer); } break; case HPET_TN_CFG + 4: // Interrupt capabilities @@ -606,9 +627,10 @@ static void hpet_ram_write(void *opaque, hwaddr addr, s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); for (i = 0; i < s->num_timers; i++) { - if ((&s->timer[i])->cmp != ~0ULL) { - hpet_set_timer(&s->timer[i]); + if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) { + update_irq(&s->timer[i], 1); } + hpet_set_timer(&s->timer[i]); } } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { /* Halt main counter and disable interrupt generation. */ From patchwork Tue Jul 23 14:15:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740113 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 EEC18C3DA63 for ; Tue, 23 Jul 2024 14:16:26 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJJ-0005GX-Pf; Tue, 23 Jul 2024 10:16:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ4-0004d4-6G for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:58 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ2-0007AD-Bw for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:57 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744153; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j4UwUK1qyFt8jfRv5O/+Xfolt2iTAQ7FuHpfmrN0EbA=; b=E5i2m/iMvShpZYWboL4kItjAqy3wi7dP6cgOY8Gv2nuf+gchKpNuLFCmofM66CFAC5aPQg 83F4HXnRJP4tEYV+I+I7AvERfGgjcvwnitmInCU4kw7a9yB8pxSyE5rNILPifYWanAiDWO Sb2Nf3IfX9YI3C93ctNa+8ZGk+SL/Qg= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-538-S-FNa-odOm2Zc5HSaRm-FA-1; Tue, 23 Jul 2024 10:15:50 -0400 X-MC-Unique: S-FNa-odOm2Zc5HSaRm-FA-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4279418eb2bso38070985e9.1 for ; Tue, 23 Jul 2024 07:15:50 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744149; x=1722348949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=j4UwUK1qyFt8jfRv5O/+Xfolt2iTAQ7FuHpfmrN0EbA=; b=W2KYipbf2uMl25G/8b8c6EQxjwrF/IS4qNBYPJQI2jJRpmT4TWFGXKMocURrpUIXFj FMc0h8XHN0QhssDophKMLvUjNEaEXERND5ov0iknT70RCOimM1jaz4mrpentcGnFXWL7 GmRPWTqChBprHCtlDSr5GV2ohGrDEuiuQA1+Lu7mr7/ps4K2aOk6fRfN5T4jkpB+jYgy iomxJuNZAJn9u8AAMjFeFCibXzbM/T7QeaifjF+6gF/jORVAffA/ysWWdsD+Mgkqkd1W 981aK0xkhRfMZRE+TIABNajf0Cl3G6S7sL4kO+pIorOpYT12bJlGxBigMBvx+gs0KPci gfLw== X-Gm-Message-State: AOJu0YwZBGP0T3p4ATX5jkeLS+He6D02qSrDKVK+gBoLOkqX4SH7wIeC l+1RPCwfBmi4b9YZbhCyY/08nh86zLbv74Mdxof1GBmhigToF6hvD2aHdqyv///L4LqvJW3avfq ZViDBkLmOrjOs+mpMvaPP0VvCUhntCT0p21NMT8W44nS40GppuE2Pu2QAzQ301sYkzMS5j9FmkJ KygtsijNZcwzg01zEufYzLH0ETl0pQYDRU1R8W X-Received: by 2002:a05:600c:c8f:b0:426:63f1:9a15 with SMTP id 5b1f17b1804b1-427dc522d2dmr70943835e9.9.1721744148810; Tue, 23 Jul 2024 07:15:48 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE6NSUjybDJ6E5Uoo/bO34cTzL8+q0jMFDFnq1KXWKKtp+hW8IIjDHNVg3A5Y8xOkDN0CvuHw== X-Received: by 2002:a05:600c:c8f:b0:426:63f1:9a15 with SMTP id 5b1f17b1804b1-427dc522d2dmr70943665e9.9.1721744148354; Tue, 23 Jul 2024 07:15:48 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-427ef3f459fsm15797165e9.0.2024.07.23.07.15.47 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:47 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PULL 06/11] hpet: ignore high bits of comparator in 32-bit mode Date: Tue, 23 Jul 2024 16:15:24 +0200 Message-ID: <20240723141529.551737-7-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 4 ++++ hw/timer/trace-events | 1 + 2 files changed, 5 insertions(+) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 58073df02b5..bbb1e5f0897 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -585,6 +585,10 @@ static void hpet_ram_write(void *opaque, hwaddr addr, } break; case HPET_TN_CMP + 4: // comparator register high order + if (timer->config & HPET_TN_32BIT) { + trace_hpet_ram_write_invalid_tn_cmp(); + break; + } trace_hpet_ram_write_tn_cmp(4); if (!timer_is_periodic(timer) || (timer->config & HPET_TN_SETVAL)) { diff --git a/hw/timer/trace-events b/hw/timer/trace-events index de769f4b716..a5fafbc6796 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -111,6 +111,7 @@ hpet_ram_write_timer_id(uint64_t timer_id) "hpet_ram_writel timer_id = 0x%" PRIx hpet_ram_write_tn_cfg(void) "hpet_ram_writel HPET_TN_CFG" hpet_ram_write_invalid_tn_cfg(uint8_t reg_off) "invalid HPET_TN_CFG + %" PRIu8 " write" hpet_ram_write_tn_cmp(uint8_t reg_off) "hpet_ram_writel HPET_TN_CMP + %" PRIu8 +hpet_ram_write_invalid_tn_cmp(void) "invalid HPET_TN_CMP + 4 write" hpet_ram_write_invalid(void) "invalid hpet_ram_writel" hpet_ram_write_counter_write_while_enabled(void) "Writing counter while HPET enabled!" hpet_ram_write_counter_written(uint8_t reg_off, uint64_t value, uint64_t counter) "HPET counter + %" PRIu8 "written. crt = 0x%" PRIx64 " -> 0x%" PRIx64 From patchwork Tue Jul 23 14:15:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740121 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 26124C3DA49 for ; Tue, 23 Jul 2024 14:17:36 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJA-0004w2-2N; Tue, 23 Jul 2024 10:16:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ5-0004ht-8F for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:59 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ3-0007BB-9V for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744155; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=X4p0LHYIjMjvQI23Lts1WhjklTNehlg506joAY8S7dI=; b=CaBVJ/O7vz7dHl2fyqV0oZdxvmYNiihfLV8LBlIWPiuODI29JVHcdAut0fSMp7h70hua3/ jXMFHz7zMGb3Otg4VppZNw3oohQaLhDfrj/IHxnu7GDSQ5Bgnlg/EV8oKJjDMZrgzVyQLb BjdKNwXsc/PAKlmyIHKG8/hpmv6bKhY= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-61-hY3r6ZBOOBixVmgIMmlxPQ-1; Tue, 23 Jul 2024 10:15:53 -0400 X-MC-Unique: hY3r6ZBOOBixVmgIMmlxPQ-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-42725ef39e2so40053135e9.0 for ; Tue, 23 Jul 2024 07:15:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744151; x=1722348951; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=X4p0LHYIjMjvQI23Lts1WhjklTNehlg506joAY8S7dI=; b=LQPBGi4EhNOueGItZdp5yY/izoiM7AfCU4nRkAEebQvDr242LE9P9lLkQ7QHApKXZp zOredWaqS9uyyaG32OoVTegBS3yVSSyBhspgm0+qZXBa0QrEOd1CCXWcWguVIP977s2W I3sQ3gVHyh3qTtGboMyTlDCvPVVC/mgb5THUYFsKwAxFjMc5R5zIDoY+4tzP3a7Ee88V BSQ5HBHBDzo1n13FjcZdnI6cfYVan90MySc5UIthl6e3ZTfbdtl+1jqHH1A/oOaBHdwe JCYrlJ6xlebxj2HbBUIjNgAITGlxdcviz+na6fdvBlVBpXZyaNOaQa8L4qkSgKS7xnOt SXHA== X-Gm-Message-State: AOJu0Ywax+GO44AQ6k9wHWyWKuoji7wv1W0iJ/flwXDR8oS6cHlhaUEw d46UBg0NOVemTF+AoZk6mgbAAQfcGs6cKSWuijxT2fmrLo1UZAJePT09kEtUhidixIMsrCKKpXK Yz3hm+RYQzBZh3z2/7anfmQYYEYk/Nl2Et4xXZHzC83oivMKp3jr2jhvshF48pVX0mlH20mZh// lVw5ojHiriJMlQQOG//uXKw93m9bClu6SRzUhv X-Received: by 2002:a05:600c:3ba4:b0:426:5269:9827 with SMTP id 5b1f17b1804b1-427dc4817d6mr80725495e9.0.1721744151362; Tue, 23 Jul 2024 07:15:51 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEbhialiTKcyHphI9IyZmhbdN1v/+4chrKOhhIhHp2VbW4vLCjBk+HZeU4kNXCJS3WXCdoImg== X-Received: by 2002:a05:600c:3ba4:b0:426:5269:9827 with SMTP id 5b1f17b1804b1-427dc4817d6mr80725315e9.0.1721744151050; Tue, 23 Jul 2024 07:15:51 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-427d69071d0sm178610065e9.26.2024.07.23.07.15.50 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:50 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PULL 07/11] hpet: remove unnecessary variable "index" Date: Tue, 23 Jul 2024 16:15:25 +0200 Message-ID: <20240723141529.551737-8-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index bbb1e5f0897..380e272fbeb 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -437,12 +437,12 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr, unsigned size) { HPETState *s = opaque; - uint64_t cur_tick, index; + uint64_t cur_tick; trace_hpet_ram_read(addr); - index = addr; + /*address range of all TN regs*/ - if (index >= 0x100 && index <= 0x3ff) { + if (addr >= 0x100 && addr <= 0x3ff) { uint8_t timer_id = (addr - 0x100) / 0x20; HPETTimer *timer = &s->timer[timer_id]; @@ -469,7 +469,7 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr, break; } } else { - switch (index) { + switch (addr) { case HPET_ID: return s->capability; case HPET_PERIOD: @@ -510,15 +510,14 @@ static void hpet_ram_write(void *opaque, hwaddr addr, { int i; HPETState *s = opaque; - uint64_t old_val, new_val, val, index; + uint64_t old_val, new_val, val; trace_hpet_ram_write(addr, value); - index = addr; old_val = hpet_ram_read(opaque, addr, 4); new_val = value; /*address range of all TN regs*/ - if (index >= 0x100 && index <= 0x3ff) { + if (addr >= 0x100 && addr <= 0x3ff) { uint8_t timer_id = (addr - 0x100) / 0x20; HPETTimer *timer = &s->timer[timer_id]; @@ -620,7 +619,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr, } return; } else { - switch (index) { + switch (addr) { case HPET_ID: return; case HPET_CFG: From patchwork Tue Jul 23 14:15:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740122 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 0E672C3DA7F for ; Tue, 23 Jul 2024 14:17:37 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJK-0005pB-7h; Tue, 23 Jul 2024 10:16:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ6-0004n1-BL for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:16:00 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJ4-0007Cf-GD for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:15:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744157; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SH5zwolTSCtrBQQLhcJsS5itYtwTMNlK41Ys5KgMIiY=; b=U3wU4ZYFLyhz4Wespq0Y5VKIr6vRXRVq/frBwNV8Rds9xeOIKJ9Bda7pgopIveHb3phgny ZJTRODG2nEQmJtZjgyKK8rJM23I58Fj6TBlxLdq1Z5eOnBOc5Rfd3DISyHhd25WRji1s9C 5G/z8YWm4y3tMf1nMZZUriVDFvMl5HA= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-620-QP2sPeAlPYG5L11ZrGhasw-1; Tue, 23 Jul 2024 10:15:55 -0400 X-MC-Unique: QP2sPeAlPYG5L11ZrGhasw-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-42660bca669so37990285e9.0 for ; Tue, 23 Jul 2024 07:15:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744154; x=1722348954; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=SH5zwolTSCtrBQQLhcJsS5itYtwTMNlK41Ys5KgMIiY=; b=wDf0u4IzsppdHRZ/tBdjHPO4kxdK27VlAkvxam9EkmgguYUVh3tHhsAUtajoJD82X5 aBN0d6F+MX8tIowJp5GLc6efUurgGXe+X8P5LfksxQ+57496AE5lc8iTy2mYMaWvSJUp DkJK8cBh5+enhsigpHJJhD0hLrLb0Sm6153RYrfOvFjiCxsgGRR8LA8175nqIOI1KcGE nCU37pcjiwry6e4603dzkC70xg17a5wKhjWcd4C/PWtjjPzTnpNhQ93IJz6/mFFGwVGp 4iLAAL5RW2UoLGbGroOeNM60ruXWrq8s+qcwjWsGTI914yPICSbFounW/ISVQAfml0yi D9nw== X-Gm-Message-State: AOJu0Yxu4tcnny8wQc74osTY9Nz/w3iVbF1AVjTUffNnO7B/KjL/8vPr kFQHV/K4zaUywxhx7/NLhEsfWKqoggJewhxCY/mfcB0IaiSOzrK5UayaUlFSho1Dsh20+Hybnr/ UsAomI3HigqhMX4rIboCKcFsR7Ot+vD2hq81OHzhb+0Ist+i8kNrNW7UyDvtxsliTy2UhsQPsk+ 1et2o6U0ze+s5dH/DOf/YtO4N8h7JXRQDgI5qZ X-Received: by 2002:a05:600c:4f0d:b0:426:5ee5:3129 with SMTP id 5b1f17b1804b1-427dc515367mr69171435e9.2.1721744153773; Tue, 23 Jul 2024 07:15:53 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFNOp9d6hFP+NpQkNTRYrKZVdTtf3UQ/unBSjrGHXaiLoEkZb6Lmaz0CmtgiyEXACIChg3xZg== X-Received: by 2002:a05:600c:4f0d:b0:426:5ee5:3129 with SMTP id 5b1f17b1804b1-427dc515367mr69171335e9.2.1721744153444; Tue, 23 Jul 2024 07:15:53 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-368787ec6e5sm11638830f8f.96.2024.07.23.07.15.52 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:53 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PULL 08/11] hpet: place read-only bits directly in "new_val" Date: Tue, 23 Jul 2024 16:15:26 +0200 Message-ID: <20240723141529.551737-9-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The variable "val" is used for two different purposes. As an intermediate value when writing configuration registers, and to store the cleared bits when writing ISR. Use "new_val" for the former, and rename the variable so that it is clearer for the latter case. Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 380e272fbeb..831e5a95b09 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -510,7 +510,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr, { int i; HPETState *s = opaque; - uint64_t old_val, new_val, val; + uint64_t old_val, new_val, cleared; trace_hpet_ram_write(addr, value); old_val = hpet_ram_read(opaque, addr, 4); @@ -536,13 +536,12 @@ static void hpet_ram_write(void *opaque, hwaddr addr, */ update_irq(timer, 0); } - val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); - timer->config = (timer->config & 0xffffffff00000000ULL) | val; + new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); + timer->config = (timer->config & 0xffffffff00000000ULL) | new_val; if (activating_bit(old_val, new_val, HPET_TN_ENABLE) && (s->isr & (1 << timer_id))) { update_irq(timer, 1); } - if (new_val & HPET_TN_32BIT) { timer->cmp = (uint32_t)timer->cmp; timer->period = (uint32_t)timer->period; @@ -623,8 +622,8 @@ static void hpet_ram_write(void *opaque, hwaddr addr, case HPET_ID: return; case HPET_CFG: - val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); - s->config = (s->config & 0xffffffff00000000ULL) | val; + new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); + s->config = (s->config & 0xffffffff00000000ULL) | new_val; if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { /* Enable main counter and interrupt generation. */ s->hpet_offset = @@ -658,9 +657,9 @@ static void hpet_ram_write(void *opaque, hwaddr addr, trace_hpet_invalid_hpet_cfg(4); break; case HPET_STATUS: - val = new_val & s->isr; + cleared = new_val & s->isr; for (i = 0; i < s->num_timers; i++) { - if (val & (1 << i)) { + if (cleared & (1 << i)) { update_irq(&s->timer[i], 0); } } From patchwork Tue Jul 23 14:15:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740124 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 CAC71C3DA49 for ; Tue, 23 Jul 2024 14:18:33 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJV-0006g7-3C; Tue, 23 Jul 2024 10:16:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJE-0005Ra-Ca for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:16:11 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJB-0007En-NV for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:16:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744162; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/9Fji9Ivp6/jtBZXZ8/sCNqAbb9UXPEOh7/iIjbW6HM=; b=Y4BTWzbpavbnKHzFQ3FJ/p+xhCA90TxMA78noVIHj+iy88GJFW/88NUyvdl/BZqpwd/c0f uMUMFUSU3aIkPi9SGBCm7FfvCMt4rJ7Y1NUBVPIEBwm1V9dysvkCdgx/eLQk7WOu/qe/kY 3hmzHfIn5thdArOMGT3CVMb9COm96/s= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-364-Ej5iiS7CNGiRNXdWpTFXQQ-1; Tue, 23 Jul 2024 10:15:58 -0400 X-MC-Unique: Ej5iiS7CNGiRNXdWpTFXQQ-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-42725d3ae3eso40985975e9.3 for ; Tue, 23 Jul 2024 07:15:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744156; x=1722348956; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/9Fji9Ivp6/jtBZXZ8/sCNqAbb9UXPEOh7/iIjbW6HM=; b=PwOxMWfCjoIMhkSW1jaUN/qJ9grooxhEnDSDf/krGOnveWY5QMb5d1x7TQnnh7so6J 4l1cx6oUgFe3AVf3gl4OBq0gLwlDLrawaRodDoJs26hFsXOFhkPzcZ7mEwsk7vMDW9kH jIk4AO9DOfTZx9mRSQoEyObU81qYbXVEEh2SmCv7wLHwnsBG5gMZj9HNCxdr+NExhCD9 22ULMCx5tyh7yKbs4bCr0OInonea88KiLx9+M6B0BHpAYuVv+RIebZufba9412GY097Q wv/M3WBDJmwFYs/aXSfuYVcyNbcQMt2jIpaqIaSlrx1GEIhCgD28WznfqIKinM0AZHey ld+A== X-Gm-Message-State: AOJu0Yxy8tABDcbQWGIUGP8X90zzHioAuvpS7Gl9JyT+4P1vWvM3jr4W J8PfUdjmy3fZnmK7fQh37idlrMShyo5bIzI7NP0oDtO2WRfmZdCyGwZWqwZ39io1h7t3WEedfNQ 66tS8ZVsW+WsBlo4ahh3a36RYmFCnZncO6vsDUOOG5XN+BJxhpz9VhpCMbWKvCWEhgY1lg+2gtE /gYCzPBFmJQxIsu0n/cplZxNfBN3UfwdyHUI/v X-Received: by 2002:a05:600c:1914:b0:426:6314:3336 with SMTP id 5b1f17b1804b1-427dc56801cmr55867525e9.36.1721744156566; Tue, 23 Jul 2024 07:15:56 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHfkRGr/BRMHBbS/ftHFh/PWHI8R1zZJzkB1uLjtKRg29HaG9Eulfk0+hcBIfd84/c0Ol/IvQ== X-Received: by 2002:a05:600c:1914:b0:426:6314:3336 with SMTP id 5b1f17b1804b1-427dc56801cmr55867295e9.36.1721744155957; Tue, 23 Jul 2024 07:15:55 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-427db2a4e3bsm142183615e9.44.2024.07.23.07.15.55 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:55 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PULL 09/11] hpet: accept 64-bit reads and writes Date: Tue, 23 Jul 2024 16:15:27 +0200 Message-ID: <20240723141529.551737-10-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Declare the MemoryRegionOps so that 64-bit reads and writes to the HPET are received directly. This makes it possible to unify the code to process low and high parts: for 32-bit reads, extract the desired word; for 32-bit writes, just merge the desired part into the old value and proceed as with a 64-bit write. Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 137 +++++++++++++----------------------------- hw/timer/trace-events | 3 +- 2 files changed, 44 insertions(+), 96 deletions(-) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 831e5a95b09..ac55dd1ebd6 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -437,6 +437,7 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr, unsigned size) { HPETState *s = opaque; + int shift = (addr & 4) * 8; uint64_t cur_tick; trace_hpet_ram_read(addr); @@ -451,52 +452,33 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr, return 0; } - switch ((addr - 0x100) % 0x20) { - case HPET_TN_CFG: - return timer->config; - case HPET_TN_CFG + 4: // Interrupt capabilities - return timer->config >> 32; + switch (addr & 0x18) { + case HPET_TN_CFG: // including interrupt capabilities + return timer->config >> shift; case HPET_TN_CMP: // comparator register - return timer->cmp; - case HPET_TN_CMP + 4: - return timer->cmp >> 32; + return timer->cmp >> shift; case HPET_TN_ROUTE: - return timer->fsb; - case HPET_TN_ROUTE + 4: - return timer->fsb >> 32; + return timer->fsb >> shift; default: trace_hpet_ram_read_invalid(); break; } } else { - switch (addr) { - case HPET_ID: - return s->capability; - case HPET_PERIOD: - return s->capability >> 32; + switch (addr & ~4) { + case HPET_ID: // including HPET_PERIOD + return s->capability >> shift; case HPET_CFG: - return s->config; - case HPET_CFG + 4: - trace_hpet_invalid_hpet_cfg(4); - return 0; + return s->config >> shift; case HPET_COUNTER: if (hpet_enabled(s)) { cur_tick = hpet_get_ticks(s); } else { cur_tick = s->hpet_counter; } - trace_hpet_ram_read_reading_counter(0, cur_tick); - return cur_tick; - case HPET_COUNTER + 4: - if (hpet_enabled(s)) { - cur_tick = hpet_get_ticks(s); - } else { - cur_tick = s->hpet_counter; - } - trace_hpet_ram_read_reading_counter(4, cur_tick); - return cur_tick >> 32; + trace_hpet_ram_read_reading_counter(addr & 4, cur_tick); + return cur_tick >> shift; case HPET_STATUS: - return s->isr; + return s->isr >> shift; default: trace_hpet_ram_read_invalid(); break; @@ -510,11 +492,11 @@ static void hpet_ram_write(void *opaque, hwaddr addr, { int i; HPETState *s = opaque; + int shift = (addr & 4) * 8; + int len = MIN(size * 8, 64 - shift); uint64_t old_val, new_val, cleared; trace_hpet_ram_write(addr, value); - old_val = hpet_ram_read(opaque, addr, 4); - new_val = value; /*address range of all TN regs*/ if (addr >= 0x100 && addr <= 0x3ff) { @@ -526,9 +508,12 @@ static void hpet_ram_write(void *opaque, hwaddr addr, trace_hpet_timer_id_out_of_range(timer_id); return; } - switch ((addr - 0x100) % 0x20) { + switch (addr & 0x18) { case HPET_TN_CFG: - trace_hpet_ram_write_tn_cfg(); + trace_hpet_ram_write_tn_cfg(addr & 4); + old_val = timer->config; + new_val = deposit64(old_val, shift, len, value); + new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); if (deactivating_bit(old_val, new_val, HPET_TN_TYPE_LEVEL)) { /* * Do this before changing timer->config; otherwise, if @@ -536,8 +521,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr, */ update_irq(timer, 0); } - new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); - timer->config = (timer->config & 0xffffffff00000000ULL) | new_val; + timer->config = new_val; if (activating_bit(old_val, new_val, HPET_TN_ENABLE) && (s->isr & (1 << timer_id))) { update_irq(timer, 1); @@ -550,56 +534,28 @@ static void hpet_ram_write(void *opaque, hwaddr addr, hpet_set_timer(timer); } break; - case HPET_TN_CFG + 4: // Interrupt capabilities - trace_hpet_ram_write_invalid_tn_cfg(4); - break; case HPET_TN_CMP: // comparator register - trace_hpet_ram_write_tn_cmp(0); if (timer->config & HPET_TN_32BIT) { - new_val = (uint32_t)new_val; - } - if (!timer_is_periodic(timer) - || (timer->config & HPET_TN_SETVAL)) { - timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val; - } - if (timer_is_periodic(timer)) { - /* - * FIXME: Clamp period to reasonable min value? - * Clamp period to reasonable max value - */ - if (timer->config & HPET_TN_32BIT) { - new_val = MIN(new_val, ~0u >> 1); + /* High 32-bits are zero, leave them untouched. */ + if (shift) { + trace_hpet_ram_write_invalid_tn_cmp(); + break; } - timer->period = - (timer->period & 0xffffffff00000000ULL) | new_val; + len = 64; + value = (uint32_t) value; } - /* - * FIXME: on a 64-bit write, HPET_TN_SETVAL should apply to the - * high bits part as well. - */ - timer->config &= ~HPET_TN_SETVAL; - if (hpet_enabled(s)) { - hpet_set_timer(timer); - } - break; - case HPET_TN_CMP + 4: // comparator register high order - if (timer->config & HPET_TN_32BIT) { - trace_hpet_ram_write_invalid_tn_cmp(); - break; - } - trace_hpet_ram_write_tn_cmp(4); + trace_hpet_ram_write_tn_cmp(addr & 4); if (!timer_is_periodic(timer) || (timer->config & HPET_TN_SETVAL)) { - timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32; + timer->cmp = deposit64(timer->cmp, shift, len, value); } if (timer_is_periodic(timer)) { /* * FIXME: Clamp period to reasonable min value? * Clamp period to reasonable max value */ - new_val = MIN(new_val, ~0u >> 1); - timer->period = - (timer->period & 0xffffffffULL) | new_val << 32; + new_val = deposit64(timer->period, shift, len, value); + timer->period = MIN(new_val, (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1); } timer->config &= ~HPET_TN_SETVAL; if (hpet_enabled(s)) { @@ -607,10 +563,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr, } break; case HPET_TN_ROUTE: - timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val; - break; - case HPET_TN_ROUTE + 4: - timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff); + timer->fsb = deposit64(timer->fsb, shift, len, value); break; default: trace_hpet_ram_write_invalid(); @@ -618,12 +571,14 @@ static void hpet_ram_write(void *opaque, hwaddr addr, } return; } else { - switch (addr) { + switch (addr & ~4) { case HPET_ID: return; case HPET_CFG: + old_val = s->config; + new_val = deposit64(old_val, shift, len, value); new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); - s->config = (s->config & 0xffffffff00000000ULL) | new_val; + s->config = new_val; if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { /* Enable main counter and interrupt generation. */ s->hpet_offset = @@ -653,10 +608,8 @@ static void hpet_ram_write(void *opaque, hwaddr addr, qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level); } break; - case HPET_CFG + 4: - trace_hpet_invalid_hpet_cfg(4); - break; case HPET_STATUS: + new_val = value << shift; cleared = new_val & s->isr; for (i = 0; i < s->num_timers; i++) { if (cleared & (1 << i)) { @@ -668,15 +621,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr, if (hpet_enabled(s)) { trace_hpet_ram_write_counter_write_while_enabled(); } - s->hpet_counter = - (s->hpet_counter & 0xffffffff00000000ULL) | value; - trace_hpet_ram_write_counter_written(0, value, s->hpet_counter); - break; - case HPET_COUNTER + 4: - trace_hpet_ram_write_counter_write_while_enabled(); - s->hpet_counter = - (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32); - trace_hpet_ram_write_counter_written(4, value, s->hpet_counter); + s->hpet_counter = deposit64(s->hpet_counter, shift, len, value); break; default: trace_hpet_ram_write_invalid(); @@ -690,7 +635,11 @@ static const MemoryRegionOps hpet_ram_ops = { .write = hpet_ram_write, .valid = { .min_access_size = 4, - .max_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, }, .endianness = DEVICE_NATIVE_ENDIAN, }; diff --git a/hw/timer/trace-events b/hw/timer/trace-events index a5fafbc6796..f48a712801e 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -108,8 +108,7 @@ hpet_ram_read_reading_counter(uint8_t reg_off, uint64_t cur_tick) "reading count hpet_ram_read_invalid(void) "invalid hpet_ram_readl" hpet_ram_write(uint64_t addr, uint64_t value) "enter hpet_ram_writel at 0x%" PRIx64 " = 0x%" PRIx64 hpet_ram_write_timer_id(uint64_t timer_id) "hpet_ram_writel timer_id = 0x%" PRIx64 -hpet_ram_write_tn_cfg(void) "hpet_ram_writel HPET_TN_CFG" -hpet_ram_write_invalid_tn_cfg(uint8_t reg_off) "invalid HPET_TN_CFG + %" PRIu8 " write" +hpet_ram_write_tn_cfg(uint8_t reg_off) "hpet_ram_writel HPET_TN_CFG + %" PRIu8 hpet_ram_write_tn_cmp(uint8_t reg_off) "hpet_ram_writel HPET_TN_CMP + %" PRIu8 hpet_ram_write_invalid_tn_cmp(void) "invalid HPET_TN_CMP + 4 write" hpet_ram_write_invalid(void) "invalid hpet_ram_writel" From patchwork Tue Jul 23 14:15:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740116 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 E597AC3DA63 for ; Tue, 23 Jul 2024 14:17:06 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJY-00071p-O5; Tue, 23 Jul 2024 10:16:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJE-0005RH-9k for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:16:11 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJB-0007Eu-Nj for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:16:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744164; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HJdZwCWA36rJai5fAzKET5M9D8dSbh2TfkiP88YY4YQ=; b=duAs8omkOM2UuuIwXruilBqg1EwNQeLxD3dMaLf0QV1oCvAzyzgK+OzTq4b3/qC4wvm4LI 4nRkNNXpWiYCkrbIE0DhWdi22x9leKtOndfJE/hFdVWEpxPR2bjURGjT0ESD8cxM7EQ0hy yMRsDLhHv8VfWCnaG4BeckLLVle+eCo= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-83-K3ZsObdWPpe7vYkbi9VpFg-1; Tue, 23 Jul 2024 10:16:00 -0400 X-MC-Unique: K3ZsObdWPpe7vYkbi9VpFg-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-367962f0cb0so3305586f8f.1 for ; Tue, 23 Jul 2024 07:16:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744159; x=1722348959; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HJdZwCWA36rJai5fAzKET5M9D8dSbh2TfkiP88YY4YQ=; b=t+0MmZOgXV7myJokWMIGdWISVgOj5rS73itMClyvvOxzKR9cxapLC3RxhMUyEkX/my iQs3P3Wibu8R/3ZiLzM9b+snuBxUMXIkt9bCiHjdO5zvUR1sZ5x/Yh35n3Ovb7930kER WcH6FHbBlBa0rR3vCzWiRDgyn2re1NzsSXOxX6WH4E5LWLMqZ8lUrloejtI5wL+F4NR1 jh3gxQCrVdVy7ZZ399CYi7paQqXcGIdkMzkQtdNMv4EaJsPFkdV/J5OyLIvwPXxetBNC FAcUhP2tPYtW5usZdLo4gJos8lz8hDQoeN3sP1NwsqtDAop40rs4wRjvi/QPQpsovgdV vw4w== X-Gm-Message-State: AOJu0Yw8TL7IeynBT3TDo75+OmJgsGGVYg7ipQmRNjwXYc+VKtGHoPtV QIkrOV9qobdhD5cb/oMM+nOKVt8si0arhF6gNPEKbhQ/6916wK4r+KtfwI4XsnNUUUgJu421FeB pr+S4jWyhdiobp0TDIQ8EvpsfWCJEkjX4pihhyJpSfRUt207jEOOkEzX/cIEbjiXDTLexeHqh5T gVJxA+r26HacdEg22dWJ/xHw8ZcEhJR+XCPFLt X-Received: by 2002:a05:6000:18aa:b0:366:ef25:de51 with SMTP id ffacd0b85a97d-369bae707ecmr7393118f8f.49.1721744159083; Tue, 23 Jul 2024 07:15:59 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHj3HpwtcBQMJzvWUBI/P8uQSDZTfo5bXNJzluPQyep8jggzsM3lWrB8RL5LIeC7LMpMZ7nXA== X-Received: by 2002:a05:6000:18aa:b0:366:ef25:de51 with SMTP id ffacd0b85a97d-369bae707ecmr7393090f8f.49.1721744158441; Tue, 23 Jul 2024 07:15:58 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-36878811899sm11623162f8f.116.2024.07.23.07.15.57 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:15:58 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PULL 10/11] hpet: store full 64-bit target value of the counter Date: Tue, 23 Jul 2024 16:15:28 +0200 Message-ID: <20240723141529.551737-11-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Store the full 64-bit value at which the timer should fire. This makes it possible to skip the imprecise hpet_calculate_diff() step, and to remove the clamping of the period to 31 or 63 bits. Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 111 +++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 62 deletions(-) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index ac55dd1ebd6..1654b7cb8b8 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -54,6 +54,7 @@ typedef struct HPETTimer { /* timers */ uint64_t cmp; /* comparator */ uint64_t fsb; /* FSB route */ /* Hidden register state */ + uint64_t cmp64; /* comparator (extended to counter width) */ uint64_t period; /* Last value written to comparator */ uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit * mode. Next pop will be actual timer expiration. @@ -115,11 +116,6 @@ static uint32_t timer_enabled(HPETTimer *t) } static uint32_t hpet_time_after(uint64_t a, uint64_t b) -{ - return ((int32_t)(b - a) < 0); -} - -static uint32_t hpet_time_after64(uint64_t a, uint64_t b) { return ((int64_t)(b - a) < 0); } @@ -156,29 +152,34 @@ static uint64_t hpet_get_ticks(HPETState *s) return ns_to_ticks(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hpet_offset); } -/* - * calculate diff between comparator value and current ticks - */ -static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current) +static uint64_t hpet_get_ns(HPETState *s, uint64_t tick) { + return ticks_to_ns(tick) - s->hpet_offset; +} +/* + * calculate next value of the general counter that matches the + * target (either entirely, or the low 32-bit only depending on + * the timer mode). + */ +static uint64_t hpet_calculate_cmp64(HPETTimer *t, uint64_t cur_tick, uint64_t target) +{ if (t->config & HPET_TN_32BIT) { - uint32_t diff, cmp; - - cmp = (uint32_t)t->cmp; - diff = cmp - (uint32_t)current; - diff = (int32_t)diff > 0 ? diff : (uint32_t)1; - return (uint64_t)diff; + uint64_t result = deposit64(cur_tick, 0, 32, target); + if (result < cur_tick) { + result += 0x100000000ULL; + } + return result; } else { - uint64_t diff, cmp; - - cmp = t->cmp; - diff = cmp - current; - diff = (int64_t)diff > 0 ? diff : (uint64_t)1; - return diff; + return target; } } +static uint64_t hpet_next_wrap(uint64_t cur_tick) +{ + return (cur_tick | 0xffffffffU) + 1; +} + static void update_irq(struct HPETTimer *timer, int set) { uint64_t mask; @@ -260,7 +261,12 @@ static bool hpet_validate_num_timers(void *opaque, int version_id) static int hpet_post_load(void *opaque, int version_id) { HPETState *s = opaque; + int i; + for (i = 0; i < s->num_timers; i++) { + HPETTimer *t = &s->timer[i]; + t->cmp64 = hpet_calculate_cmp64(t, s->hpet_counter, t->cmp); + } /* Recalculate the offset between the main counter and guest time */ if (!s->hpet_offset_saved) { s->hpet_offset = ticks_to_ns(s->hpet_counter) @@ -356,14 +362,10 @@ static const VMStateDescription vmstate_hpet = { } }; -static void hpet_arm(HPETTimer *t, uint64_t ticks) +static void hpet_arm(HPETTimer *t, uint64_t tick) { - if (ticks < ns_to_ticks(INT64_MAX / 2)) { - timer_mod(t->qemu_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_ns(ticks)); - } else { - timer_del(t->qemu_timer); - } + /* FIXME: Clamp period to reasonable min value? */ + timer_mod(t->qemu_timer, hpet_get_ns(t->state, tick)); } /* @@ -372,54 +374,44 @@ static void hpet_arm(HPETTimer *t, uint64_t ticks) static void hpet_timer(void *opaque) { HPETTimer *t = opaque; - uint64_t diff; - uint64_t period = t->period; uint64_t cur_tick = hpet_get_ticks(t->state); if (timer_is_periodic(t) && period != 0) { + while (hpet_time_after(cur_tick, t->cmp64)) { + t->cmp64 += period; + } if (t->config & HPET_TN_32BIT) { - while (hpet_time_after(cur_tick, t->cmp)) { - t->cmp = (uint32_t)(t->cmp + t->period); - } + t->cmp = (uint32_t)t->cmp64; } else { - while (hpet_time_after64(cur_tick, t->cmp)) { - t->cmp += period; - } - } - diff = hpet_calculate_diff(t, cur_tick); - hpet_arm(t, diff); - } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { - if (t->wrap_flag) { - diff = hpet_calculate_diff(t, cur_tick); - hpet_arm(t, diff); - t->wrap_flag = 0; + t->cmp = t->cmp64; } + hpet_arm(t, t->cmp64); + } else if (t->wrap_flag) { + t->wrap_flag = 0; + hpet_arm(t, t->cmp64); } update_irq(t, 1); } static void hpet_set_timer(HPETTimer *t) { - uint64_t diff; - uint32_t wrap_diff; /* how many ticks until we wrap? */ uint64_t cur_tick = hpet_get_ticks(t->state); - /* whenever new timer is being set up, make sure wrap_flag is 0 */ t->wrap_flag = 0; - diff = hpet_calculate_diff(t, cur_tick); + t->cmp64 = hpet_calculate_cmp64(t, cur_tick, t->cmp); + if (t->config & HPET_TN_32BIT) { - /* hpet spec says in one-shot 32-bit mode, generate an interrupt when - * counter wraps in addition to an interrupt with comparator match. - */ - if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { - wrap_diff = 0xffffffff - (uint32_t)cur_tick; - if (wrap_diff < (uint32_t)diff) { - diff = wrap_diff; + /* hpet spec says in one-shot 32-bit mode, generate an interrupt when + * counter wraps in addition to an interrupt with comparator match. + */ + if (!timer_is_periodic(t) && t->cmp64 > hpet_next_wrap(cur_tick)) { t->wrap_flag = 1; + hpet_arm(t, hpet_next_wrap(cur_tick)); + return; } } - hpet_arm(t, diff); + hpet_arm(t, t->cmp64); } static void hpet_del_timer(HPETTimer *t) @@ -550,12 +542,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr, timer->cmp = deposit64(timer->cmp, shift, len, value); } if (timer_is_periodic(timer)) { - /* - * FIXME: Clamp period to reasonable min value? - * Clamp period to reasonable max value - */ - new_val = deposit64(timer->period, shift, len, value); - timer->period = MIN(new_val, (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1); + timer->period = deposit64(timer->period, shift, len, value); } timer->config &= ~HPET_TN_SETVAL; if (hpet_enabled(s)) { From patchwork Tue Jul 23 14:15:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13740118 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) (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 11139C3DA63 for ; Tue, 23 Jul 2024 14:17:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sWGJU-00066C-Ca; Tue, 23 Jul 2024 10:16:24 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJE-0005TP-S0 for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:16:11 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sWGJB-0007F2-SN for qemu-devel@nongnu.org; Tue, 23 Jul 2024 10:16:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721744165; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tClUS2s/M0YyRZbl85m11Cv3d2+aU9p8IaBUrdhpDqA=; b=fF9wgae5T7M/fHenUJ2fflY5L8dztgyl3Gi2ksf20Qlq+hsQ9/5T4Nb9T46WIc9tMypZBT DNClkNtd2z42hK7rVwyfh5ZDLD4qhlHBvCnjYwEawc5Yx5THqjmxHNaYwUQOMFqkEPlNbh w1vVhKU81jRGV/rHnyyvLGs5Xi6XPs0= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-401-dzYBZFupN0ubaxgyGL_c3g-1; Tue, 23 Jul 2024 10:16:02 -0400 X-MC-Unique: dzYBZFupN0ubaxgyGL_c3g-1 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-36832c7023bso3243374f8f.2 for ; Tue, 23 Jul 2024 07:16:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721744161; x=1722348961; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=tClUS2s/M0YyRZbl85m11Cv3d2+aU9p8IaBUrdhpDqA=; b=kE6iwGXGg8GJbsCrzo5+uaRpOohfBq/y92onNAvKelHFoPqaWBwo/W45wEsAdCugrm pJLKvAASAxCXRd8xvcmYg79qWlfmiAtUkci7U0CMQLOrwjHKNnqv/ZcIQlRgz7+6t8p6 heafR6Wh7kAEmgPn1rYZvwLoHfYw2kgYzWYODZ3sFiAvvh6BxUdiG3c0SwN/tLdl45VA q5EeSErROqgCN4MkaabkztqwbJz5hr30hwXPyOf1/ivXNA8OXFoAICTAeUlYQ0TX8qC6 CWgQ6FnC0cQqKusv/LV+Owcna7/+gcBJUle2AeEdoM3Emv3jcWjxf56mGUh7UGSKTGQk ukwA== X-Gm-Message-State: AOJu0YzZzVQKmmsrmFEKdI+cdkxJYEn+xHjaAJEMe/XCg2IIkC9eZnjF RxDk0zeLRa4RlsbFfwn3mdYizFQMavz4LllZb2hL2jSVdC+qMAMcfYsFpm6IqMI8MsK3RpxAHwy CjHu3nGZfCPwnXLRt8b5qjFFcmCxas9F0e93k71I6LxWsSjmvnV0pcXZbdCRFGsBbQH+uNkWrgG kcMwrQT1VC8Tds1v3r9ieDf5XjlG0YLhY3DvDr X-Received: by 2002:a05:6000:1564:b0:368:4910:8f49 with SMTP id ffacd0b85a97d-369bae23910mr7158192f8f.12.1721744161335; Tue, 23 Jul 2024 07:16:01 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGvLD8dFCXeg1E8al4FQUbHm7UUf+7qa7GAS1iRuhIUznmjft04usdMkSBFN1xVaIb9Xk58Fw== X-Received: by 2002:a05:6000:1564:b0:368:4910:8f49 with SMTP id ffacd0b85a97d-369bae23910mr7158173f8f.12.1721744160955; Tue, 23 Jul 2024 07:16:00 -0700 (PDT) Received: from avogadro.local ([151.95.101.29]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-36878694a4dsm11718986f8f.59.2024.07.23.07.16.00 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jul 2024 07:16:00 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PULL 11/11] hpet: avoid timer storms on periodic timers Date: Tue, 23 Jul 2024 16:15:29 +0200 Message-ID: <20240723141529.551737-12-pbonzini@redhat.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723141529.551737-1-pbonzini@redhat.com> References: <20240723141529.551737-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.133, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org If the period is set to a value that is too low, there could be no time left to run the rest of QEMU. Do not trigger interrupts faster than 1 MHz. Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 1654b7cb8b8..471950adef1 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -59,6 +59,7 @@ typedef struct HPETTimer { /* timers */ uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit * mode. Next pop will be actual timer expiration. */ + uint64_t last; /* last value armed, to avoid timer storms */ } HPETTimer; struct HPETState { @@ -266,6 +267,7 @@ static int hpet_post_load(void *opaque, int version_id) for (i = 0; i < s->num_timers; i++) { HPETTimer *t = &s->timer[i]; t->cmp64 = hpet_calculate_cmp64(t, s->hpet_counter, t->cmp); + t->last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - NANOSECONDS_PER_SECOND; } /* Recalculate the offset between the main counter and guest time */ if (!s->hpet_offset_saved) { @@ -364,8 +366,15 @@ static const VMStateDescription vmstate_hpet = { static void hpet_arm(HPETTimer *t, uint64_t tick) { - /* FIXME: Clamp period to reasonable min value? */ - timer_mod(t->qemu_timer, hpet_get_ns(t->state, tick)); + uint64_t ns = hpet_get_ns(t->state, tick); + + /* Clamp period to reasonable min value (1 us) */ + if (timer_is_periodic(t) && ns - t->last < 1000) { + ns = t->last + 1000; + } + + t->last = ns; + timer_mod(t->qemu_timer, ns); } /*