From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 929191D9A41; Thu, 14 Nov 2024 10:08:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578896; cv=none; b=TADaxQJPTR6M1hRK3ctjGkVw/FFDNLjEfxP5YbEqrZjX/MEApI/X2VXbhiUaS2tJuamO5NySm3wVF/r6+2A7+MFmj58u14sZVaV0xbIIvUCTpMAvFSRzI/mFIucRZGForUO+5jeog7bIqXBLQDuqVrssm6ykzaRhIp8YWJNHdDk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578896; c=relaxed/simple; bh=7Q/u9mXiu4INaF1tH+EiC3ANPsGGRziBmdY8gjeuz0A=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Y4Q9J5rAG+TNhD/G+UzQLGyKn5QXdBHPW9eXWHBnr/+HTUItEPF2ygZr5Dr+84/8dRLCB5dKTWFHuIhZN6gR01CVrW2CvE5qwXy/zw8vhpy08EV2BLJu6Q6v2/AZTbvJiZLhQy1AqG46o8aUs/G2dw/+rEzXb6SwNHfD51y349s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=CT1SqqCm; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="CT1SqqCm" X-UUID: 56546beaa27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=V+uTllLumsvRiNSI4QHHF2N/3sKtFUpT/a3mYpx8kfY=; b=CT1SqqCmBFjNxa/EYovZ3QRcVCc81ad7SeWnToHLTC3mnSDs6Qdm+B4N+Tqx2QFAltV9R6d2HeWkr7SEScAytrdTNqcyHO5+TNrwKr+BAWHKOAd7VnIudVXMTeZ/7+4JGyaxKdxbqE5CWxpRK/sgCGp69Uwyi0hGEohXP14PCZw=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:301ffcc9-ebce-44ca-a881-980843bb4034,IP:0,U RL:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:0 X-CID-META: VersionHash:b0fcdc3,CLOUDID:a75e0c4f-a2ae-4b53-acd4-c3dc8f449198,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 56546beaa27011ef99858b75a2457dd9-20241114 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1374894203; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:02 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:02 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 01/25] virt: geniezone: enable gzvm-ko in defconfig Date: Thu, 14 Nov 2024 18:07:38 +0800 Message-ID: <20241114100802.4116-2-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan Add config in defconfig to enable gzvm driver by default Signed-off-by: Yingshiuan Pan Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/configs/defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index d13218d0c30f..0f63d4837b61 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1733,3 +1733,5 @@ CONFIG_CORESIGHT_STM=3Dm CONFIG_CORESIGHT_CPU_DEBUG=3Dm CONFIG_CORESIGHT_CTI=3Dm CONFIG_MEMTEST=3Dy +CONFIG_VIRT_DRIVERS=3Dy +CONFIG_MTK_GZVM=3Dm --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CACFA1F7789; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578899; cv=none; b=HbbRTGnsc+fsECyDWKmhLNDPwRyUkfv9P07paFk07aOYC+G/ALTfW2tsasweMRZui9UuKSxnbRTSnqnaOR5nQAHQGMrUoHHgeqWi10dRKqqrGW/S9+LOuIEgZ0uYYu9ocruR48JvE2I/hCpbNb+16ACQTCa9B8Fk3IYuH2NKV38= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578899; c=relaxed/simple; bh=kvyRHDyImxXjhKxdoVzxK8xW36OyLtNhCrsUulNwzvI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EDy4FL5fTVm+EkwpeD21dP6X7yZpqmVxkiRMRGSmsbJP8d98jxlrWW/6WnbuoyM8SoytKhk6oxYvWRE4xioN1VTHjyeiKb9Xr/00og49ONUgXL6hRPjJzZO4Reu/RIXL7srVoMYSHoVqttk6d/Q3dukFQQf01pZaF0tsfR1F6Us= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=c/ALBO09; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="c/ALBO09" X-UUID: 56b83e86a27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=PO7+1L/RL1jlngVwSYfjIWxhUQu8nxxElZ4cG7x7r88=; b=c/ALBO09I62XsFGLRj8l+YQr1OpPbBuOqtVh7gq6Wpwci8wgGNAqfaXfnqQ6yEF9JNBjw05VH3t6ogN5cG9k9Lw9uPhO1f18QFHhbQcbn6FTech1FjUMrpMGxKj2zZij01+ia9T+fpNT8/4xmpWRkcaBwvWKTIkE2cug5NrVepQ=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:dca5c297-f48e-428b-8a60-343c3932a906,IP:0,U RL:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:0 X-CID-META: VersionHash:b0fcdc3,CLOUDID:d76b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 56b83e86a27011efbd192953cf12861f-20241114 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 507297029; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS14N1.mediatek.inc (172.21.101.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:03 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:02 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , "Catalin Marinas" , Will Deacon , "Steven Rostedt" , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 02/25] docs: geniezone: Introduce GenieZone hypervisor Date: Thu, 14 Nov 2024 18:07:39 +0800 Message-ID: <20241114100802.4116-3-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--14.459700-8.000000 X-TMASE-MatchedRID: +CLiPMT38ZAihjhlMTu+HHa57ruHAnHxFuNF4lJG6xs1LB46LFAAkkd0 Rzx07LDVu1YWrIMJBFIUZ7mqlsLL7wAwGIAo3ShbyATMS/tDL5ipD1R7N5OROMA5YKm8dwM6jIZ 02fRmyUctK7tHzSdmVLdnCNkrUAnN1ddezVny+QLiHyvyXeXh5qny79MYSKWc/uK0hv0lVwklHD ysIsZQz11tBKF7hhAzucwGRxuiOSoY1mlq1H5Z3ov2/i8VNqeOWOi4GPaBr7/FpA1uJFd1mtZho S9qxz0XHuLux1hFzDvyN9+MhBBXP9D+INh9HpXLSEQN/D/3cG4ayaQg2/Z1zxy/A9iZcrIf+bls dPlPYzaEOdaLaz+/0fJtR6XZoHQXq9Fb0RfhjvR3p/MPn9NFkc/rSr8VfmGwJ870fpj93L41Itq 0yDsRhtMHHnHl1YlR3VFTasCiHDkWfqaKovr4bRDK/Fqp4JZ8fS0Ip2eEHnz3IzXlXlpamPoLR4 +zsDTtgUicvJ4MChmZe7u+gKYNYQqHGxD+0tBiTNWJBiG7qgnFyyED9rMmwkNHOP6jPEsn X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--14.459700-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: C36932093DDEBE95FB9B90E7042C04888CCC10DA95C3422327E1DA15A6F171792000:8 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan GenieZone is MediaTek proprietary hypervisor solution, and it is running in EL2 stand alone as a type-I hypervisor. It is a pure EL2 implementation which implies it does not rely any specific host VM, and this behavior improves GenieZone's security as it limits its interface. Signed-off-by: Yingshiuan Pan Co-developed-by: Yi-De Wu Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- Documentation/virt/geniezone/introduction.rst | 87 +++++++++++++++++++ Documentation/virt/index.rst | 1 + MAINTAINERS | 6 ++ 3 files changed, 94 insertions(+) create mode 100644 Documentation/virt/geniezone/introduction.rst diff --git a/Documentation/virt/geniezone/introduction.rst b/Documentation/= virt/geniezone/introduction.rst new file mode 100644 index 000000000000..206b019f777b --- /dev/null +++ b/Documentation/virt/geniezone/introduction.rst @@ -0,0 +1,87 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +GenieZone Introduction +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Overview +=3D=3D=3D=3D=3D=3D=3D=3D +GenieZone hypervisor (gzvm) is a type-I hypervisor that supports various v= irtual +machine types and provides security features such as TEE-like scenarios and +secure boot. It can create guest VMs for security use cases and has +virtualization capabilities for both platform and interrupt. Although the +hypervisor can be booted independently, it requires the assistance of Geni= eZone +hypervisor kernel driver (also named gzvm) to leverage the ability of Linux +kernel for vCPU scheduling, memory management, inter-VM communication and = virtio +backend support. + +Supported Architecture +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +GenieZone now only supports MediaTek ARM64 SoC. + +Features +=3D=3D=3D=3D=3D=3D=3D=3D + +- vCPU Management + + VM manager aims to provide vCPUs on the basis of time sharing on physical + CPUs. It requires Linux kernel in host VM for vCPU scheduling and VM pow= er + management. + +- Memory Management + + Direct use of physical memory from VMs is forbidden and designed to be + dictated to the privilege models managed by GenieZone hypervisor for sec= urity + reason. With the help of the gzvm module, the hypervisor is able to mani= pulate + memory as objects. + +- Virtual Platform + + The gzvm hypervisor emulates a virtual mobile platform for guest OS runn= ing on + guest VM. The platform supports various architecture-defined devices, su= ch as + virtual arch timer, GIC, MMIO, PSCI, and exception watching...etc. + +- Inter-VM Communication + + Communication among guest VMs is provided mainly on RPC. More communicat= ion + mechanisms will be provided in the future based on VirtIO-vsock. + +- Device Virtualization + + The solution is provided using the well-known VirtIO. The gzvm module re= directs + MMIO traps back to VMM where the virtual devices are mostly emulated. + Ioeventfd is implemented using eventfd for signaling host VM that some IO + events in guest VMs need to be processed. + +- Interrupt virtualization + + All interrupts during some guest VMs running are handled by GenieZone + hypervisor with the help of gzvm module, both virtual and physical ones. + In case there's no guest VM running, physical interrupts are handled by = host + VM directly for performance reason. Irqfd is also implemented using even= tfd + for accepting vIRQ requests in gzvm module. + +Platform architecture component +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D + +- vm + + The vm component is responsible for setting up the capability and memory + management for the protected VMs. The capability is mainly about the lif= ecycle + control and boot context initialization. And the memory management is hi= ghly + integrated with ARM 2-stage translation tables to convert VA to IPA to PA + under proper security measures required by protected VMs. + +- vcpu + + The vcpu component is the core of virtualizing an aarch64 physical CPU, = and it + controls the vCPU lifecycle including creating, running and destroying. + With self-defined exit handler, the vm component is able to act accordin= gly + before termination. + +- vgic + + The vgic component exposes control interfaces to Linux kernel via irqchi= p, and + we intend to support all SPI, PPI, and SGI. When it comes to virtual + interrupts, the GenieZone hypervisor writes to list registers and trigge= rs + vIRQ injection in guest VMs via GIC. diff --git a/Documentation/virt/index.rst b/Documentation/virt/index.rst index 7fb55ae08598..cf12444db336 100644 --- a/Documentation/virt/index.rst +++ b/Documentation/virt/index.rst @@ -16,6 +16,7 @@ Virtualization Support coco/sev-guest coco/tdx-guest hyperv/index + geniezone/introduction =20 .. only:: html and subproject =20 diff --git a/MAINTAINERS b/MAINTAINERS index 279560bf2b6d..bd119e707b7f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9671,6 +9671,12 @@ F: include/vdso/ F: kernel/time/vsyscall.c F: lib/vdso/ =20 +GENIEZONE HYPERVISOR DRIVER +M: Yingshiuan Pan +M: Ze-Yu Wang +M: Liju Chen +F: Documentation/virt/geniezone/ + GENWQE (IBM Generic Workqueue Card) M: Frank Haverkamp S: Supported --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B2D731F7097; Thu, 14 Nov 2024 10:08:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578898; cv=none; b=f5sfV7xLReU3m/FRFSED11bIi4KzkVJcH45RXGHgXWeld70r4CDcY6CtcLyl8K7zK8B/ka3UnutsKhk4+TaMSH1Yxk2iIyD2QoWo1s/MtDtN3HGk2KfxANmlfz/uNg/x4Rc01BhfFzzHfr5lQ5JhLEM91IHy0KEAQb7FSLfcCZk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578898; c=relaxed/simple; bh=+T7zJWsnL96H+zjaNN/L5YeRWGH7NRHm/d1ZxqSbAGM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=agKDcijUeqaXG1ra7uQgRTOUw/Q9qr1zQMcX+Smscte8BhmsCVub0bqkMth0Aj8fy6SuQtewgI4kVNMlmJGt+vVYCYyJAGXHXSUedz/HvGLh8YW+uSHb8Qj0SbFi7QmOyT2DMIbNAqUZ6A1Str6439es+IYJibsMeQLY9sWiziA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=cqo8o8Hz; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="cqo8o8Hz" X-UUID: 5693531ea27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=NeZfIxfE73lDEasKhP0FSNvN7LjURM3GXgvN0vxDtZk=; b=cqo8o8HzZGQVlMvcaGOhnqZ8EpllxXW+K97JLT3fvIPUvpT8FpsZR+4eQmg37ixW5UcwCFNksmPtpwFJiydNHN+0ZGNawqhenScC6R/rv5br54WejBqSoUYC6PFtiBilhSsV9Tij0uEkkuUUh/fWQcneQ0JVHPySReEC7epbtDI=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:0f8530bc-7c50-4ed0-8503-ec875d049a85,IP:0,U RL:25,TC:0,Content:-5,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:20 X-CID-META: VersionHash:b0fcdc3,CLOUDID:d66b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 5693531ea27011efbd192953cf12861f-20241114 Received: from mtkmbs13n1.mediatek.inc [(172.21.101.193)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 388720392; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 02:08:03 -0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:03 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 03/25] dt-bindings: hypervisor: Add MediaTek GenieZone hypervisor Date: Thu, 14 Nov 2024 18:07:40 +0800 Message-ID: <20241114100802.4116-4-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan Add documentation for GenieZone(gzvm) node. This node informs gzvm driver to start probing if proprietary geniezone hypervisor firmware is available and capable of executing virtual machine operations. [Reason to use dt solution] The GenieZone hypervisor acts as a vendor firmware to enable platform virtualization, offering an implementation that is independent of Linux-specific implementations. - Previously, our approach involved probing via hypercalls to detect the presence of our hypervisor firmware. However, this method raised concerns about potential impacts on all systems, including those without the embedded GenieZone hypervisor.[1] - By utilizing the device tree solution, we can accurately identify the GenieZone hypervisor's presence without relying on hypercalls, ensuring a more targeted and efficient detection process that minimizes the risk of unintended consequences on non-GenieZone systems. [1] https://lore.kernel.org/all/2fe0c7f9-55fc-ae63-3631-8526a0212ccd@linaro= .org/ Signed-off-by: Yingshiuan Pan Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- .../bindings/firmware/mediatek,geniezone.yaml | 34 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/firmware/mediatek,gen= iezone.yaml diff --git a/Documentation/devicetree/bindings/firmware/mediatek,geniezone.= yaml b/Documentation/devicetree/bindings/firmware/mediatek,geniezone.yaml new file mode 100644 index 000000000000..c9610ed27a1a --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/mediatek,geniezone.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/firmware/mediatek,geniezone.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek GenieZone hypervisor + +maintainers: + - Yingshiuan Pan + +description: + GenieZone is a proprietary type-I hypervisor firmware developed by Media= Tek, + providing an isolated execution environment for mTEE (MediaTek Trusted + Execution Environment) and AVF (Android Virtualization Framework) virtual + machines. This binding facilitates the integration of GenieZone into the + Android Virtualization Framework (AVF) with Crosvm as the VMM. The driver + exposes hypervisor control interfaces to the VMM for managing virtual + machine lifecycles and assisting virtual device emulation. + +properties: + compatible: + const: mediatek,geniezone + +required: + - compatible + +additionalProperties: false + +examples: + - | + hypervisor { + compatible =3D "mediatek,geniezone"; + }; diff --git a/MAINTAINERS b/MAINTAINERS index bd119e707b7f..291f46017f3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9675,6 +9675,7 @@ GENIEZONE HYPERVISOR DRIVER M: Yingshiuan Pan M: Ze-Yu Wang M: Liju Chen +F: Documentation/devicetree/bindings/firmware/mediatek,geniezone.yaml F: Documentation/virt/geniezone/ =20 GENWQE (IBM Generic Workqueue Card) --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CADBC1F7796; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; cv=none; b=YULIVwkvvdGT4IAATrE1Ew49ZnXcC8Gg83EYvuDDI6KbessJDDAWCwfz6Zcjvd+wLXxyIV2RXPVUQFdGdtX+HoKfSwF9LQRjWLGhiRLy2rXdU9NBnlGgWGmX9wS0KHaZtfUaEqwK9qUO3Jwq+rUsnwRABGWTkyNyYndoqVqSKBY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; c=relaxed/simple; bh=+zQ6qqZUbppfom3vUzm7Qfhcl63rxoUSx8nOUo99fOE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=OWvliOi8j+AuOxuViqsEI6fV4Fqb1Axmdaem/SaKpS4mJl58F8XZBFnv1NaGBKUiKvXfPz99UzJmqx7RGg/W7cxk2D76U1icbG9/H7fuWHUB5+uhmtIY3y5w1zp42G7w5XutNjitaRY4GGIwMl/U8Qz1n+Z9z0jJRtgg2V0MstY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=qEQEKRuF; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="qEQEKRuF" X-UUID: 56e4da7ca27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=9FJ7JtnvV9b15dJtnISl5o8zU3rCv61vcVYHpSWnMyM=; b=qEQEKRuFdxcrIPhJ8Mzg3oJMCAG2MapKvo2Uo40qQ3EJLzqsnK+1NvWM/rRpXGtDThvbD2ogKmbcXe2KnuxTAyAGNF1Lh7wbKEZ+o+xoPQNBZKZwNZlm7t6krxT8SDf9KAyJwixAw/yrSfDBczjP5ysKOL+OG2YlInF83UAquF0=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:003bb6ab-e4ab-42b3-8e79-63b1f1220890,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:263fa25c-f18b-4d56-b49c-93279ee09144,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_ULN,TF_CID_SPAM_SNR X-UUID: 56e4da7ca27011efbd192953cf12861f-20241114 Received: from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 582868460; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:03 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:03 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , "Catalin Marinas" , Will Deacon , "Steven Rostedt" , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 04/25] virt: geniezone: Add GenieZone hypervisor driver Date: Thu, 14 Nov 2024 18:07:41 +0800 Message-ID: <20241114100802.4116-5-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--14.710900-8.000000 X-TMASE-MatchedRID: 7lb+J3RorLbPwZWTvltloQI0yP/uoH+DUAjrAJWsTe9mU223IIioZfb9 MQK6DQClvfKrrb4bmIqy7ec+ITUwM2eIEG00SdU9drnuu4cCcfF/aDoolm3GXWJkJOQVCIpwMKw CZ7huGiG36SL29gBZ5pCCPgbCpGAQEx7gYK5Baw8mZusHWPhfCgXBq8VnFhCkGoH7Aor25l4faH aH7SYxz5w9wMcKngv65JZWpbmrOY42fA1oT3w9vBes/RxhysDbO69hrW/YgWHRziMbBeTI+f6rI PjisOwVLnrst5PEBItY/xqzfORJ/3+cOjB/YDBsE0Q83A2vD+sikU4xQFgb7nwqSr02aA0dg7M3 17/33cGmuE8sHNH+0fooE3M+qP72Nb4r89y+oGvRfDQgu+j+5SlayzmQ9QV0Fp7kniXxovOJW14 oA532uJW8QZiQ0LetCAtqzqtapouzMsBjmgeEEBIRh9wkXSlF+q1Y+/eEArbczkKO5k4APq0Rom hWPJaQe8WHAlOjF6AQCEi5k+nQxB8TzIzimOwPC24oEZ6SpSk6XEE7Yhw4Fi2BBbyYEj+Q5vYtb tlkT/6Wv3BspGBaJ/lZLP6l7wtQSZ5q7ZSBIyM= X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--14.710900-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: 29EDF289D22924B512A59001A52A272A3404E3BD152226C4C9ADBD9EA32D74C92000:8 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan GenieZone hypervisor(gzvm) is a type-I hypervisor that supports various virtual machine types and provides security features such as TEE-like scenarios and secure boot. It can create guest VMs for security use cases and has virtualization capabilities for both platform and interrupt. Although the hypervisor can be booted independently, it requires the assistance of GenieZone hypervisor kernel driver(gzvm-ko) to leverage the ability of Linux kernel for vCPU scheduling, memory management, inter-VM communication and virtio backend support. Add the basic hypervisor driver. Subsequent patches will add more supported features to this driver. Signed-off-by: Yingshiuan Pan Co-developed-by: Jerry Wang Signed-off-by: Jerry Wang Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- MAINTAINERS | 3 + arch/arm64/Kbuild | 1 + arch/arm64/geniezone/Makefile | 9 ++ arch/arm64/geniezone/gzvm_arch_common.h | 44 +++++++++ arch/arm64/geniezone/vm.c | 72 +++++++++++++++ drivers/virt/Kconfig | 2 + drivers/virt/geniezone/Kconfig | 16 ++++ drivers/virt/geniezone/Makefile | 9 ++ drivers/virt/geniezone/gzvm_main.c | 117 ++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 41 +++++++++ 10 files changed, 314 insertions(+) create mode 100644 arch/arm64/geniezone/Makefile create mode 100644 arch/arm64/geniezone/gzvm_arch_common.h create mode 100644 arch/arm64/geniezone/vm.c create mode 100644 drivers/virt/geniezone/Kconfig create mode 100644 drivers/virt/geniezone/Makefile create mode 100644 drivers/virt/geniezone/gzvm_main.c create mode 100644 include/linux/soc/mediatek/gzvm_drv.h diff --git a/MAINTAINERS b/MAINTAINERS index 291f46017f3f..708c13103ec5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9677,6 +9677,9 @@ M: Ze-Yu Wang M: Liju Chen F: Documentation/devicetree/bindings/firmware/mediatek,geniezone.yaml F: Documentation/virt/geniezone/ +F: arch/arm64/geniezone/ +F: drivers/virt/geniezone/ +F: include/linux/soc/mediatek/gzvm_drv.h =20 GENWQE (IBM Generic Workqueue Card) M: Frank Haverkamp diff --git a/arch/arm64/Kbuild b/arch/arm64/Kbuild index 5bfbf7d79c99..0c3cca572919 100644 --- a/arch/arm64/Kbuild +++ b/arch/arm64/Kbuild @@ -4,6 +4,7 @@ obj-$(CONFIG_KVM) +=3D kvm/ obj-$(CONFIG_XEN) +=3D xen/ obj-$(subst m,y,$(CONFIG_HYPERV)) +=3D hyperv/ obj-$(CONFIG_CRYPTO) +=3D crypto/ +obj-$(CONFIG_MTK_GZVM) +=3D geniezone/ =20 # for cleaning subdir- +=3D boot diff --git a/arch/arm64/geniezone/Makefile b/arch/arm64/geniezone/Makefile new file mode 100644 index 000000000000..2957898cdd05 --- /dev/null +++ b/arch/arm64/geniezone/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Main Makefile for gzvm, this one includes drivers/virt/geniezone/Makefile +# +include $(srctree)/drivers/virt/geniezone/Makefile + +gzvm-y +=3D vm.o + +obj-$(CONFIG_MTK_GZVM) +=3D gzvm.o diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h new file mode 100644 index 000000000000..660c7cf3fc18 --- /dev/null +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#ifndef __GZVM_ARCH_COMMON_H__ +#define __GZVM_ARCH_COMMON_H__ + +#include + +enum { + GZVM_FUNC_PROBE =3D 12, + NR_GZVM_FUNC, +}; + +#define SMC_ENTITY_MTK 59 +#define GZVM_FUNCID_START (0x1000) +#define GZVM_HCALL_ID(func) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ + SMC_ENTITY_MTK, (GZVM_FUNCID_START + (func))) + +#define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) + +/** + * gzvm_hypcall_wrapper() - the wrapper for hvc calls + * @a0: argument passed in registers 0 + * @a1: argument passed in registers 1 + * @a2: argument passed in registers 2 + * @a3: argument passed in registers 3 + * @a4: argument passed in registers 4 + * @a5: argument passed in registers 5 + * @a6: argument passed in registers 6 + * @a7: argument passed in registers 7 + * @res: result values from registers 0 to 3 + * + * Return: The wrapper helps caller to convert geniezone errno to Linux er= rno. + */ +int gzvm_hypcall_wrapper(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res); + +#endif /* __GZVM_ARCH_COMMON_H__ */ diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c new file mode 100644 index 000000000000..daad21b28f6f --- /dev/null +++ b/arch/arm64/geniezone/vm.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include + +#include +#include "gzvm_arch_common.h" + +/** + * gzvm_hypcall_wrapper() - the wrapper for hvc calls + * @a0: arguments passed in registers 0 + * @a1: arguments passed in registers 1 + * @a2: arguments passed in registers 2 + * @a3: arguments passed in registers 3 + * @a4: arguments passed in registers 4 + * @a5: arguments passed in registers 5 + * @a6: arguments passed in registers 6 + * @a7: arguments passed in registers 7 + * @res: result values from registers 0 to 3 + * + * Return: The wrapper helps caller to convert geniezone errno to Linux er= rno. + */ +int gzvm_hypcall_wrapper(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res) +{ + struct arm_smccc_1_2_regs res_1_2; + struct arm_smccc_1_2_regs args =3D { + .a0 =3D a0, + .a1 =3D a1, + .a2 =3D a2, + .a3 =3D a3, + .a4 =3D a4, + .a5 =3D a5, + .a6 =3D a6, + .a7 =3D a7, + }; + arm_smccc_1_2_hvc(&args, &res_1_2); + res->a0 =3D res_1_2.a0; + res->a1 =3D res_1_2.a1; + res->a2 =3D res_1_2.a2; + res->a3 =3D res_1_2.a3; + + return gzvm_err_to_errno(res->a0); +} + +int gzvm_arch_probe(struct gzvm_version drv_version, + struct gzvm_version *hyp_version) +{ + struct arm_smccc_res res; + int ret; + + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_PROBE, + drv_version.major, + drv_version.minor, + drv_version.sub, + 0, 0, 0, 0, &res); + if (ret) + return -ENXIO; + + hyp_version->major =3D (u32)res.a1; + hyp_version->minor =3D (u32)res.a2; + hyp_version->sub =3D res.a3; + + return 0; +} diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig index d8c848cf09a6..848eb97202d1 100644 --- a/drivers/virt/Kconfig +++ b/drivers/virt/Kconfig @@ -49,4 +49,6 @@ source "drivers/virt/acrn/Kconfig" =20 source "drivers/virt/coco/Kconfig" =20 +source "drivers/virt/geniezone/Kconfig" + endif diff --git a/drivers/virt/geniezone/Kconfig b/drivers/virt/geniezone/Kconfig new file mode 100644 index 000000000000..b17c06c91074 --- /dev/null +++ b/drivers/virt/geniezone/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config MTK_GZVM + tristate "GenieZone Hypervisor driver for guest VM operation" + depends on ARM64 && EVENTFD + help + This driver, gzvm, enables to run guest VMs on MTK GenieZone + hypervisor. It exports kvm-like interfaces for VMM (e.g., crosvm) in + order to operate guest VMs on GenieZone hypervisor. + + GenieZone hypervisor now only supports MediaTek SoC and arm64 + architecture. + + Select M if you want it be built as a module (gzvm.ko). + + If unsure, say N. diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makef= ile new file mode 100644 index 000000000000..3a82e5fddf90 --- /dev/null +++ b/drivers/virt/geniezone/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for GenieZone driver, this file should be include in arch's +# to avoid two ko being generated. +# + +GZVM_DIR ?=3D ../../../drivers/virt/geniezone + +gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c new file mode 100644 index 000000000000..dc91fd61ba75 --- /dev/null +++ b/drivers/virt/geniezone/gzvm_main.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct gzvm_driver gzvm_drv =3D { + .drv_version =3D { + .major =3D GZVM_DRV_MAJOR_VERSION, + .minor =3D GZVM_DRV_MINOR_VERSION, + .sub =3D 0, + }, +}; + +/** + * gzvm_err_to_errno() - Convert geniezone return value to standard errno + * + * @err: Return value from geniezone function return + * + * Return: Standard errno + */ +int gzvm_err_to_errno(unsigned long err) +{ + int gz_err =3D (int)err; + + switch (gz_err) { + case 0: + return 0; + case ERR_NO_MEMORY: + return -ENOMEM; + case ERR_NOT_SUPPORTED: + fallthrough; + case ERR_NOT_IMPLEMENTED: + return -EOPNOTSUPP; + case ERR_FAULT: + return -EFAULT; + default: + break; + } + + return -EINVAL; +} + +static int gzvm_dev_open(struct inode *inode, struct file *file) +{ + /* + * Reference count to prevent this module is unload without destroying + * VM + */ + try_module_get(THIS_MODULE); + return 0; +} + +static int gzvm_dev_release(struct inode *inode, struct file *file) +{ + module_put(THIS_MODULE); + return 0; +} + +static const struct file_operations gzvm_chardev_ops =3D { + .llseek =3D noop_llseek, + .open =3D gzvm_dev_open, + .release =3D gzvm_dev_release, +}; + +static struct miscdevice gzvm_dev =3D { + .minor =3D MISC_DYNAMIC_MINOR, + .name =3D KBUILD_MODNAME, + .fops =3D &gzvm_chardev_ops, +}; + +static int gzvm_drv_probe(struct platform_device *pdev) +{ + if (gzvm_arch_probe(gzvm_drv.drv_version, &gzvm_drv.hyp_version) !=3D 0) { + dev_err(&pdev->dev, "Not found available conduit\n"); + return -ENODEV; + } + + pr_debug("Found GenieZone hypervisor version %u.%u.%llu\n", + gzvm_drv.hyp_version.major, gzvm_drv.hyp_version.minor, + gzvm_drv.hyp_version.sub); + + return misc_register(&gzvm_dev); +} + +static void gzvm_drv_remove(struct platform_device *pdev) +{ + misc_deregister(&gzvm_dev); +} + +static const struct of_device_id gzvm_of_match[] =3D { + { .compatible =3D "mediatek,geniezone" }, + {/* sentinel */}, +}; + +static struct platform_driver gzvm_driver =3D { + .probe =3D gzvm_drv_probe, + .remove =3D gzvm_drv_remove, + .driver =3D { + .name =3D KBUILD_MODNAME, + .of_match_table =3D gzvm_of_match, + }, +}; + +module_platform_driver(gzvm_driver); + +MODULE_DEVICE_TABLE(of, gzvm_of_match); +MODULE_AUTHOR("MediaTek"); +MODULE_DESCRIPTION("GenieZone interface for VMM"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h new file mode 100644 index 000000000000..495bf5b8b8e0 --- /dev/null +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#ifndef __GZVM_DRV_H__ +#define __GZVM_DRV_H__ + +/* GZVM version encode */ +#define GZVM_DRV_MAJOR_VERSION 16 +#define GZVM_DRV_MINOR_VERSION 0 + +struct gzvm_version { + u32 major; + u32 minor; + u64 sub; /* currently, used by hypervisor */ +}; + +struct gzvm_driver { + struct gzvm_version hyp_version; + struct gzvm_version drv_version; +}; + +/* + * These are the definitions of APIs between GenieZone hypervisor and driv= er, + * there's no need to be visible to uapi. Furthermore, we need GenieZone + * specific error code in order to map to Linux errno + */ +#define NO_ERROR (0) +#define ERR_NO_MEMORY (-5) +#define ERR_NOT_SUPPORTED (-24) +#define ERR_NOT_IMPLEMENTED (-27) +#define ERR_FAULT (-40) + +int gzvm_err_to_errno(unsigned long err); + +/* arch-dependant functions */ +int gzvm_arch_probe(struct gzvm_version drv_version, + struct gzvm_version *hyp_version); + +#endif /* __GZVM_DRV_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7CBCD1F708C; Thu, 14 Nov 2024 10:08:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578898; cv=none; b=cGn8SDp0NAN/g0ERtBPbR419yznuyj7r39SV1I+AnktgvqKFXyrLKLBJVWoOmBpMY0CvC0ZoGan2T4rwoG4n9QjNp2reqDv5eNeayuxtPjy8zLf85L7PqUgx3gTfZ4xa5mLxLgYSK4Jlcqfu8r5FM7yAffnyThU3BmPFdQkxMRs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578898; c=relaxed/simple; bh=vBEw1tJsCF2b9Wp56GZyAuzgdD628y71avP43YUkkEo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=V2J7yepbiI0WpDEClrK5Ha0bHNCOc3wMQVIRrLYCRkB95AmV8nu1PdY01AlezDHtEqn7G+zCH24PNlZF862ExNIWL3ppAOWYba0PDmg4Zd9AON595yMwb04aEQKrhFjGda0psC/dby1PF0/6OlxNmSg/kU2ck7cLx4pB7P5UVEU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=QWl/y8gX; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="QWl/y8gX" X-UUID: 565805aca27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=GONwmY7pvPVHwGJga8ZRaLBO74qwe7MnnfV4NItAYII=; b=QWl/y8gXzIZDYfxtdF5TZNO8MBozI+m2ne4xZxkuvvSlbNcJuL0vn3DwVoJ1aWeI1JFV6kE0777QiaaXTqNpt0LrJmiCX2babYbHcVh1lAAJcDmJaIQuyk71HPHYznFb7WLMPTRaIes/uZ9PegKBfxOAsfj80G7/E2Sn98yYt1o=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:0ad5a781-e0d3-4141-a329-d4941aa45d75,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:bf6b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 565805aca27011ef99858b75a2457dd9-20241114 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 195652705; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:03 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:03 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 05/25] virt: geniezone: Add vm support Date: Thu, 14 Nov 2024 18:07:42 +0800 Message-ID: <20241114100802.4116-6-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan The VM component is responsible for setting up the capability and memory management for the protected VMs. The capability is mainly about the lifecycle control and boot context initialization. Signed-off-by: Yingshiuan Pan Co-developed-by: Jerry Wang Signed-off-by: Jerry Wang Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- MAINTAINERS | 1 + arch/arm64/geniezone/gzvm_arch_common.h | 4 ++ arch/arm64/geniezone/vm.c | 27 +++++++ drivers/virt/geniezone/Makefile | 2 +- drivers/virt/geniezone/gzvm_main.c | 15 ++++ drivers/virt/geniezone/gzvm_vm.c | 93 +++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 29 ++++++++ include/uapi/linux/gzvm.h | 25 +++++++ 8 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 drivers/virt/geniezone/gzvm_vm.c create mode 100644 include/uapi/linux/gzvm.h diff --git a/MAINTAINERS b/MAINTAINERS index 708c13103ec5..e7fd6f6a4350 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9680,6 +9680,7 @@ F: Documentation/virt/geniezone/ F: arch/arm64/geniezone/ F: drivers/virt/geniezone/ F: include/linux/soc/mediatek/gzvm_drv.h +F: include/uapi/linux/gzvm.h =20 GENWQE (IBM Generic Workqueue Card) M: Frank Haverkamp diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 660c7cf3fc18..60ee5ed2b39f 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -9,6 +9,8 @@ #include =20 enum { + GZVM_FUNC_CREATE_VM =3D 0, + GZVM_FUNC_DESTROY_VM =3D 1, GZVM_FUNC_PROBE =3D 12, NR_GZVM_FUNC, }; @@ -19,6 +21,8 @@ enum { ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ SMC_ENTITY_MTK, (GZVM_FUNCID_START + (func))) =20 +#define MT_HVC_GZVM_CREATE_VM GZVM_HCALL_ID(GZVM_FUNC_CREATE_VM) +#define MT_HVC_GZVM_DESTROY_VM GZVM_HCALL_ID(GZVM_FUNC_DESTROY_VM) #define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) =20 /** diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index daad21b28f6f..8e3c9f872bb1 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -7,6 +7,7 @@ #include #include =20 +#include #include #include "gzvm_arch_common.h" =20 @@ -70,3 +71,29 @@ int gzvm_arch_probe(struct gzvm_version drv_version, =20 return 0; } + +/** + * gzvm_arch_create_vm() - create vm + * @vm_type: VM type. Only supports Linux VM now. + * + * Return: + * * positive value - VM ID + * * -ENOMEM - Memory not enough for storing VM data + */ +int gzvm_arch_create_vm(unsigned long vm_type) +{ + struct arm_smccc_res res; + int ret; + + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_CREATE_VM, vm_type, 0, 0, 0, 0, + 0, 0, &res); + return ret ? ret : res.a1; +} + +int gzvm_arch_destroy_vm(u16 vm_id) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_DESTROY_VM, vm_id, 0, 0, 0, 0, + 0, 0, &res); +} diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makef= ile index 3a82e5fddf90..25614ea3dea2 100644 --- a/drivers/virt/geniezone/Makefile +++ b/drivers/virt/geniezone/Makefile @@ -6,4 +6,4 @@ =20 GZVM_DIR ?=3D ../../../drivers/virt/geniezone =20 -gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o +gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index dc91fd61ba75..02dec63ce48f 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -4,6 +4,7 @@ */ =20 #include +#include #include #include #include @@ -48,6 +49,19 @@ int gzvm_err_to_errno(unsigned long err) return -EINVAL; } =20 +static long gzvm_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long user_args) +{ + switch (cmd) { + case GZVM_CREATE_VM: + return gzvm_dev_ioctl_create_vm(&gzvm_drv, user_args); + default: + break; + } + + return -ENOTTY; +} + static int gzvm_dev_open(struct inode *inode, struct file *file) { /* @@ -65,6 +79,7 @@ static int gzvm_dev_release(struct inode *inode, struct f= ile *file) } =20 static const struct file_operations gzvm_chardev_ops =3D { + .unlocked_ioctl =3D gzvm_dev_ioctl, .llseek =3D noop_llseek, .open =3D gzvm_dev_open, .release =3D gzvm_dev_release, diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c new file mode 100644 index 000000000000..500bc8276d60 --- /dev/null +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_MUTEX(gzvm_list_lock); +static LIST_HEAD(gzvm_list); + +static void gzvm_destroy_vm(struct gzvm *gzvm) +{ + pr_debug("VM-%u is going to be destroyed\n", gzvm->vm_id); + + mutex_lock(&gzvm->lock); + + gzvm_arch_destroy_vm(gzvm->vm_id); + + mutex_lock(&gzvm_list_lock); + list_del(&gzvm->vm_list); + mutex_unlock(&gzvm_list_lock); + + mutex_unlock(&gzvm->lock); + + kfree(gzvm); +} + +static int gzvm_vm_release(struct inode *inode, struct file *filp) +{ + struct gzvm *gzvm =3D filp->private_data; + + gzvm_destroy_vm(gzvm); + return 0; +} + +static const struct file_operations gzvm_vm_fops =3D { + .release =3D gzvm_vm_release, +}; + +static struct gzvm *gzvm_create_vm(struct gzvm_driver *drv, unsigned long = vm_type) +{ + int ret; + struct gzvm *gzvm; + + gzvm =3D kzalloc(sizeof(*gzvm), GFP_KERNEL); + if (!gzvm) + return ERR_PTR(-ENOMEM); + + ret =3D gzvm_arch_create_vm(vm_type); + if (ret < 0) { + kfree(gzvm); + return ERR_PTR(ret); + } + + gzvm->gzvm_drv =3D drv; + gzvm->vm_id =3D ret; + gzvm->mm =3D current->mm; + mutex_init(&gzvm->lock); + + mutex_lock(&gzvm_list_lock); + list_add(&gzvm->vm_list, &gzvm_list); + mutex_unlock(&gzvm_list_lock); + + pr_debug("VM-%u is created\n", gzvm->vm_id); + + return gzvm; +} + +/** + * gzvm_dev_ioctl_create_vm - Create vm fd + * @vm_type: VM type. Only supports Linux VM now + * @drv: GenieZone driver info to be stored in struct gzvm for future usage + * + * Return: fd of vm, negative if error + */ +int gzvm_dev_ioctl_create_vm(struct gzvm_driver *drv, unsigned long vm_typ= e) +{ + struct gzvm *gzvm; + + gzvm =3D gzvm_create_vm(drv, vm_type); + if (IS_ERR(gzvm)) + return PTR_ERR(gzvm); + + return anon_inode_getfd("gzvm-vm", &gzvm_vm_fops, gzvm, + O_RDWR | O_CLOEXEC); +} diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 495bf5b8b8e0..70008afaaf61 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -6,6 +6,10 @@ #ifndef __GZVM_DRV_H__ #define __GZVM_DRV_H__ =20 +#include +#include +#include + /* GZVM version encode */ #define GZVM_DRV_MAJOR_VERSION 16 #define GZVM_DRV_MINOR_VERSION 0 @@ -21,6 +25,8 @@ struct gzvm_driver { struct gzvm_version drv_version; }; =20 +#define INVALID_VM_ID 0xffff + /* * These are the definitions of APIs between GenieZone hypervisor and driv= er, * there's no need to be visible to uapi. Furthermore, we need GenieZone @@ -32,10 +38,33 @@ struct gzvm_driver { #define ERR_NOT_IMPLEMENTED (-27) #define ERR_FAULT (-40) =20 +/** + * struct gzvm: the following data structures are for data transferring be= tween + * driver and hypervisor, and they're aligned with hypervisor definitions. + * @gzvm_drv: the data structure is used to keep driver's information + * @mm: userspace tied to this vm + * @lock: lock for list_add + * @vm_list: list head for vm list + * @vm_id: vm id + */ +struct gzvm { + struct gzvm_driver *gzvm_drv; + struct mm_struct *mm; + struct mutex lock; + struct list_head vm_list; + u16 vm_id; +}; + +int gzvm_dev_ioctl_create_vm(struct gzvm_driver *drv, unsigned long vm_typ= e); + int gzvm_err_to_errno(unsigned long err); =20 +void gzvm_destroy_all_vms(void); + /* arch-dependant functions */ int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version); +int gzvm_arch_create_vm(unsigned long vm_type); +int gzvm_arch_destroy_vm(u16 vm_id); =20 #endif /* __GZVM_DRV_H__ */ diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h new file mode 100644 index 000000000000..c26c7720fab7 --- /dev/null +++ b/include/uapi/linux/gzvm.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +/** + * DOC: UAPI of GenieZone Hypervisor + * + * This file declares common data structure shared among user space, + * kernel space, and GenieZone hypervisor. + */ +#ifndef __GZVM_H__ +#define __GZVM_H__ + +#include +#include +#include + +/* GZVM ioctls */ +#define GZVM_IOC_MAGIC 0x92 /* gz */ + +/* ioctls for /dev/gzvm fds */ +#define GZVM_CREATE_VM _IO(GZVM_IOC_MAGIC, 0x01) /* Returns = a Geniezone VM fd */ + +#endif /* __GZVM_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 395B81F8186; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; cv=none; b=fTYDWg4lEZydx4n8IPVY017+b4zVVVrE91tiSn+3Cgedmrqt+LmlkUn3ZatxeHBGhrp4E0DFYbQYAkn1Qm59oN23feMZRT8HSxHIpWlvsAWEK6y1p2hcE6/POV57iEFq3E2GiD+c8MMh+I1GwY6M1ypwrRCFiOErq3kddrk2P3U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; c=relaxed/simple; bh=vDrCF1jEyeRoGyWgogrWsoiDlZptE4FguL7PD6asEpA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=X0Ws/oZI/36bQjJZX8au5fpHYtsFusEUU9K0vQagyX73BKo3OEcd3CRr/pRRNS8WTbCxs6rMU5AmARrMS9wqGJAcuulCBORZTPj5QKVsT2hrAt7VFLMvx/Q/2F3AyLwkaZYkh9ivw/l97q2ppKKod1BTv47gpx0jL7dX80X3L58= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=qEAILsDA; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="qEAILsDA" X-UUID: 565b6e90a27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=u5UgKkLQICznpxBLnHfAmIGMhd7AIetkQb14w1LT4Fw=; b=qEAILsDAYS55mjjgi/k/GtGOGimpjge8fQbphqPnx2DBpUZsN55QYWIMo7ug+LN1K1XssQqzqrINS9rBS+jyd9Ho79rss54cg4s+u28y8i/k/chRfKRfgt8P/OXJz+H+w6RtuhApU9jDsYfRbWoPvJ4ELFZ7YXoY+RzfXKOwwjw=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:3b66df0d-44b2-4657-9bea-70f04e0eea6f,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:183fa25c-f18b-4d56-b49c-93279ee09144,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 565b6e90a27011ef99858b75a2457dd9-20241114 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1802850390; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:03 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:03 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 06/25] virt: geniezone: Add set_user_memory_region for vm Date: Thu, 14 Nov 2024 18:07:43 +0800 Message-ID: <20241114100802.4116-7-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan Direct use of physical memory from VMs is forbidden and designed to be dictated to the privilege models managed by GenieZone hypervisor for security reason. With the help of gzvm-ko, the hypervisor would be able to manipulate memory as objects. And the memory management is highly integrated with ARM 2-stage translation tables to convert VA to IPA to PA under proper security measures required by protected VMs. Signed-off-by: Yingshiuan Pan Co-developed-by: Jerry Wang Signed-off-by: Jerry Wang Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 2 + arch/arm64/geniezone/vm.c | 9 ++ drivers/virt/geniezone/gzvm_vm.c | 141 ++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 65 +++++++++++ include/uapi/linux/gzvm.h | 31 ++++++ 5 files changed, 248 insertions(+) diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 60ee5ed2b39f..4250c0f567e7 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -11,6 +11,7 @@ enum { GZVM_FUNC_CREATE_VM =3D 0, GZVM_FUNC_DESTROY_VM =3D 1, + GZVM_FUNC_SET_MEMREGION =3D 4, GZVM_FUNC_PROBE =3D 12, NR_GZVM_FUNC, }; @@ -23,6 +24,7 @@ enum { =20 #define MT_HVC_GZVM_CREATE_VM GZVM_HCALL_ID(GZVM_FUNC_CREATE_VM) #define MT_HVC_GZVM_DESTROY_VM GZVM_HCALL_ID(GZVM_FUNC_DESTROY_VM) +#define MT_HVC_GZVM_SET_MEMREGION GZVM_HCALL_ID(GZVM_FUNC_SET_MEMREGION) #define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) =20 /** diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 8e3c9f872bb1..f15a3ba8e295 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -72,6 +72,15 @@ int gzvm_arch_probe(struct gzvm_version drv_version, return 0; } =20 +int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, + phys_addr_t region) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_SET_MEMREGION, vm_id, + buf_size, region, 0, 0, 0, 0, &res); +} + /** * gzvm_arch_create_vm() - create vm * @vm_type: VM type. Only supports Linux VM now. diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 500bc8276d60..7daa79c16dd1 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -15,6 +15,146 @@ static DEFINE_MUTEX(gzvm_list_lock); static LIST_HEAD(gzvm_list); =20 +int gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot, u64 gfn, + u64 *hva_memslot) +{ + u64 offset; + + if (gfn < memslot->base_gfn) + return -EINVAL; + + offset =3D gfn - memslot->base_gfn; + *hva_memslot =3D memslot->userspace_addr + offset * PAGE_SIZE; + return 0; +} + +/** + * register_memslot_addr_range() - Register memory region to GenieZone + * @gzvm: Pointer to struct gzvm + * @memslot: Pointer to struct gzvm_memslot + * + * Return: 0 for success, negative number for error + */ +static int +register_memslot_addr_range(struct gzvm *gzvm, struct gzvm_memslot *memslo= t) +{ + struct gzvm_memory_region_ranges *region; + u32 buf_size =3D PAGE_SIZE * 2; + u64 gfn; + + region =3D alloc_pages_exact(buf_size, GFP_KERNEL); + if (!region) + return -ENOMEM; + + region->slot =3D memslot->slot_id; + region->total_pages =3D memslot->npages; + gfn =3D memslot->base_gfn; + region->gpa =3D PFN_PHYS(gfn); + + if (gzvm_arch_set_memregion(gzvm->vm_id, buf_size, + virt_to_phys(region))) { + pr_err("Failed to register memregion to hypervisor\n"); + free_pages_exact(region, buf_size); + return -EFAULT; + } + + free_pages_exact(region, buf_size); + return 0; +} + +/** + * memory_region_pre_check() - Preliminary check for userspace memory regi= on + * @gzvm: Pointer to struct gzvm. + * @mem: Input memory region from user. + * + * Return: true for check passed, false for invalid input. + */ +static bool +memory_region_pre_check(struct gzvm *gzvm, + struct gzvm_userspace_memory_region *mem) +{ + if (mem->slot >=3D GZVM_MAX_MEM_REGION) + return false; + + if (!PAGE_ALIGNED(mem->guest_phys_addr) || + !PAGE_ALIGNED(mem->memory_size)) + return false; + + if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) + return false; + + if ((mem->memory_size >> PAGE_SHIFT) > GZVM_MEM_MAX_NR_PAGES) + return false; + + return true; +} + +/** + * gzvm_vm_ioctl_set_memory_region() - Set memory region of guest + * @gzvm: Pointer to struct gzvm. + * @mem: Input memory region from user. + * + * Return: 0 for success, negative number for error + * + * -EXIO - The memslot is out-of-range + * -EFAULT - Cannot find corresponding vma + * -EINVAL - Region size and VMA size mismatch + */ +static int +gzvm_vm_ioctl_set_memory_region(struct gzvm *gzvm, + struct gzvm_userspace_memory_region *mem) +{ + struct vm_area_struct *vma; + struct gzvm_memslot *memslot; + unsigned long size; + + if (memory_region_pre_check(gzvm, mem) !=3D true) + return -EINVAL; + + memslot =3D &gzvm->memslot[mem->slot]; + + vma =3D vma_lookup(gzvm->mm, mem->userspace_addr); + if (!vma) + return -EFAULT; + + size =3D vma->vm_end - vma->vm_start; + if (size !=3D mem->memory_size) + return -EINVAL; + + memslot->base_gfn =3D __phys_to_pfn(mem->guest_phys_addr); + memslot->npages =3D size >> PAGE_SHIFT; + memslot->userspace_addr =3D mem->userspace_addr; + memslot->vma =3D vma; + memslot->flags =3D mem->flags; + memslot->slot_id =3D mem->slot; + return register_memslot_addr_range(gzvm, memslot); +} + +/* gzvm_vm_ioctl() - Ioctl handler of VM FD */ +static long gzvm_vm_ioctl(struct file *filp, unsigned int ioctl, + unsigned long arg) +{ + long ret; + void __user *argp =3D (void __user *)arg; + struct gzvm *gzvm =3D filp->private_data; + + switch (ioctl) { + case GZVM_SET_USER_MEMORY_REGION: { + struct gzvm_userspace_memory_region userspace_mem; + + if (copy_from_user(&userspace_mem, argp, sizeof(userspace_mem))) + return -EFAULT; + + ret =3D gzvm_vm_ioctl_set_memory_region(gzvm, &userspace_mem); + break; + } + default: + ret =3D -ENOTTY; + } + + return ret; +} + static void gzvm_destroy_vm(struct gzvm *gzvm) { pr_debug("VM-%u is going to be destroyed\n", gzvm->vm_id); @@ -42,6 +182,7 @@ static int gzvm_vm_release(struct inode *inode, struct f= ile *filp) =20 static const struct file_operations gzvm_vm_fops =3D { .release =3D gzvm_vm_release, + .unlocked_ioctl =3D gzvm_vm_ioctl, }; =20 static struct gzvm *gzvm_create_vm(struct gzvm_driver *drv, unsigned long = vm_type) diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 70008afaaf61..e309ad169e34 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -7,6 +7,7 @@ #define __GZVM_DRV_H__ =20 #include +#include #include #include =20 @@ -25,6 +26,12 @@ struct gzvm_driver { struct gzvm_version drv_version; }; =20 +/* + * For the normal physical address, the highest 12 bits should be zero, so= we + * can mask bit 62 ~ bit 52 to indicate the error physical address + */ +#define GZVM_PA_ERR_BAD (0x7ffULL << 52) + #define INVALID_VM_ID 0xffff =20 /* @@ -38,11 +45,63 @@ struct gzvm_driver { #define ERR_NOT_IMPLEMENTED (-27) #define ERR_FAULT (-40) =20 +/* + * The following data structures are for data transferring between driver = and + * hypervisor, and they're aligned with hypervisor definitions + */ +#define GZVM_MAX_MEM_REGION 10 + +/** + * struct mem_region_addr_range: identical to ffa memory constituent + * @address: the base IPA of the constituent memory region, aligned to 4 k= iB + * @pg_cnt: the number of 4 kiB pages in the constituent memory region + * @reserved: reserved for 64bit alignment + */ +struct mem_region_addr_range { + __u64 address; + __u32 pg_cnt; + __u32 reserved; +}; + +struct gzvm_memory_region_ranges { + __u32 slot; + __u32 constituent_cnt; + __u64 total_pages; + __u64 gpa; + struct mem_region_addr_range constituents[]; +}; + +/* + * A reasonable and large enough limit for the maximum number of pages a + * guest can use. + */ +#define GZVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1) + +/** + * struct gzvm_memslot: VM's memory slot descriptor + * @base_gfn: begin of guest page frame + * @npages: number of pages this slot covers + * @userspace_addr: corresponding userspace va + * @vma: vma related to this userspace addr + * @flags: define the usage of memory region. Ex. guest memory or + * firmware protection + * @slot_id: the id is used to identify the memory slot + */ +struct gzvm_memslot { + u64 base_gfn; + unsigned long npages; + unsigned long userspace_addr; + struct vm_area_struct *vma; + u32 flags; + u32 slot_id; +}; + /** * struct gzvm: the following data structures are for data transferring be= tween * driver and hypervisor, and they're aligned with hypervisor definitions. * @gzvm_drv: the data structure is used to keep driver's information * @mm: userspace tied to this vm + * @memslot: VM's memory slot descriptor * @lock: lock for list_add * @vm_list: list head for vm list * @vm_id: vm id @@ -50,6 +109,7 @@ struct gzvm_driver { struct gzvm { struct gzvm_driver *gzvm_drv; struct mm_struct *mm; + struct gzvm_memslot memslot[GZVM_MAX_MEM_REGION]; struct mutex lock; struct list_head vm_list; u16 vm_id; @@ -64,7 +124,12 @@ void gzvm_destroy_all_vms(void); /* arch-dependant functions */ int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version); +int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, + phys_addr_t region); int gzvm_arch_create_vm(unsigned long vm_type); int gzvm_arch_destroy_vm(u16 vm_id); =20 +int gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot, u64 gfn, + u64 *hva_memslot); + #endif /* __GZVM_DRV_H__ */ diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index c26c7720fab7..59c0f790b2e6 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -22,4 +22,35 @@ /* ioctls for /dev/gzvm fds */ #define GZVM_CREATE_VM _IO(GZVM_IOC_MAGIC, 0x01) /* Returns = a Geniezone VM fd */ =20 +/* ioctls for VM fds */ +/* for GZVM_SET_MEMORY_REGION */ +struct gzvm_memory_region { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; /* bytes */ +}; + +#define GZVM_SET_MEMORY_REGION _IOW(GZVM_IOC_MAGIC, 0x40, \ + struct gzvm_memory_region) + +/** + * struct gzvm_userspace_memory_region: gzvm userspace memory region descr= iptor + * @slot: memory slot + * @flags: describe the usage of userspace memory region + * @guest_phys_addr: guest vm's physical address + * @memory_size: memory size in bytes + * @userspace_addr: start of the userspace allocated memory + */ +struct gzvm_userspace_memory_region { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; + __u64 userspace_addr; +}; + +#define GZVM_SET_USER_MEMORY_REGION _IOW(GZVM_IOC_MAGIC, 0x46, \ + struct gzvm_userspace_memory_region) + #endif /* __GZVM_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 39F3A1F8187; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; cv=none; b=qe7jVLIqwQc6KnUGPl4/iBNP1Exx+MgN8dQdKz+oAnDLTYgXBMpF/RF/RjG+IUvuQVJBx57tlmNwcFu+2OYSlOBLOmPNVGiWXuIY1EIm/fSu9ffk6jV3LamRvcFLYYhYALQJoA0k953p2j63+ReJuySV2nHEXOMh1ToRCcN0ebo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; c=relaxed/simple; bh=Pid3CQJuJuhKp+z7f+AQIHesTIk2BY8AAAhe7Lnv4wk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=FliBBA/Zi2z0RqTEU6M/jtxFzhjF7MEqdsfbhuduXe1AK/r4nsSaZetfC6VJS2N64NyjnasC6Rxzq/sNWbIxUKUAKmOZBcL9eoV9m6cBO5plXs1N5ghSk3YNrmdPt9HUWLbdBuPQUyII2bRjiYV9TzGYoRAZu9YzJoMtB4frD/k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=FSbk0Iev; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="FSbk0Iev" X-UUID: 570e11eea27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=9OLvAP+NG9HiNLs4uhxNVA9q12G2YrIAijNru0vfkKk=; b=FSbk0IevXudo1+0TXVwc1DbqdyMLKSb+RNZD9RArSu6jBCW4dsWLwffnL14R4Njjlk0FMH7mxQ/Nl6e1XzYP80+ex+/j2khQ890S6N67eA3ZAsxTaGxh9NIE/vNFMBiM55ys+Gd09eOIMDSdKb6y6DNy4vZec27h6AFjhBjS6aw=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:b7514412-83ae-4313-b644-930b3f08f3c6,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:c25e0c4f-a2ae-4b53-acd4-c3dc8f449198,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 570e11eea27011efbd192953cf12861f-20241114 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1096866175; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:03 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:03 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 07/25] virt: geniezone: Add vm capability check Date: Thu, 14 Nov 2024 18:07:44 +0800 Message-ID: <20241114100802.4116-8-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan Inquire the `capability support` on GenieZone hypervisor. Example: `GZVM_CAP_PROTECTED_VM` or `GZVM_CAP_VM_GPA_SIZE`. Signed-off-by: Yingshiuan Pan Co-developed-by: Jerry Wang Signed-off-by: Jerry Wang Co-developed-by: Kevenny Hsieh Signed-off-by: Kevenny Hsieh Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 2 + arch/arm64/geniezone/vm.c | 122 ++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_main.c | 26 +++++ drivers/virt/geniezone/gzvm_vm.c | 23 ++++- include/linux/soc/mediatek/gzvm_drv.h | 5 + include/uapi/linux/gzvm.h | 31 ++++++ 6 files changed, 208 insertions(+), 1 deletion(-) diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 4250c0f567e7..e500dbe7f943 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -13,6 +13,7 @@ enum { GZVM_FUNC_DESTROY_VM =3D 1, GZVM_FUNC_SET_MEMREGION =3D 4, GZVM_FUNC_PROBE =3D 12, + GZVM_FUNC_ENABLE_CAP =3D 13, NR_GZVM_FUNC, }; =20 @@ -26,6 +27,7 @@ enum { #define MT_HVC_GZVM_DESTROY_VM GZVM_HCALL_ID(GZVM_FUNC_DESTROY_VM) #define MT_HVC_GZVM_SET_MEMREGION GZVM_HCALL_ID(GZVM_FUNC_SET_MEMREGION) #define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) +#define MT_HVC_GZVM_ENABLE_CAP GZVM_HCALL_ID(GZVM_FUNC_ENABLE_CAP) =20 /** * gzvm_hypcall_wrapper() - the wrapper for hvc calls diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index f15a3ba8e295..75748c9ce3be 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -81,6 +81,40 @@ int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, buf_size, region, 0, 0, 0, 0, &res); } =20 +static int gzvm_cap_vm_gpa_size(void __user *argp) +{ + __u64 value =3D CONFIG_ARM64_PA_BITS; + + if (copy_to_user(argp, &value, sizeof(__u64))) + return -EFAULT; + + return 0; +} + +int gzvm_arch_check_extension(struct gzvm *gzvm, __u64 cap, void __user *a= rgp) +{ + int ret; + + switch (cap) { + case GZVM_CAP_PROTECTED_VM: { + __u64 success =3D 1; + + if (copy_to_user(argp, &success, sizeof(__u64))) + return -EFAULT; + + return 0; + } + case GZVM_CAP_VM_GPA_SIZE: { + ret =3D gzvm_cap_vm_gpa_size(argp); + return ret; + } + default: + break; + } + + return -EOPNOTSUPP; +} + /** * gzvm_arch_create_vm() - create vm * @vm_type: VM type. Only supports Linux VM now. @@ -106,3 +140,91 @@ int gzvm_arch_destroy_vm(u16 vm_id) return gzvm_hypcall_wrapper(MT_HVC_GZVM_DESTROY_VM, vm_id, 0, 0, 0, 0, 0, 0, &res); } + +static int gzvm_vm_arch_enable_cap(struct gzvm *gzvm, + struct gzvm_enable_cap *cap, + struct arm_smccc_res *res) +{ + return gzvm_hypcall_wrapper(MT_HVC_GZVM_ENABLE_CAP, gzvm->vm_id, + cap->cap, cap->args[0], cap->args[1], + cap->args[2], cap->args[3], cap->args[4], + res); +} + +/** + * gzvm_vm_ioctl_get_pvmfw_size() - Get pvmfw size from hypervisor, return + * in x1, and return to userspace in args + * @gzvm: Pointer to struct gzvm. + * @cap: Pointer to struct gzvm_enable_cap. + * @argp: Pointer to struct gzvm_enable_cap in user space. + * + * Return: + * * 0 - Succeed + * * -EINVAL - Hypervisor return invalid results + * * -EFAULT - Fail to copy back to userspace buffer + */ +static int gzvm_vm_ioctl_get_pvmfw_size(struct gzvm *gzvm, + struct gzvm_enable_cap *cap, + void __user *argp) +{ + struct arm_smccc_res res =3D {0}; + + if (gzvm_vm_arch_enable_cap(gzvm, cap, &res) !=3D 0) + return -EINVAL; + + cap->args[1] =3D res.a1; + if (copy_to_user(argp, cap, sizeof(*cap))) + return -EFAULT; + + return 0; +} + +/** + * gzvm_vm_ioctl_cap_pvm() - Proceed GZVM_CAP_PROTECTED_VM's subcommands + * @gzvm: Pointer to struct gzvm. + * @cap: Pointer to struct gzvm_enable_cap. + * @argp: Pointer to struct gzvm_enable_cap in user space. + * + * Return: + * * 0 - Succeed + * * -EINVAL - Invalid subcommand or arguments + */ +static int gzvm_vm_ioctl_cap_pvm(struct gzvm *gzvm, + struct gzvm_enable_cap *cap, + void __user *argp) +{ + struct arm_smccc_res res =3D {0}; + int ret; + + switch (cap->args[0]) { + case GZVM_CAP_PVM_SET_PVMFW_GPA: + fallthrough; + case GZVM_CAP_PVM_SET_PROTECTED_VM: + ret =3D gzvm_vm_arch_enable_cap(gzvm, cap, &res); + return ret; + case GZVM_CAP_PVM_GET_PVMFW_SIZE: + ret =3D gzvm_vm_ioctl_get_pvmfw_size(gzvm, cap, argp); + return ret; + default: + break; + } + + return -EINVAL; +} + +int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, + struct gzvm_enable_cap *cap, + void __user *argp) +{ + int ret; + + switch (cap->cap) { + case GZVM_CAP_PROTECTED_VM: + ret =3D gzvm_vm_ioctl_cap_pvm(gzvm, cap, argp); + return ret; + default: + break; + } + + return -EINVAL; +} diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index 02dec63ce48f..db1076c9a4da 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -49,12 +49,38 @@ int gzvm_err_to_errno(unsigned long err) return -EINVAL; } =20 +/** + * gzvm_dev_ioctl_check_extension() - Check if given capability is support + * or not + * + * @gzvm: Pointer to struct gzvm + * @args: Pointer in u64 from userspace + * + * Return: + * * 0 - Supported, no error + * * -EOPNOTSUPP - Unsupported + * * -EFAULT - Failed to get data from userspace + */ +long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args) +{ + __u64 cap; + void __user *argp =3D (void __user *)args; + + if (copy_from_user(&cap, argp, sizeof(uint64_t))) + return -EFAULT; + return gzvm_arch_check_extension(gzvm, cap, argp); +} + static long gzvm_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long user_args) { switch (cmd) { case GZVM_CREATE_VM: return gzvm_dev_ioctl_create_vm(&gzvm_drv, user_args); + case GZVM_CHECK_EXTENSION: + if (!user_args) + return -EINVAL; + return gzvm_dev_ioctl_check_extension(NULL, user_args); default: break; } diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 7daa79c16dd1..2f6d416f5518 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -130,6 +130,13 @@ gzvm_vm_ioctl_set_memory_region(struct gzvm *gzvm, return register_memslot_addr_range(gzvm, memslot); } =20 +static int gzvm_vm_ioctl_enable_cap(struct gzvm *gzvm, + struct gzvm_enable_cap *cap, + void __user *argp) +{ + return gzvm_vm_ioctl_arch_enable_cap(gzvm, cap, argp); +} + /* gzvm_vm_ioctl() - Ioctl handler of VM FD */ static long gzvm_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) @@ -139,6 +146,10 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned = int ioctl, struct gzvm *gzvm =3D filp->private_data; =20 switch (ioctl) { + case GZVM_CHECK_EXTENSION: { + ret =3D gzvm_dev_ioctl_check_extension(gzvm, arg); + break; + } case GZVM_SET_USER_MEMORY_REGION: { struct gzvm_userspace_memory_region userspace_mem; =20 @@ -148,10 +159,20 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned= int ioctl, ret =3D gzvm_vm_ioctl_set_memory_region(gzvm, &userspace_mem); break; } + case GZVM_ENABLE_CAP: { + struct gzvm_enable_cap cap; + + if (copy_from_user(&cap, argp, sizeof(cap))) { + ret =3D -EFAULT; + goto out; + } + ret =3D gzvm_vm_ioctl_enable_cap(gzvm, &cap, argp); + break; + } default: ret =3D -ENOTTY; } - +out: return ret; } =20 diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index e309ad169e34..f8503c52708a 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -115,6 +115,7 @@ struct gzvm { u16 vm_id; }; =20 +long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args); int gzvm_dev_ioctl_create_vm(struct gzvm_driver *drv, unsigned long vm_typ= e); =20 int gzvm_err_to_errno(unsigned long err); @@ -126,8 +127,12 @@ int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version); int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, phys_addr_t region); +int gzvm_arch_check_extension(struct gzvm *gzvm, __u64 cap, void __user *a= rgp); int gzvm_arch_create_vm(unsigned long vm_type); int gzvm_arch_destroy_vm(u16 vm_id); +int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, + struct gzvm_enable_cap *cap, + void __user *argp); =20 int gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot, u64 gfn, u64 *hva_memslot); diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 59c0f790b2e6..a79e787c9181 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -16,12 +16,30 @@ #include #include =20 +#define GZVM_CAP_VM_GPA_SIZE 0xa5 +#define GZVM_CAP_PROTECTED_VM 0xffbadab1 + +/* sub-commands put in args[0] for GZVM_CAP_PROTECTED_VM */ +#define GZVM_CAP_PVM_SET_PVMFW_GPA 0 +#define GZVM_CAP_PVM_GET_PVMFW_SIZE 1 +/* GZVM_CAP_PVM_SET_PROTECTED_VM only sets protected but not load pvmfw */ +#define GZVM_CAP_PVM_SET_PROTECTED_VM 2 + /* GZVM ioctls */ #define GZVM_IOC_MAGIC 0x92 /* gz */ =20 /* ioctls for /dev/gzvm fds */ #define GZVM_CREATE_VM _IO(GZVM_IOC_MAGIC, 0x01) /* Returns = a Geniezone VM fd */ =20 +/* + * Check if the given capability is supported or not. + * The argument is capability. Ex. GZVM_CAP_PROTECTED_VM or GZVM_CAP_VM_GP= A_SIZE + * return is 0 (supported, no error) + * return is -EOPNOTSUPP (unsupported) + * return is -EFAULT (failed to get the argument from userspace) + */ +#define GZVM_CHECK_EXTENSION _IO(GZVM_IOC_MAGIC, 0x03) + /* ioctls for VM fds */ /* for GZVM_SET_MEMORY_REGION */ struct gzvm_memory_region { @@ -53,4 +71,17 @@ struct gzvm_userspace_memory_region { #define GZVM_SET_USER_MEMORY_REGION _IOW(GZVM_IOC_MAGIC, 0x46, \ struct gzvm_userspace_memory_region) =20 +/** + * struct gzvm_enable_cap: The `capability support` on GenieZone hypervisor + * @cap: `GZVM_CAP_ARM_PROTECTED_VM` or `GZVM_CAP_ARM_VM_IPA_SIZE` + * @args: x3-x7 registers can be used for additional args + */ +struct gzvm_enable_cap { + __u64 cap; + __u64 args[5]; +}; + +#define GZVM_ENABLE_CAP _IOW(GZVM_IOC_MAGIC, 0xa3, \ + struct gzvm_enable_cap) + #endif /* __GZVM_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E02891F80A3; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; cv=none; b=op+Gjr/v7ocRWSZ30QJHTgTxCzAur6hfrXjf7dIQ15g/6fWGYIi67kCVHPTuIon1gELtUXIclAsuCASUck72gAVBsiD10UX9loTfE/+dLwJDkpY0/7nKw2KANGgT67d/wd5+0fm3eXPoK8kaABod+9JDMkFbFAs0yvoSBsU8GJA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; c=relaxed/simple; bh=CnYKCnjh+OshG3c4GDnK1NxoRbxyHtQ1oIVD7bFvZ7s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lLZyWM/0T9brC00UNMKIR5hSy31rZ+SmJyLVfnlPTAMQf9MUc9h8fhIxdzcpvsA82U3+NYpq3nKkKn1CxXYup7hyAYSAn5cIj61QZqNui+QJ9WpFRfu6Tp4KSDwu68T8sYjyFAjIPOdHbvjtnQzxbmH1EeXNQgfice2wfjyUXeI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=T9IIliPh; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="T9IIliPh" X-UUID: 573aacb8a27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=N/RXaBfRcnx99pYbTmZfmdkFcNtrHaodlykF5WFiOH4=; b=T9IIliPh2fb83sizhEj8W5+z5CwMGuYkPbCFFx//+JZDVc/KlCAFKp79WVHaT5HlL2bj411i9SPFIednPzirU6WzKScpvji//HjxtRFUd+3CkDHeSWbR5BZqCTWJsAdFkkgfp9TBWga4Ds4BYBYv3INqjmGhdJEBAItAExAc8rI=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:ba593133-b891-4012-ae14-f03a6b03b8cc,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:df5e0c4f-a2ae-4b53-acd4-c3dc8f449198,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_ULN,TF_CID_SPAM_SNR X-UUID: 573aacb8a27011ef99858b75a2457dd9-20241114 Received: from mtkmbs11n2.mediatek.inc [(172.21.101.187)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1862349412; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:04 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , "Catalin Marinas" , Will Deacon , "Steven Rostedt" , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 08/25] virt: geniezone: Add vcpu support Date: Thu, 14 Nov 2024 18:07:45 +0800 Message-ID: <20241114100802.4116-9-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--20.544700-8.000000 X-TMASE-MatchedRID: ECSH4q3mZHU0+65nJzb9bEraSPuPii4AtjHGWON8yeMKOjjtK9XSTadT v3G1Y/zd4Qs7pgHb9b2tsViygrLz2s3AmdtMjGJV7spMO3HwKCBMkOX0UoduuQ6QlBHhBZuwPJ0 5UREtjOWcPcDHCp4L+uSWVqW5qzmOj1OThq6Zp6Dd+fuf9kcapkDwlkRNC6PCYmQk5BUIinA6HX BOl2Wm2Qj52DJiGF5HqzwZPjuphJ40tXz7JRHgp6OuVibdZNTv+eBf9ovw8I3xSV7YBeBhS7cei 5v4WhA88AJGS7I64l28Q8AeJlNjCOwy2NhRsPyb/IBH0OAL+EcpWss5kPUFdOyoRjfYVC+cEoN4 n3g9RrZM95mRqkWcfzu61Cx4kIX1xlkBw4mGj0DN+qWlu2ZxaPx3eAlFiEvxYdn5x3tXIpf7gOY YNr2s3BOpooSKio6+7AcVBQeYHVk9P00/csRFqOLz1o40byIqv8jdqvFOu+LujTNvTG+bSQIV69 fUswQ/9thk9nbRgmWaYxhidxNqtytBqm1xUHqFJXKk/roE/RBdxx6WRf+5sIKwF4K/wIz9uOiT3 BKFjXv1J65TSXiI79o4ZZRegcAcLiQq6BGiCDiXXOyNnX/prDlIA4KS6pW3uBsk5njfgGxy7uXb FJiueN3wr7DvX5irNQnzreyncQbXvsE3MPuDQmivjLE8DPtZaN2KuTwsCwIZBfmlz1qR+1tqLKp XLjMw4vM1YF6AJbbCCfuIMF6xLcK21zBg2KlfAqYBE3k9Mpw= X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--20.544700-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: A3A018006A9C37D847C2BD1ED5D7913AD45D46DCB55957CF0B3CEDD47585AA3D2000:8 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan VMM use this interface to create vcpu instance which is a fd, and this fd will be for any vcpu operations, such as setting vcpu registers and accepts the most important ioctl GZVM_VCPU_RUN which requests GenieZone hypervisor to do context switch to execute VM's vcpu context. Signed-off-by: Yingshiuan Pan Co-developed-by: Jerry Wang Signed-off-by: Jerry Wang Co-developed-by: Kevenny Hsieh Signed-off-by: Kevenny Hsieh Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/Makefile | 2 +- arch/arm64/geniezone/gzvm_arch_common.h | 18 ++ arch/arm64/geniezone/vcpu.c | 80 ++++++++ arch/arm64/geniezone/vm.c | 12 ++ drivers/virt/geniezone/Makefile | 3 +- drivers/virt/geniezone/gzvm_vcpu.c | 248 ++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_vm.c | 5 + include/linux/soc/mediatek/gzvm_drv.h | 24 +++ include/uapi/linux/gzvm.h | 163 ++++++++++++++++ 9 files changed, 553 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/geniezone/vcpu.c create mode 100644 drivers/virt/geniezone/gzvm_vcpu.c diff --git a/arch/arm64/geniezone/Makefile b/arch/arm64/geniezone/Makefile index 2957898cdd05..69b0a4abeab0 100644 --- a/arch/arm64/geniezone/Makefile +++ b/arch/arm64/geniezone/Makefile @@ -4,6 +4,6 @@ # include $(srctree)/drivers/virt/geniezone/Makefile =20 -gzvm-y +=3D vm.o +gzvm-y +=3D vm.o vcpu.o =20 obj-$(CONFIG_MTK_GZVM) +=3D gzvm.o diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index e500dbe7f943..3ec7bea5651f 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -11,9 +11,15 @@ enum { GZVM_FUNC_CREATE_VM =3D 0, GZVM_FUNC_DESTROY_VM =3D 1, + GZVM_FUNC_CREATE_VCPU =3D 2, + GZVM_FUNC_DESTROY_VCPU =3D 3, GZVM_FUNC_SET_MEMREGION =3D 4, + GZVM_FUNC_RUN =3D 5, + GZVM_FUNC_GET_ONE_REG =3D 8, + GZVM_FUNC_SET_ONE_REG =3D 9, GZVM_FUNC_PROBE =3D 12, GZVM_FUNC_ENABLE_CAP =3D 13, + GZVM_FUNC_INFORM_EXIT =3D 14, NR_GZVM_FUNC, }; =20 @@ -25,9 +31,15 @@ enum { =20 #define MT_HVC_GZVM_CREATE_VM GZVM_HCALL_ID(GZVM_FUNC_CREATE_VM) #define MT_HVC_GZVM_DESTROY_VM GZVM_HCALL_ID(GZVM_FUNC_DESTROY_VM) +#define MT_HVC_GZVM_CREATE_VCPU GZVM_HCALL_ID(GZVM_FUNC_CREATE_VCPU) +#define MT_HVC_GZVM_DESTROY_VCPU GZVM_HCALL_ID(GZVM_FUNC_DESTROY_VCPU) #define MT_HVC_GZVM_SET_MEMREGION GZVM_HCALL_ID(GZVM_FUNC_SET_MEMREGION) +#define MT_HVC_GZVM_RUN GZVM_HCALL_ID(GZVM_FUNC_RUN) +#define MT_HVC_GZVM_GET_ONE_REG GZVM_HCALL_ID(GZVM_FUNC_GET_ONE_REG) +#define MT_HVC_GZVM_SET_ONE_REG GZVM_HCALL_ID(GZVM_FUNC_SET_ONE_REG) #define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) #define MT_HVC_GZVM_ENABLE_CAP GZVM_HCALL_ID(GZVM_FUNC_ENABLE_CAP) +#define MT_HVC_GZVM_INFORM_EXIT GZVM_HCALL_ID(GZVM_FUNC_INFORM_EXIT) =20 /** * gzvm_hypcall_wrapper() - the wrapper for hvc calls @@ -49,4 +61,10 @@ int gzvm_hypcall_wrapper(unsigned long a0, unsigned long= a1, unsigned long a6, unsigned long a7, struct arm_smccc_res *res); =20 +static inline unsigned int +assemble_vm_vcpu_tuple(u16 vmid, u16 vcpuid) +{ + return ((unsigned int)vmid << 16 | vcpuid); +} + #endif /* __GZVM_ARCH_COMMON_H__ */ diff --git a/arch/arm64/geniezone/vcpu.c b/arch/arm64/geniezone/vcpu.c new file mode 100644 index 000000000000..e12ea9cb4941 --- /dev/null +++ b/arch/arm64/geniezone/vcpu.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include + +#include +#include +#include "gzvm_arch_common.h" + +int gzvm_arch_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, __u64 reg_id, + bool is_write, __u64 *data) +{ + struct arm_smccc_res res; + unsigned long a1; + int ret; + + a1 =3D assemble_vm_vcpu_tuple(vcpu->gzvm->vm_id, vcpu->vcpuid); + if (!is_write) { + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_GET_ONE_REG, + a1, reg_id, 0, 0, 0, 0, 0, &res); + if (ret =3D=3D 0) + *data =3D res.a1; + } else { + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_SET_ONE_REG, + a1, reg_id, *data, 0, 0, 0, 0, &res); + } + + return ret; +} + +int gzvm_arch_vcpu_run(struct gzvm_vcpu *vcpu, __u64 *exit_reason) +{ + struct arm_smccc_res res; + unsigned long a1; + int ret; + + a1 =3D assemble_vm_vcpu_tuple(vcpu->gzvm->vm_id, vcpu->vcpuid); + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_RUN, a1, 0, 0, 0, 0, 0, + 0, &res); + *exit_reason =3D res.a1; + return ret; +} + +int gzvm_arch_destroy_vcpu(u16 vm_id, int vcpuid) +{ + struct arm_smccc_res res; + unsigned long a1; + + a1 =3D assemble_vm_vcpu_tuple(vm_id, vcpuid); + gzvm_hypcall_wrapper(MT_HVC_GZVM_DESTROY_VCPU, a1, 0, 0, 0, 0, 0, 0, + &res); + + return 0; +} + +/** + * gzvm_arch_create_vcpu() - Call smc to gz hypervisor to create vcpu + * @vm_id: vm id + * @vcpuid: vcpu id + * @run: Virtual address of vcpu->run + * + * Return: The wrapper helps caller to convert geniezone errno to Linux er= rno. + */ +int gzvm_arch_create_vcpu(u16 vm_id, int vcpuid, void *run) +{ + struct arm_smccc_res res; + unsigned long a1, a2; + int ret; + + a1 =3D assemble_vm_vcpu_tuple(vm_id, vcpuid); + a2 =3D (__u64)virt_to_phys(run); + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_CREATE_VCPU, a1, a2, 0, 0, 0, 0, + 0, &res); + + return ret; +} diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 75748c9ce3be..743951aa8ec3 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -51,6 +51,18 @@ int gzvm_hypcall_wrapper(unsigned long a0, unsigned long= a1, return gzvm_err_to_errno(res->a0); } =20 +int gzvm_arch_inform_exit(u16 vm_id) +{ + struct arm_smccc_res res; + int ret; + + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_INFORM_EXIT, vm_id, 0, 0, 0, 0, = 0, 0, &res); + if (ret) + return -ENXIO; + + return 0; +} + int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version) { diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makef= ile index 25614ea3dea2..9cc453c0819b 100644 --- a/drivers/virt/geniezone/Makefile +++ b/drivers/virt/geniezone/Makefile @@ -6,4 +6,5 @@ =20 GZVM_DIR ?=3D ../../../drivers/virt/geniezone =20 -gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o +gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o \ + $(GZVM_DIR)/gzvm_vcpu.o diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c new file mode 100644 index 000000000000..c8a4e0f2f027 --- /dev/null +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* maximum size needed for holding an integer */ +#define ITOA_MAX_LEN 12 + +static long gzvm_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, + void __user *argp, + bool is_write) +{ + struct gzvm_one_reg reg; + void __user *reg_addr; + u64 data =3D 0; + u64 reg_size; + long ret; + + if (copy_from_user(®, argp, sizeof(reg))) + return -EFAULT; + + reg_addr =3D u64_to_user_ptr(reg.addr); + reg_size =3D (reg.id & GZVM_REG_SIZE_MASK) >> GZVM_REG_SIZE_SHIFT; + reg_size =3D BIT(reg_size); + + if (reg_size !=3D 1 && reg_size !=3D 2 && reg_size !=3D 4 && reg_size != =3D 8) + return -EINVAL; + + if (is_write) { + /* GZ hypervisor would filter out invalid vcpu register access */ + if (copy_from_user(&data, reg_addr, reg_size)) + return -EFAULT; + } else { + return -EOPNOTSUPP; + } + + ret =3D gzvm_arch_vcpu_update_one_reg(vcpu, reg.id, is_write, &data); + + if (ret) + return ret; + + return 0; +} + +/** + * gzvm_vcpu_run() - Handle vcpu run ioctl, entry point to guest and exit + * point from guest + * @vcpu: Pointer to struct gzvm_vcpu + * @argp: Pointer to struct gzvm_vcpu_run in userspace + * + * Return: + * * 0 - Success. + * * Negative - Failure. + */ +static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, void __user *argp) +{ + bool need_userspace =3D false; + u64 exit_reason =3D 0; + + if (copy_from_user(vcpu->run, argp, sizeof(struct gzvm_vcpu_run))) + return -EFAULT; + + for (int i =3D 0; i < ARRAY_SIZE(vcpu->run->padding1); i++) { + if (vcpu->run->padding1[i]) + return -EINVAL; + } + + if (vcpu->run->immediate_exit =3D=3D 1) + return -EINTR; + + while (!need_userspace && !signal_pending(current)) { + gzvm_arch_vcpu_run(vcpu, &exit_reason); + + switch (exit_reason) { + case GZVM_EXIT_MMIO: + need_userspace =3D true; + break; + /** + * it's geniezone's responsibility to fill corresponding data + * structure + */ + case GZVM_EXIT_HYPERCALL: + fallthrough; + case GZVM_EXIT_EXCEPTION: + fallthrough; + case GZVM_EXIT_DEBUG: + fallthrough; + case GZVM_EXIT_FAIL_ENTRY: + fallthrough; + case GZVM_EXIT_INTERNAL_ERROR: + fallthrough; + case GZVM_EXIT_SYSTEM_EVENT: + fallthrough; + case GZVM_EXIT_SHUTDOWN: + need_userspace =3D true; + break; + case GZVM_EXIT_IRQ: + fallthrough; + case GZVM_EXIT_GZ: + break; + case GZVM_EXIT_UNKNOWN: + fallthrough; + default: + pr_err("vcpu unknown exit\n"); + need_userspace =3D true; + } + } + + if (copy_to_user(argp, vcpu->run, sizeof(struct gzvm_vcpu_run))) + return -EFAULT; + if (signal_pending(current)) { + // invoke hvc to inform gz to map memory + gzvm_arch_inform_exit(vcpu->gzvm->vm_id); + return -ERESTARTSYS; + } + return 0; +} + +static long gzvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, + unsigned long arg) +{ + int ret =3D -ENOTTY; + void __user *argp =3D (void __user *)arg; + struct gzvm_vcpu *vcpu =3D filp->private_data; + + switch (ioctl) { + case GZVM_RUN: + ret =3D gzvm_vcpu_run(vcpu, argp); + break; + case GZVM_GET_ONE_REG: + /* !is_write */ + ret =3D -EOPNOTSUPP; + break; + case GZVM_SET_ONE_REG: + /* is_write */ + ret =3D gzvm_vcpu_update_one_reg(vcpu, argp, true); + break; + default: + break; + } + + return ret; +} + +static const struct file_operations gzvm_vcpu_fops =3D { + .unlocked_ioctl =3D gzvm_vcpu_ioctl, + .llseek =3D noop_llseek, +}; + +/* caller must hold the vm lock */ +static void gzvm_destroy_vcpu(struct gzvm_vcpu *vcpu) +{ + if (!vcpu) + return; + + gzvm_arch_destroy_vcpu(vcpu->gzvm->vm_id, vcpu->vcpuid); + /* clean guest's data */ + memset(vcpu->run, 0, GZVM_VCPU_RUN_MAP_SIZE); + free_pages_exact(vcpu->run, GZVM_VCPU_RUN_MAP_SIZE); + kfree(vcpu); +} + +/** + * gzvm_destroy_vcpus() - Destroy all vcpus, caller has to hold the vm lock + * + * @gzvm: vm struct that owns the vcpus + */ +void gzvm_destroy_vcpus(struct gzvm *gzvm) +{ + int i; + + for (i =3D 0; i < GZVM_MAX_VCPUS; i++) { + gzvm_destroy_vcpu(gzvm->vcpus[i]); + gzvm->vcpus[i] =3D NULL; + } +} + +/* create_vcpu_fd() - Allocates an inode for the vcpu. */ +static int create_vcpu_fd(struct gzvm_vcpu *vcpu) +{ + /* sizeof("gzvm-vcpu:") + max(strlen(itoa(vcpuid))) + null */ + char name[10 + ITOA_MAX_LEN + 1]; + + snprintf(name, sizeof(name), "gzvm-vcpu:%d", vcpu->vcpuid); + return anon_inode_getfd(name, &gzvm_vcpu_fops, vcpu, O_RDWR | O_CLOEXEC); +} + +/** + * gzvm_vm_ioctl_create_vcpu() - for GZVM_CREATE_VCPU + * @gzvm: Pointer to struct gzvm + * @cpuid: equals arg + * + * Return: Fd of vcpu, negative errno if error occurs + */ +int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cpuid) +{ + struct gzvm_vcpu *vcpu; + int ret; + + if (cpuid >=3D GZVM_MAX_VCPUS) + return -EINVAL; + + vcpu =3D kzalloc(sizeof(*vcpu), GFP_KERNEL); + if (!vcpu) + return -ENOMEM; + + /** + * Allocate 2 pages for data sharing between driver and gz hypervisor + * + * |- page 0 -|- page 1 -| + * |gzvm_vcpu_run|......|hwstate|.......| + * + */ + vcpu->run =3D alloc_pages_exact(GZVM_VCPU_RUN_MAP_SIZE, + GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!vcpu->run) { + ret =3D -ENOMEM; + goto free_vcpu; + } + vcpu->vcpuid =3D cpuid; + vcpu->gzvm =3D gzvm; + mutex_init(&vcpu->lock); + + ret =3D gzvm_arch_create_vcpu(gzvm->vm_id, vcpu->vcpuid, vcpu->run); + if (ret < 0) + goto free_vcpu_run; + + ret =3D create_vcpu_fd(vcpu); + if (ret < 0) + goto free_vcpu_run; + gzvm->vcpus[cpuid] =3D vcpu; + + return ret; + +free_vcpu_run: + free_pages_exact(vcpu->run, GZVM_VCPU_RUN_MAP_SIZE); +free_vcpu: + kfree(vcpu); + return ret; +} diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 2f6d416f5518..f6b069dc53fc 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -150,6 +150,10 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned = int ioctl, ret =3D gzvm_dev_ioctl_check_extension(gzvm, arg); break; } + case GZVM_CREATE_VCPU: { + ret =3D gzvm_vm_ioctl_create_vcpu(gzvm, arg); + break; + } case GZVM_SET_USER_MEMORY_REGION: { struct gzvm_userspace_memory_region userspace_mem; =20 @@ -182,6 +186,7 @@ static void gzvm_destroy_vm(struct gzvm *gzvm) =20 mutex_lock(&gzvm->lock); =20 + gzvm_destroy_vcpus(gzvm); gzvm_arch_destroy_vm(gzvm->vm_id); =20 mutex_lock(&gzvm_list_lock); diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index f8503c52708a..ef02df39192d 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -32,6 +32,7 @@ struct gzvm_driver { */ #define GZVM_PA_ERR_BAD (0x7ffULL << 52) =20 +#define GZVM_VCPU_MMAP_SIZE PAGE_SIZE #define INVALID_VM_ID 0xffff =20 /* @@ -49,8 +50,11 @@ struct gzvm_driver { * The following data structures are for data transferring between driver = and * hypervisor, and they're aligned with hypervisor definitions */ +#define GZVM_MAX_VCPUS 8 #define GZVM_MAX_MEM_REGION 10 =20 +#define GZVM_VCPU_RUN_MAP_SIZE (PAGE_SIZE * 2) + /** * struct mem_region_addr_range: identical to ffa memory constituent * @address: the base IPA of the constituent memory region, aligned to 4 k= iB @@ -96,10 +100,19 @@ struct gzvm_memslot { u32 slot_id; }; =20 +struct gzvm_vcpu { + struct gzvm *gzvm; + int vcpuid; + /* lock of vcpu*/ + struct mutex lock; + struct gzvm_vcpu_run *run; +}; + /** * struct gzvm: the following data structures are for data transferring be= tween * driver and hypervisor, and they're aligned with hypervisor definitions. * @gzvm_drv: the data structure is used to keep driver's information + * @vcpus: VM's cpu descriptors * @mm: userspace tied to this vm * @memslot: VM's memory slot descriptor * @lock: lock for list_add @@ -108,6 +121,7 @@ struct gzvm_memslot { */ struct gzvm { struct gzvm_driver *gzvm_drv; + struct gzvm_vcpu *vcpus[GZVM_MAX_VCPUS]; struct mm_struct *mm; struct gzvm_memslot memslot[GZVM_MAX_MEM_REGION]; struct mutex lock; @@ -122,6 +136,8 @@ int gzvm_err_to_errno(unsigned long err); =20 void gzvm_destroy_all_vms(void); =20 +void gzvm_destroy_vcpus(struct gzvm *gzvm); + /* arch-dependant functions */ int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version); @@ -137,4 +153,12 @@ int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, int gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot, u64 gfn, u64 *hva_memslot); =20 +int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cpuid); +int gzvm_arch_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, __u64 reg_id, + bool is_write, __u64 *data); +int gzvm_arch_create_vcpu(u16 vm_id, int vcpuid, void *run); +int gzvm_arch_vcpu_run(struct gzvm_vcpu *vcpu, __u64 *exit_reason); +int gzvm_arch_destroy_vcpu(u16 vm_id, int vcpuid); +int gzvm_arch_inform_exit(u16 vm_id); + #endif /* __GZVM_DRV_H__ */ diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index a79e787c9181..1146467487ca 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -25,6 +25,30 @@ /* GZVM_CAP_PVM_SET_PROTECTED_VM only sets protected but not load pvmfw */ #define GZVM_CAP_PVM_SET_PROTECTED_VM 2 =20 +/* + * Architecture specific registers are to be defined and ORed with + * the arch identifier. + */ +#define GZVM_REG_ARCH_ARM64 FIELD_PREP(GENMASK_ULL(63, 56), 0x60) +#define GZVM_REG_ARCH_MASK FIELD_PREP(GENMASK_ULL(63, 56), 0xff) +/* + * Reg size =3D BIT((reg.id & GZVM_REG_SIZE_MASK) >> GZVM_REG_SIZE_SHIFT) = bytes + */ +#define GZVM_REG_SIZE_SHIFT 52 +#define GZVM_REG_SIZE_MASK FIELD_PREP(GENMASK_ULL(63, 48), 0x00f0) + +#define GZVM_REG_SIZE_U8 FIELD_PREP(GENMASK_ULL(63, 48), 0x0000) +#define GZVM_REG_SIZE_U16 FIELD_PREP(GENMASK_ULL(63, 48), 0x0010) +#define GZVM_REG_SIZE_U32 FIELD_PREP(GENMASK_ULL(63, 48), 0x0020) +#define GZVM_REG_SIZE_U64 FIELD_PREP(GENMASK_ULL(63, 48), 0x0030) +#define GZVM_REG_SIZE_U128 FIELD_PREP(GENMASK_ULL(63, 48), 0x0040) +#define GZVM_REG_SIZE_U256 FIELD_PREP(GENMASK_ULL(63, 48), 0x0050) +#define GZVM_REG_SIZE_U512 FIELD_PREP(GENMASK_ULL(63, 48), 0x0060) +#define GZVM_REG_SIZE_U1024 FIELD_PREP(GENMASK_ULL(63, 48), 0x0070) +#define GZVM_REG_SIZE_U2048 FIELD_PREP(GENMASK_ULL(63, 48), 0x0080) + +#define GZVM_REG_TYPE_GENERAL2 FIELD_PREP(GENMASK(23, 16), 0x10) + /* GZVM ioctls */ #define GZVM_IOC_MAGIC 0x92 /* gz */ =20 @@ -51,6 +75,11 @@ struct gzvm_memory_region { =20 #define GZVM_SET_MEMORY_REGION _IOW(GZVM_IOC_MAGIC, 0x40, \ struct gzvm_memory_region) +/* + * GZVM_CREATE_VCPU receives as a parameter the vcpu slot, + * and returns a vcpu fd. + */ +#define GZVM_CREATE_VCPU _IO(GZVM_IOC_MAGIC, 0x41) =20 /** * struct gzvm_userspace_memory_region: gzvm userspace memory region descr= iptor @@ -71,6 +100,127 @@ struct gzvm_userspace_memory_region { #define GZVM_SET_USER_MEMORY_REGION _IOW(GZVM_IOC_MAGIC, 0x46, \ struct gzvm_userspace_memory_region) =20 +/* + * ioctls for vcpu fds + */ +#define GZVM_RUN _IO(GZVM_IOC_MAGIC, 0x80) + +/* VM exit reason */ +enum { + GZVM_EXIT_UNKNOWN =3D 0x92920000, + GZVM_EXIT_MMIO =3D 0x92920001, + GZVM_EXIT_HYPERCALL =3D 0x92920002, + GZVM_EXIT_IRQ =3D 0x92920003, + GZVM_EXIT_EXCEPTION =3D 0x92920004, + GZVM_EXIT_DEBUG =3D 0x92920005, + GZVM_EXIT_FAIL_ENTRY =3D 0x92920006, + GZVM_EXIT_INTERNAL_ERROR =3D 0x92920007, + GZVM_EXIT_SYSTEM_EVENT =3D 0x92920008, + GZVM_EXIT_SHUTDOWN =3D 0x92920009, + GZVM_EXIT_GZ =3D 0x9292000a, +}; + +/** + * struct gzvm_vcpu_run: Same purpose as kvm_run, this struct is + * shared between userspace, kernel and + * GenieZone hypervisor + * @exit_reason: The reason why gzvm_vcpu_run has stopped running the vCPU + * @immediate_exit: Polled when the vcpu is scheduled. + * If set, immediately returns -EINTR + * @padding1: Reserved for future-proof and must be zero filled + * @mmio: The nested struct in anonymous union. Handle mmio in host side + * @fail_entry: The nested struct in anonymous union. + * Handle invalid entry address at the first run + * @exception: The nested struct in anonymous union. + * Handle exception occurred in VM + * @hypercall: The nested struct in anonymous union. + * Some hypercalls issued from VM must be handled + * @internal: The nested struct in anonymous union. The errors from hyperv= isor + * @system_event: The nested struct in anonymous union. + * VM's PSCI must be handled by host + * @padding: Fix it to a reasonable size future-proof for keeping the same + * struct size when adding new variables in the union is needed + * + * Keep identical layout between the 3 modules + */ +struct gzvm_vcpu_run { + /* to userspace */ + __u32 exit_reason; + __u8 immediate_exit; + __u8 padding1[3]; + /* union structure of collection of guest exit reason */ + union { + /* GZVM_EXIT_MMIO */ + struct { + /* From FAR_EL2 */ + /* The address guest tries to access */ + __u64 phys_addr; + /* The value to be written (is_write is 1) or + * be filled by user for reads (is_write is 0) + */ + __u8 data[8]; + /* From ESR_EL2 as */ + /* The size of written data. + * Only the first `size` bytes of `data` are handled + */ + __u64 size; + /* From ESR_EL2 */ + /* The register number where the data is stored */ + __u32 reg_nr; + /* From ESR_EL2 */ + /* 1 for VM to perform a write or 0 for VM to perform a read */ + __u8 is_write; + } mmio; + /* GZVM_EXIT_FAIL_ENTRY */ + struct { + /* The reason codes about hardware entry failure */ + __u64 hardware_entry_failure_reason; + /* The current processor number via smp_processor_id() */ + __u32 cpu; + } fail_entry; + /* GZVM_EXIT_EXCEPTION */ + struct { + /* Which exception vector */ + __u32 exception; + /* Exception error codes */ + __u32 error_code; + } exception; + /* GZVM_EXIT_HYPERCALL */ + struct { + /* The hypercall's arguments */ + __u64 args[8]; /* in-out */ + } hypercall; + /* GZVM_EXIT_INTERNAL_ERROR */ + struct { + /* The errors codes about GZVM_EXIT_INTERNAL_ERROR */ + __u32 suberror; + /* The number of elements used in data[] */ + __u32 ndata; + /* Keep the detailed information about GZVM_EXIT_SYSTEM_EVENT */ + __u64 data[16]; + } internal; + /* GZVM_EXIT_SYSTEM_EVENT */ + struct { +#define GZVM_SYSTEM_EVENT_SHUTDOWN 1 +#define GZVM_SYSTEM_EVENT_RESET 2 +#define GZVM_SYSTEM_EVENT_CRASH 3 +#define GZVM_SYSTEM_EVENT_WAKEUP 4 +#define GZVM_SYSTEM_EVENT_SUSPEND 5 +#define GZVM_SYSTEM_EVENT_SEV_TERM 6 +#define GZVM_SYSTEM_EVENT_S2IDLE 7 + /* System event type. + * Ex. GZVM_SYSTEM_EVENT_SHUTDOWN or GZVM_SYSTEM_EVENT_RESET...etc. + */ + __u32 type; + /* The number of elements used in data[] */ + __u32 ndata; + /* Keep the detailed information about GZVM_EXIT_SYSTEM_EVENT */ + __u64 data[16]; + } system_event; + char padding[256]; + }; +}; + /** * struct gzvm_enable_cap: The `capability support` on GenieZone hypervisor * @cap: `GZVM_CAP_ARM_PROTECTED_VM` or `GZVM_CAP_ARM_VM_IPA_SIZE` @@ -84,4 +234,17 @@ struct gzvm_enable_cap { #define GZVM_ENABLE_CAP _IOW(GZVM_IOC_MAGIC, 0xa3, \ struct gzvm_enable_cap) =20 +/* for GZVM_GET/SET_ONE_REG */ +struct gzvm_one_reg { + __u64 id; + __u64 addr; +}; + +#define GZVM_GET_ONE_REG _IOW(GZVM_IOC_MAGIC, 0xab, \ + struct gzvm_one_reg) +#define GZVM_SET_ONE_REG _IOW(GZVM_IOC_MAGIC, 0xac, \ + struct gzvm_one_reg) + +#define GZVM_REG_GENERIC 0x0000000000000000ULL + #endif /* __GZVM_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B7E081F76B6; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; cv=none; b=EvvV5i4n1fOGjLc2wJumykH8gS2JTpw5Sg0vxLbksgmpH3TaQrPYInfmIjjsiAAJ72aT+vFZspIbna2Rq41YwCp1KB5up/+rpJSI/McK7egV9C8HluTnDeWtRKnKqsCpwts12yU8nYsGK8HIRDSw16dl837Ntc7OHkeCxp+X6ts= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; c=relaxed/simple; bh=YarfZ4sOnnWTmMQv0HfTNuzZIk5rcamFTNFdrSaMajU=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aQlxdfOASfK+7ywYPJh31J96KrHZl2EpM4NpMixtFnsPcnEOkfaM7zNyn083wHENuPc05i9PDhXsv29wd7X7V/MUJRC0X7YOxYCIQ9Lzag8iMmXAJV1o6r2LWHSe92V3XiPlqj1wQkD1vrvH8Hxpjb7HAyy5QLUm6rffzB93JiI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=eylohGuy; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="eylohGuy" X-UUID: 57530a2ea27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=pJS6jnLzDPuhO5FmDgJiG8r9VIieur4cdT5W4MFUj5c=; b=eylohGuyqV0O24VkSKnj76VMkFi2IiYhsG3YzNaGI3RNLZ+0AaRGv8rwQzRg9oqpONzmrBHqBqm0LSNWmg3/1u94mp543E3YypcuLMZN3mbz9yg/XD1R61CfDeX5EaOGlRWNwg6wEQ1S1ZEWuYTn6UmcFAWGT9a1FifT0ewPXdY=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:c9af3b4a-29f9-4de3-9e68-79507eca5f14,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:e76b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 57530a2ea27011ef99858b75a2457dd9-20241114 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 470650385; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n2.mediatek.inc (172.21.101.108) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:04 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 09/25] virt: geniezone: Add irqchip support for virtual interrupt injection Date: Thu, 14 Nov 2024 18:07:46 +0800 Message-ID: <20241114100802.4116-10-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan Enable GenieZone to handle virtual interrupt injection request. Signed-off-by: Yingshiuan Pan Co-developed-by: Kevenny Hsieh Signed-off-by: Kevenny Hsieh Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/Makefile | 2 +- arch/arm64/geniezone/gzvm_arch_common.h | 4 ++ arch/arm64/geniezone/vgic.c | 50 +++++++++++++++ drivers/virt/geniezone/gzvm_common.h | 12 ++++ drivers/virt/geniezone/gzvm_vm.c | 81 +++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 4 ++ include/uapi/linux/gzvm.h | 66 ++++++++++++++++++++ 7 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/geniezone/vgic.c create mode 100644 drivers/virt/geniezone/gzvm_common.h diff --git a/arch/arm64/geniezone/Makefile b/arch/arm64/geniezone/Makefile index 69b0a4abeab0..0e4f1087f9de 100644 --- a/arch/arm64/geniezone/Makefile +++ b/arch/arm64/geniezone/Makefile @@ -4,6 +4,6 @@ # include $(srctree)/drivers/virt/geniezone/Makefile =20 -gzvm-y +=3D vm.o vcpu.o +gzvm-y +=3D vm.o vcpu.o vgic.o =20 obj-$(CONFIG_MTK_GZVM) +=3D gzvm.o diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 3ec7bea5651f..eb7a0b7ded8c 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -17,6 +17,8 @@ enum { GZVM_FUNC_RUN =3D 5, GZVM_FUNC_GET_ONE_REG =3D 8, GZVM_FUNC_SET_ONE_REG =3D 9, + GZVM_FUNC_IRQ_LINE =3D 10, + GZVM_FUNC_CREATE_DEVICE =3D 11, GZVM_FUNC_PROBE =3D 12, GZVM_FUNC_ENABLE_CAP =3D 13, GZVM_FUNC_INFORM_EXIT =3D 14, @@ -37,6 +39,8 @@ enum { #define MT_HVC_GZVM_RUN GZVM_HCALL_ID(GZVM_FUNC_RUN) #define MT_HVC_GZVM_GET_ONE_REG GZVM_HCALL_ID(GZVM_FUNC_GET_ONE_REG) #define MT_HVC_GZVM_SET_ONE_REG GZVM_HCALL_ID(GZVM_FUNC_SET_ONE_REG) +#define MT_HVC_GZVM_IRQ_LINE GZVM_HCALL_ID(GZVM_FUNC_IRQ_LINE) +#define MT_HVC_GZVM_CREATE_DEVICE GZVM_HCALL_ID(GZVM_FUNC_CREATE_DEVICE) #define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) #define MT_HVC_GZVM_ENABLE_CAP GZVM_HCALL_ID(GZVM_FUNC_ENABLE_CAP) #define MT_HVC_GZVM_INFORM_EXIT GZVM_HCALL_ID(GZVM_FUNC_INFORM_EXIT) diff --git a/arch/arm64/geniezone/vgic.c b/arch/arm64/geniezone/vgic.c new file mode 100644 index 000000000000..084efe845e41 --- /dev/null +++ b/arch/arm64/geniezone/vgic.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include +#include "gzvm_arch_common.h" + +int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_CREATE_DEVICE, vm_id, + virt_to_phys(gzvm_dev), 0, 0, 0, 0, 0, + &res); +} + +/** + * gzvm_arch_inject_irq() - Inject virtual interrupt to a VM + * @gzvm: Pointer to struct gzvm + * @vcpu_idx: vcpu index, only valid if PPI + * @irq: *SPI* irq number (excluding offset value `32`) + * @level: 1 if true else 0 + * + * Return: + * * 0 - Success. + * * Negative - Failure. + */ +int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, + u32 irq, bool level) +{ + unsigned long a1 =3D assemble_vm_vcpu_tuple(gzvm->vm_id, vcpu_idx); + struct arm_smccc_res res; + + /* + * VMM's virtual device irq number starts from 0, but ARM's shared periph= eral + * interrupt number starts from 32. hypervisor adds offset 32 + */ + gzvm_hypcall_wrapper(MT_HVC_GZVM_IRQ_LINE, a1, irq, level, + 0, 0, 0, 0, &res); + if (res.a0) { + pr_err("Failed to set IRQ level (%d) to irq#%u on vcpu %d with ret=3D%d\= n", + level, irq, vcpu_idx, (int)res.a0); + return -EFAULT; + } + + return 0; +} diff --git a/drivers/virt/geniezone/gzvm_common.h b/drivers/virt/geniezone/= gzvm_common.h new file mode 100644 index 000000000000..c8d90fee3a18 --- /dev/null +++ b/drivers/virt/geniezone/gzvm_common.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#ifndef __GZ_COMMON_H__ +#define __GZ_COMMON_H__ + +int gzvm_irqchip_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, + u32 irq, bool level); + +#endif /* __GZVM_COMMON_H__ */ diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index f6b069dc53fc..16e757303fbd 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -11,6 +11,7 @@ #include #include #include +#include "gzvm_common.h" =20 static DEFINE_MUTEX(gzvm_list_lock); static LIST_HEAD(gzvm_list); @@ -130,6 +131,72 @@ gzvm_vm_ioctl_set_memory_region(struct gzvm *gzvm, return register_memslot_addr_range(gzvm, memslot); } =20 +int gzvm_irqchip_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, + u32 irq, bool level) +{ + return gzvm_arch_inject_irq(gzvm, vcpu_idx, irq, level); +} + +static int gzvm_vm_ioctl_irq_line(struct gzvm *gzvm, + struct gzvm_irq_level *irq_level) +{ + u32 irq =3D irq_level->irq; + u32 vcpu_idx, vcpu2_idx, irq_num; + bool level =3D irq_level->level; + + vcpu_idx =3D FIELD_GET(GZVM_IRQ_LINE_VCPU, irq); + vcpu2_idx =3D FIELD_GET(GZVM_IRQ_LINE_VCPU2, irq) * (GZVM_IRQ_VCPU_MASK += 1); + irq_num =3D FIELD_GET(GZVM_IRQ_LINE_NUM, irq); + + return gzvm_irqchip_inject_irq(gzvm, vcpu_idx + vcpu2_idx, irq_num, + level); +} + +static int gzvm_vm_ioctl_create_device(struct gzvm *gzvm, void __user *arg= p) +{ + struct gzvm_create_device *gzvm_dev; + void *dev_data =3D NULL; + int ret; + + gzvm_dev =3D (struct gzvm_create_device *)alloc_pages_exact(PAGE_SIZE, + GFP_KERNEL); + if (!gzvm_dev) + return -ENOMEM; + if (copy_from_user(gzvm_dev, argp, sizeof(*gzvm_dev))) { + ret =3D -EFAULT; + goto err_free_dev; + } + + if (gzvm_dev->attr_addr !=3D 0 && gzvm_dev->attr_size !=3D 0) { + size_t attr_size =3D gzvm_dev->attr_size; + void __user *attr_addr =3D u64_to_user_ptr(gzvm_dev->attr_addr); + + /* Size of device specific data should not be over a page. */ + if (attr_size > PAGE_SIZE) + return -EINVAL; + + dev_data =3D alloc_pages_exact(attr_size, GFP_KERNEL); + if (!dev_data) { + ret =3D -ENOMEM; + goto err_free_dev; + } + + if (copy_from_user(dev_data, attr_addr, attr_size)) { + ret =3D -EFAULT; + goto err_free_dev_data; + } + gzvm_dev->attr_addr =3D virt_to_phys(dev_data); + } + + ret =3D gzvm_arch_create_device(gzvm->vm_id, gzvm_dev); +err_free_dev_data: + if (dev_data) + free_pages_exact(dev_data, 0); +err_free_dev: + free_pages_exact(gzvm_dev, 0); + return ret; +} + static int gzvm_vm_ioctl_enable_cap(struct gzvm *gzvm, struct gzvm_enable_cap *cap, void __user *argp) @@ -163,6 +230,20 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned = int ioctl, ret =3D gzvm_vm_ioctl_set_memory_region(gzvm, &userspace_mem); break; } + case GZVM_IRQ_LINE: { + struct gzvm_irq_level irq_event; + + if (copy_from_user(&irq_event, argp, sizeof(irq_event))) { + ret =3D -EFAULT; + goto out; + } + ret =3D gzvm_vm_ioctl_irq_line(gzvm, &irq_event); + break; + } + case GZVM_CREATE_DEVICE: { + ret =3D gzvm_vm_ioctl_create_device(gzvm, argp); + break; + } case GZVM_ENABLE_CAP: { struct gzvm_enable_cap cap; =20 diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index ef02df39192d..d5b81ceb520d 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -161,4 +161,8 @@ int gzvm_arch_vcpu_run(struct gzvm_vcpu *vcpu, __u64 *e= xit_reason); int gzvm_arch_destroy_vcpu(u16 vm_id, int vcpuid); int gzvm_arch_inform_exit(u16 vm_id); =20 +int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev= ); +int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, + u32 irq, bool level); + #endif /* __GZVM_DRV_H__ */ diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 1146467487ca..03fd0735fb80 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -100,6 +100,72 @@ struct gzvm_userspace_memory_region { #define GZVM_SET_USER_MEMORY_REGION _IOW(GZVM_IOC_MAGIC, 0x46, \ struct gzvm_userspace_memory_region) =20 +/* for GZVM_IRQ_LINE, irq field index values */ +#define GZVM_IRQ_VCPU_MASK 0xff +#define GZVM_IRQ_LINE_TYPE GENMASK(27, 24) +#define GZVM_IRQ_LINE_VCPU GENMASK(23, 16) +#define GZVM_IRQ_LINE_VCPU2 GENMASK(31, 28) +#define GZVM_IRQ_LINE_NUM GENMASK(15, 0) + +/* irq_type field */ +#define GZVM_IRQ_TYPE_CPU 0 +#define GZVM_IRQ_TYPE_SPI 1 +#define GZVM_IRQ_TYPE_PPI 2 + +/* out-of-kernel GIC cpu interrupt injection irq_number field */ +#define GZVM_IRQ_CPU_IRQ 0 +#define GZVM_IRQ_CPU_FIQ 1 + +struct gzvm_irq_level { + union { + __u32 irq; + __s32 status; + }; + __u32 level; +}; + +#define GZVM_IRQ_LINE _IOW(GZVM_IOC_MAGIC, 0x61, \ + struct gzvm_irq_level) + +enum gzvm_device_type { + GZVM_DEV_TYPE_ARM_VGIC_V3_DIST =3D 0, + GZVM_DEV_TYPE_ARM_VGIC_V3_REDIST =3D 1, + GZVM_DEV_TYPE_MAX, +}; + +/** + * struct gzvm_create_device: For GZVM_CREATE_DEVICE. + * @dev_type: Device type. + * @id: Device id. + * @flags: Bypass to hypervisor to handle them and these are flags of virt= ual + * devices. + * @dev_addr: Device ipa address in VM's view. + * @dev_reg_size: Device register range size. + * @attr_addr: If user -> kernel, this is user virtual address of device + * specific attributes (if needed). If kernel->hypervisor, + * this is ipa. + * @attr_size: This attr_size is the buffer size in bytes of each attribute + * needed from various devices. The attribute here refers to t= he + * additional data passed from VMM(e.g. Crosvm) to GenieZone + * hypervisor when virtual devices were to be created. Thus, + * we need attr_addr and attr_size in the gzvm_create_device + * structure to keep track of the attribute mentioned. + * + * Store information needed to create device. + */ +struct gzvm_create_device { + __u32 dev_type; + __u32 id; + __u64 flags; + __u64 dev_addr; + __u64 dev_reg_size; + __u64 attr_addr; + __u64 attr_size; +}; + +#define GZVM_CREATE_DEVICE _IOWR(GZVM_IOC_MAGIC, 0xe0, \ + struct gzvm_create_device) + /* * ioctls for vcpu fds */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF9C91F890A; Thu, 14 Nov 2024 10:08:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578903; cv=none; b=sr3G7k3woh81K3ppwgONIKRHiwGvmc76h2eQGXWLAtA/i3ew8t7La69aDNRKNZpH66FB7eQ9VFwU7owH5Da4GOJDiSW9/Ry/vU0HWpy6iW2EcndVUyjmSptFn8bWUHLKLSRT/Lx4Er3XzK2P74Zsxrc3D914bBFz0S1iiVTS8A4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578903; c=relaxed/simple; bh=5KCV/7/vhXl5YjXFwYBNofKw5VwCtGdw72uQmLO9pxY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NflAphBuQUzHPzETZzWxlqY48vMvTJx6v47CW+1SyGmTL7IPkRv+lPR35iafkWss29f6itdNWmBo1+EkuRk/PaxS54iWccb9D8VN75MoU8D7Xki2m9CLOCmMcR8NTUK7GhU1Z2ogBlFZQAuUXEaU+lxZL9I+zn1lY95pYEid7LY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=guiTSCyL; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="guiTSCyL" X-UUID: 576bdd1aa27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=sPxS2LMpGUEH4wS2jMTeT6CwdPHlACKUrLz/KAsU1EA=; b=guiTSCyLsR15xx+vIjxmLBnZF7WPfM1b2SJjqigi0Z0U2zv/He0aVNqBFoX53JZfnp2bzUdXz0lx8IGs2/R9dozCViwZRrqhQ3oHJO+LS0m1yWF4nmoNWLOoKdKLFcQm/W74jnGgcdbnl9Bz2aLSj+g+MT2/kVgof6Ns2KrQltI=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:8926aa69-f231-47bf-b344-f88e49e5fee2,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:473fa25c-f18b-4d56-b49c-93279ee09144,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 576bdd1aa27011ef99858b75a2457dd9-20241114 Received: from mtkmbs09n1.mediatek.inc [(172.21.101.35)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1621546838; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 02:08:04 -0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:04 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 10/25] virt: geniezone: Add irqfd support Date: Thu, 14 Nov 2024 18:07:47 +0800 Message-ID: <20241114100802.4116-11-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan irqfd enables other threads than vcpu threads to inject virtual interrupt through irqfd asynchronously rather through ioctl interface. This interface is necessary for VMM which creates separated thread for IO handling or uses vhost devices. Signed-off-by: Yingshiuan Pan Co-developed-by: Kevenny Hsieh Signed-off-by: Kevenny Hsieh Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 18 ++ drivers/virt/geniezone/Makefile | 2 +- drivers/virt/geniezone/gzvm_irqfd.c | 382 ++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_main.c | 12 +- drivers/virt/geniezone/gzvm_vcpu.c | 1 + drivers/virt/geniezone/gzvm_vm.c | 18 ++ include/linux/soc/mediatek/gzvm_drv.h | 26 ++ include/uapi/linux/gzvm.h | 26 ++ 8 files changed, 483 insertions(+), 2 deletions(-) create mode 100644 drivers/virt/geniezone/gzvm_irqfd.c diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index eb7a0b7ded8c..d4b49a4b283a 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -45,6 +45,8 @@ enum { #define MT_HVC_GZVM_ENABLE_CAP GZVM_HCALL_ID(GZVM_FUNC_ENABLE_CAP) #define MT_HVC_GZVM_INFORM_EXIT GZVM_HCALL_ID(GZVM_FUNC_INFORM_EXIT) =20 +#define GIC_V3_NR_LRS 16 + /** * gzvm_hypcall_wrapper() - the wrapper for hvc calls * @a0: argument passed in registers 0 @@ -65,6 +67,22 @@ int gzvm_hypcall_wrapper(unsigned long a0, unsigned long= a1, unsigned long a6, unsigned long a7, struct arm_smccc_res *res); =20 +/** + * struct gzvm_vcpu_hwstate: Sync architecture state back to host for hand= ling + * @nr_lrs: The available LRs(list registers) in Soc. + * @__pad: add an explicit '__u32 __pad;' in the middle to make it clear + * what the actual layout is. + * @lr: The array of LRs(list registers). + * + * - Keep the same layout of hypervisor data struct. + * - Sync list registers back for acking virtual device interrupt status. + */ +struct gzvm_vcpu_hwstate { + __le32 nr_lrs; + __le32 __pad; + __le64 lr[GIC_V3_NR_LRS]; +}; + static inline unsigned int assemble_vm_vcpu_tuple(u16 vmid, u16 vcpuid) { diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makef= ile index 9cc453c0819b..19a835b0aac2 100644 --- a/drivers/virt/geniezone/Makefile +++ b/drivers/virt/geniezone/Makefile @@ -7,4 +7,4 @@ GZVM_DIR ?=3D ../../../drivers/virt/geniezone =20 gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o \ - $(GZVM_DIR)/gzvm_vcpu.o + $(GZVM_DIR)/gzvm_vcpu.o $(GZVM_DIR)/gzvm_irqfd.o diff --git a/drivers/virt/geniezone/gzvm_irqfd.c b/drivers/virt/geniezone/g= zvm_irqfd.c new file mode 100644 index 000000000000..7d9470287d39 --- /dev/null +++ b/drivers/virt/geniezone/gzvm_irqfd.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include +#include "gzvm_common.h" + +struct gzvm_irq_ack_notifier { + struct hlist_node link; + unsigned int gsi; + void (*irq_acked)(struct gzvm_irq_ack_notifier *ian); +}; + +/** + * struct gzvm_kernel_irqfd: gzvm kernel irqfd descriptor. + * @gzvm: Pointer to struct gzvm. + * @wait: Wait queue entry. + * @gsi: Used for level IRQ fast-path. + * @eventfd: Used for setup/shutdown. + * @list: struct list_head. + * @pt: struct poll_table_struct. + * @shutdown: struct work_struct. + */ +struct gzvm_kernel_irqfd { + struct gzvm *gzvm; + wait_queue_entry_t wait; + + int gsi; + + struct eventfd_ctx *eventfd; + struct list_head list; + poll_table pt; + struct work_struct shutdown; +}; + +static struct workqueue_struct *irqfd_cleanup_wq; + +/** + * irqfd_set_irq(): irqfd to inject virtual interrupt. + * @gzvm: Pointer to gzvm. + * @irq: This is spi interrupt number (starts from 0 instead of 32). + * @level: irq triggered level. + */ +static void irqfd_set_irq(struct gzvm *gzvm, u32 irq, int level) +{ + if (level) + gzvm_irqchip_inject_irq(gzvm, 0, irq, level); +} + +/** + * irqfd_shutdown() - Race-free decouple logic (ordering is critical). + * @work: Pointer to work_struct. + */ +static void irqfd_shutdown(struct work_struct *work) +{ + struct gzvm_kernel_irqfd *irqfd =3D + container_of(work, struct gzvm_kernel_irqfd, shutdown); + struct gzvm *gzvm =3D irqfd->gzvm; + u64 cnt; + + /* Make sure irqfd has been initialized in assign path. */ + synchronize_srcu(&gzvm->irq_srcu); + + /* + * Synchronize with the wait-queue and unhook ourselves to prevent + * further events. + */ + eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt); + + /* + * It is now safe to release the object's resources + */ + eventfd_ctx_put(irqfd->eventfd); + kfree(irqfd); +} + +/** + * irqfd_is_active() - Assumes gzvm->irqfds.lock is held. + * @irqfd: Pointer to gzvm_kernel_irqfd. + * + * Return: + * * true - irqfd is active. + */ +static bool irqfd_is_active(struct gzvm_kernel_irqfd *irqfd) +{ + return list_empty(&irqfd->list) ? false : true; +} + +/** + * irqfd_deactivate() - Mark the irqfd as inactive and schedule it for rem= oval. + * assumes gzvm->irqfds.lock is held. + * @irqfd: Pointer to gzvm_kernel_irqfd. + */ +static void irqfd_deactivate(struct gzvm_kernel_irqfd *irqfd) +{ + if (!irqfd_is_active(irqfd)) + return; + + list_del_init(&irqfd->list); + + queue_work(irqfd_cleanup_wq, &irqfd->shutdown); +} + +/** + * irqfd_wakeup() - Callback of irqfd wait queue, would be woken by writin= g to + * irqfd to do virtual interrupt injection. + * @wait: Pointer to wait_queue_entry_t. + * @mode: Unused. + * @sync: Unused. + * @key: Get flags about Epoll events. + * + * Return: + * * 0 - Success + */ +static int irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode, int s= ync, + void *key) +{ + struct gzvm_kernel_irqfd *irqfd =3D + container_of(wait, struct gzvm_kernel_irqfd, wait); + __poll_t flags =3D key_to_poll(key); + struct gzvm *gzvm =3D irqfd->gzvm; + + if (flags & EPOLLIN) { + u64 cnt; + + eventfd_ctx_do_read(irqfd->eventfd, &cnt); + /* gzvm's irq injection is not blocked, don't need workq */ + irqfd_set_irq(gzvm, irqfd->gsi, 1); + } + + if (flags & EPOLLHUP) { + /* The eventfd is closing, detach from GZVM */ + unsigned long iflags; + + spin_lock_irqsave(&gzvm->irqfds.lock, iflags); + + /* + * Do more check if someone deactivated the irqfd before + * we could acquire the irqfds.lock. + */ + if (irqfd_is_active(irqfd)) + irqfd_deactivate(irqfd); + + spin_unlock_irqrestore(&gzvm->irqfds.lock, iflags); + } + + return 0; +} + +static void irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *= wqh, + poll_table *pt) +{ + struct gzvm_kernel_irqfd *irqfd =3D + container_of(pt, struct gzvm_kernel_irqfd, pt); + add_wait_queue_priority(wqh, &irqfd->wait); +} + +static int gzvm_irqfd_assign(struct gzvm *gzvm, struct gzvm_irqfd *args) +{ + struct gzvm_kernel_irqfd *irqfd, *tmp; + struct fd f; + struct eventfd_ctx *eventfd =3D NULL; + int ret; + int idx; + + irqfd =3D kzalloc(sizeof(*irqfd), GFP_KERNEL_ACCOUNT); + if (!irqfd) + return -ENOMEM; + + irqfd->gzvm =3D gzvm; + irqfd->gsi =3D args->gsi; + + INIT_LIST_HEAD(&irqfd->list); + INIT_WORK(&irqfd->shutdown, irqfd_shutdown); + + f =3D fdget(args->fd); + if (fd_empty(f)) { + ret =3D -EBADF; + goto out; + } + + eventfd =3D eventfd_ctx_fileget(fd_file(f)); + if (IS_ERR(eventfd)) { + ret =3D PTR_ERR(eventfd); + goto fail; + } + + irqfd->eventfd =3D eventfd; + + /* + * Install our own custom wake-up handling so we are notified via + * a callback whenever someone signals the underlying eventfd + */ + init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup); + init_poll_funcptr(&irqfd->pt, irqfd_ptable_queue_proc); + + spin_lock_irq(&gzvm->irqfds.lock); + + ret =3D 0; + list_for_each_entry(tmp, &gzvm->irqfds.items, list) { + if (irqfd->eventfd !=3D tmp->eventfd) + continue; + /* This fd is used for another irq already. */ + pr_err("already used: gsi=3D%d fd=3D%d\n", args->gsi, args->fd); + ret =3D -EBUSY; + spin_unlock_irq(&gzvm->irqfds.lock); + goto fail; + } + + idx =3D srcu_read_lock(&gzvm->irq_srcu); + + list_add_tail(&irqfd->list, &gzvm->irqfds.items); + + spin_unlock_irq(&gzvm->irqfds.lock); + + vfs_poll(fd_file(f), &irqfd->pt); + + srcu_read_unlock(&gzvm->irq_srcu, idx); + + /* + * do not drop the file until the irqfd is fully initialized, otherwise + * we might race against the EPOLLHUP + */ + fdput(f); + return 0; + +fail: + if (eventfd && !IS_ERR(eventfd)) + eventfd_ctx_put(eventfd); + + fdput(f); + +out: + kfree(irqfd); + return ret; +} + +static void gzvm_notify_acked_gsi(struct gzvm *gzvm, int gsi) +{ + struct gzvm_irq_ack_notifier *gian; + + hlist_for_each_entry_srcu(gian, &gzvm->irq_ack_notifier_list, + link, srcu_read_lock_held(&gzvm->irq_srcu)) + if (gian->gsi =3D=3D gsi) + gian->irq_acked(gian); +} + +void gzvm_notify_acked_irq(struct gzvm *gzvm, unsigned int gsi) +{ + int idx; + + idx =3D srcu_read_lock(&gzvm->irq_srcu); + gzvm_notify_acked_gsi(gzvm, gsi); + srcu_read_unlock(&gzvm->irq_srcu, idx); +} + +/** + * gzvm_irqfd_deassign() - Shutdown any irqfd's that match fd+gsi. + * @gzvm: Pointer to gzvm. + * @args: Pointer to gzvm_irqfd. + * + * Return: + * * 0 - Success. + * * Negative value - Failure. + */ +static int gzvm_irqfd_deassign(struct gzvm *gzvm, struct gzvm_irqfd *args) +{ + struct gzvm_kernel_irqfd *irqfd, *tmp; + struct eventfd_ctx *eventfd; + + eventfd =3D eventfd_ctx_fdget(args->fd); + if (IS_ERR(eventfd)) + return PTR_ERR(eventfd); + + spin_lock_irq(&gzvm->irqfds.lock); + + list_for_each_entry_safe(irqfd, tmp, &gzvm->irqfds.items, list) { + if (irqfd->eventfd =3D=3D eventfd && irqfd->gsi =3D=3D args->gsi) + irqfd_deactivate(irqfd); + } + + spin_unlock_irq(&gzvm->irqfds.lock); + eventfd_ctx_put(eventfd); + + /* + * Block until we know all outstanding shutdown jobs have completed + * so that we guarantee there will not be any more interrupts on this + * gsi once this deassign function returns. + */ + flush_workqueue(irqfd_cleanup_wq); + + return 0; +} + +int gzvm_irqfd(struct gzvm *gzvm, struct gzvm_irqfd *args) +{ + for (int i =3D 0; i < ARRAY_SIZE(args->pad); i++) { + if (args->pad[i]) + return -EINVAL; + } + + if (args->flags & + ~(GZVM_IRQFD_FLAG_DEASSIGN | GZVM_IRQFD_FLAG_RESAMPLE)) + return -EINVAL; + + if (args->flags & GZVM_IRQFD_FLAG_DEASSIGN) + return gzvm_irqfd_deassign(gzvm, args); + + return gzvm_irqfd_assign(gzvm, args); +} + +/** + * gzvm_vm_irqfd_init() - Initialize irqfd data structure per VM + * + * @gzvm: Pointer to struct gzvm. + * + * Return: + * * 0 - Success. + * * Negative - Failure. + */ +int gzvm_vm_irqfd_init(struct gzvm *gzvm) +{ + mutex_init(&gzvm->irq_lock); + + spin_lock_init(&gzvm->irqfds.lock); + INIT_LIST_HEAD(&gzvm->irqfds.items); + if (init_srcu_struct(&gzvm->irq_srcu)) + return -EINVAL; + INIT_HLIST_HEAD(&gzvm->irq_ack_notifier_list); + + return 0; +} + +/** + * gzvm_vm_irqfd_release() - This function is called as the gzvm VM fd is = being + * released. Shutdown all irqfds that still remain open. + * @gzvm: Pointer to gzvm. + */ +void gzvm_vm_irqfd_release(struct gzvm *gzvm) +{ + struct gzvm_kernel_irqfd *irqfd, *tmp; + + spin_lock_irq(&gzvm->irqfds.lock); + + list_for_each_entry_safe(irqfd, tmp, &gzvm->irqfds.items, list) + irqfd_deactivate(irqfd); + + spin_unlock_irq(&gzvm->irqfds.lock); + + /* + * Block until we know all outstanding shutdown jobs have completed. + */ + flush_workqueue(irqfd_cleanup_wq); +} + +/** + * gzvm_drv_irqfd_init() - Erase flushing work items when a VM exits. + * + * Return: + * * 0 - Success. + * * Negative - Failure. + * + * Create a host-wide workqueue for issuing deferred shutdown requests + * aggregated from all vm* instances. We need our own isolated + * queue to ease flushing work items when a VM exits. + */ +int gzvm_drv_irqfd_init(void) +{ + irqfd_cleanup_wq =3D alloc_workqueue("gzvm-irqfd-cleanup", 0, 0); + if (!irqfd_cleanup_wq) + return -ENOMEM; + + return 0; +} + +void gzvm_drv_irqfd_exit(void) +{ + destroy_workqueue(irqfd_cleanup_wq); +} diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index db1076c9a4da..60348b88cd24 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -119,6 +119,8 @@ static struct miscdevice gzvm_dev =3D { =20 static int gzvm_drv_probe(struct platform_device *pdev) { + int ret; + if (gzvm_arch_probe(gzvm_drv.drv_version, &gzvm_drv.hyp_version) !=3D 0) { dev_err(&pdev->dev, "Not found available conduit\n"); return -ENODEV; @@ -128,11 +130,19 @@ static int gzvm_drv_probe(struct platform_device *pde= v) gzvm_drv.hyp_version.major, gzvm_drv.hyp_version.minor, gzvm_drv.hyp_version.sub); =20 - return misc_register(&gzvm_dev); + ret =3D misc_register(&gzvm_dev); + if (ret) + return ret; + + ret =3D gzvm_drv_irqfd_init(); + if (ret) + return ret; + return 0; } =20 static void gzvm_drv_remove(struct platform_device *pdev) { + gzvm_drv_irqfd_exit(); misc_deregister(&gzvm_dev); } =20 diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index c8a4e0f2f027..7e1e16d0f3a1 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -225,6 +225,7 @@ int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cp= uid) ret =3D -ENOMEM; goto free_vcpu; } + vcpu->hwstate =3D (void *)vcpu->run + PAGE_SIZE; vcpu->vcpuid =3D cpuid; vcpu->gzvm =3D gzvm; mutex_init(&vcpu->lock); diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 16e757303fbd..df1d666d5bcb 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -244,6 +244,16 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned = int ioctl, ret =3D gzvm_vm_ioctl_create_device(gzvm, argp); break; } + case GZVM_IRQFD: { + struct gzvm_irqfd data; + + if (copy_from_user(&data, argp, sizeof(data))) { + ret =3D -EFAULT; + goto out; + } + ret =3D gzvm_irqfd(gzvm, &data); + break; + } case GZVM_ENABLE_CAP: { struct gzvm_enable_cap cap; =20 @@ -267,6 +277,7 @@ static void gzvm_destroy_vm(struct gzvm *gzvm) =20 mutex_lock(&gzvm->lock); =20 + gzvm_vm_irqfd_release(gzvm); gzvm_destroy_vcpus(gzvm); gzvm_arch_destroy_vm(gzvm->vm_id); =20 @@ -312,6 +323,13 @@ static struct gzvm *gzvm_create_vm(struct gzvm_driver = *drv, unsigned long vm_typ gzvm->mm =3D current->mm; mutex_init(&gzvm->lock); =20 + ret =3D gzvm_vm_irqfd_init(gzvm); + if (ret) { + pr_err("Failed to initialize irqfd\n"); + kfree(gzvm); + return ERR_PTR(ret); + } + mutex_lock(&gzvm_list_lock); list_add(&gzvm->vm_list, &gzvm_list); mutex_unlock(&gzvm_list_lock); diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index d5b81ceb520d..c19035ff7975 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -10,6 +10,7 @@ #include #include #include +#include =20 /* GZVM version encode */ #define GZVM_DRV_MAJOR_VERSION 16 @@ -45,6 +46,7 @@ struct gzvm_driver { #define ERR_NOT_SUPPORTED (-24) #define ERR_NOT_IMPLEMENTED (-27) #define ERR_FAULT (-40) +#define GZVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 =20 /* * The following data structures are for data transferring between driver = and @@ -106,6 +108,7 @@ struct gzvm_vcpu { /* lock of vcpu*/ struct mutex lock; struct gzvm_vcpu_run *run; + struct gzvm_vcpu_hwstate *hwstate; }; =20 /** @@ -116,8 +119,12 @@ struct gzvm_vcpu { * @mm: userspace tied to this vm * @memslot: VM's memory slot descriptor * @lock: lock for list_add + * @irqfds: the data structure is used to keep irqfds's information * @vm_list: list head for vm list * @vm_id: vm id + * @irq_ack_notifier_list: list head for irq ack notifier + * @irq_srcu: structure data for SRCU(sleepable rcu) + * @irq_lock: lock for irq injection */ struct gzvm { struct gzvm_driver *gzvm_drv; @@ -125,8 +132,20 @@ struct gzvm { struct mm_struct *mm; struct gzvm_memslot memslot[GZVM_MAX_MEM_REGION]; struct mutex lock; + + struct { + spinlock_t lock; + struct list_head items; + struct list_head resampler_list; + struct mutex resampler_lock; + } irqfds; + struct list_head vm_list; u16 vm_id; + + struct hlist_head irq_ack_notifier_list; + struct srcu_struct irq_srcu; + struct mutex irq_lock; }; =20 long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args); @@ -165,4 +184,11 @@ int gzvm_arch_create_device(u16 vm_id, struct gzvm_cre= ate_device *gzvm_dev); int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, u32 irq, bool level); =20 +void gzvm_notify_acked_irq(struct gzvm *gzvm, unsigned int gsi); +int gzvm_irqfd(struct gzvm *gzvm, struct gzvm_irqfd *args); +int gzvm_drv_irqfd_init(void); +void gzvm_drv_irqfd_exit(void); +int gzvm_vm_irqfd_init(struct gzvm *gzvm); +void gzvm_vm_irqfd_release(struct gzvm *gzvm); + #endif /* __GZVM_DRV_H__ */ diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 03fd0735fb80..aa61ece00cac 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -313,4 +313,30 @@ struct gzvm_one_reg { =20 #define GZVM_REG_GENERIC 0x0000000000000000ULL =20 +#define GZVM_IRQFD_FLAG_DEASSIGN BIT(0) +/* + * GZVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies + * the irqfd to operate in resampling mode for level triggered interrupt + * emulation. + */ +#define GZVM_IRQFD_FLAG_RESAMPLE BIT(1) + +/** + * struct gzvm_irqfd: gzvm irqfd descriptor + * @fd: File descriptor. + * @gsi: Used for level IRQ fast-path. + * @flags: FLAG_DEASSIGN or FLAG_RESAMPLE. + * @resamplefd: The file descriptor of the resampler. + * @pad: Reserved for future-proof. + */ +struct gzvm_irqfd { + __u32 fd; + __u32 gsi; + __u32 flags; + __u32 resamplefd; + __u8 pad[16]; +}; + +#define GZVM_IRQFD _IOW(GZVM_IOC_MAGIC, 0x76, struct gzvm_irqfd) + #endif /* __GZVM_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A4CA71F8900; Thu, 14 Nov 2024 10:08:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; cv=none; b=VnFbowoSsPupRFEzPsSVGIOVIvGC7zn/rCEYAyiBBFQiO99de//pn9Ru0HRvRNfCh3RL0ouzH2mP6jj4PXEyDIBLdFqIjgQd4N/IqI28iSeCzvw0XgRuGoQ2WQQBV9j3JgZzYrg5Piy6msL3ExqLQCEqFht+VACdMxrrtpwlpv8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; c=relaxed/simple; bh=wfbvIWm+lgsbfTQxjtKTXKDvvHlHE3iY16iIMolj2B8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nme50KY+xb2QYzNZ7eQ8cM+rnK5jTCZ/Lm5N4XE8bb+RJsKyDHLd44L1XMYR82kcReN93yKjbFI4lQu2BXOfVVnu4TGAYKMHxldt87q82AOO1YKL8ijpEm3SLt5qa9qaNqAwx4dcz9jbqel4GUUWFMHKEuDWODzsrCLZaSj9ZTk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=jqaIldYb; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="jqaIldYb" X-UUID: 57946776a27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=S8TOUN7WKAKqi+9Kvjb5HEqNlVJsmMRCFDmMVzd6vuU=; b=jqaIldYbIlSw2634Z3dsXpNz1iUQC/yazrrLRICvONE75D4tC23z1q98AmkCgMD01cTvZEPzRsOqaUeoq8HxtItxEAjOPfxEE76BBYxH8FixyQxYl3AYMcp9QoFdI8+kODWBqXbh+LmAlwIFdqTDdkBqhoPLDsaszt27zqs4Mb4=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:c2280762-646e-4f14-a4c4-265c129ded66,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:da6b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 57946776a27011efbd192953cf12861f-20241114 Received: from mtkmbs13n1.mediatek.inc [(172.21.101.193)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1739100366; Thu, 14 Nov 2024 18:08:06 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs11n1.mediatek.inc (172.21.101.185) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:04 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 11/25] virt: geniezone: Add ioeventfd support Date: Thu, 14 Nov 2024 18:07:48 +0800 Message-ID: <20241114100802.4116-12-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan Ioeventfd leverages eventfd to provide asynchronous notification mechanism for VMM. VMM can register a mmio address and bind with an eventfd. Once a mmio trap occurs on this registered region, its corresponding eventfd will be notified. Signed-off-by: Yingshiuan Pan Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- drivers/virt/geniezone/Makefile | 3 +- drivers/virt/geniezone/gzvm_ioeventfd.c | 281 ++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_vcpu.c | 27 ++- drivers/virt/geniezone/gzvm_vm.c | 17 ++ include/linux/soc/mediatek/gzvm_drv.h | 15 ++ include/uapi/linux/gzvm.h | 25 +++ 6 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 drivers/virt/geniezone/gzvm_ioeventfd.c diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makef= ile index 19a835b0aac2..bc5ae49f2407 100644 --- a/drivers/virt/geniezone/Makefile +++ b/drivers/virt/geniezone/Makefile @@ -7,4 +7,5 @@ GZVM_DIR ?=3D ../../../drivers/virt/geniezone =20 gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o \ - $(GZVM_DIR)/gzvm_vcpu.o $(GZVM_DIR)/gzvm_irqfd.o + $(GZVM_DIR)/gzvm_vcpu.o $(GZVM_DIR)/gzvm_irqfd.o \ + $(GZVM_DIR)/gzvm_ioeventfd.o diff --git a/drivers/virt/geniezone/gzvm_ioeventfd.c b/drivers/virt/geniezo= ne/gzvm_ioeventfd.c new file mode 100644 index 000000000000..98afcfdd4e1c --- /dev/null +++ b/drivers/virt/geniezone/gzvm_ioeventfd.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct gzvm_ioevent { + struct list_head list; + __u64 addr; + __u32 len; + struct eventfd_ctx *evt_ctx; + __u64 datamatch; + bool wildcard; +}; + +/** + * ioeventfd_check_collision() - Check collision assumes gzvm->ioevent_loc= k held. + * @gzvm: Pointer to gzvm. + * @p: Pointer to gzvm_ioevent. + * + * Return: + * * true - collision found + * * false - no collision + */ +static bool ioeventfd_check_collision(struct gzvm *gzvm, struct gzvm_ioeve= nt *p) +{ + struct gzvm_ioevent *_p; + + list_for_each_entry(_p, &gzvm->ioevents, list) { + if (_p->addr =3D=3D p->addr && + (!_p->len || !p->len || + (_p->len =3D=3D p->len && + (_p->wildcard || p->wildcard || + _p->datamatch =3D=3D p->datamatch)))) + return true; + if (p->addr >=3D _p->addr && p->addr < _p->addr + _p->len) + return true; + } + + return false; +} + +static void gzvm_ioevent_release(struct gzvm_ioevent *p) +{ + eventfd_ctx_put(p->evt_ctx); + list_del(&p->list); + kfree(p); +} + +static bool gzvm_ioevent_in_range(struct gzvm_ioevent *p, __u64 addr, int = len, + const void *val) +{ + u64 _val; + + if (addr !=3D p->addr) + /* address must be precise for a hit */ + return false; + + if (!p->len) + /* length =3D 0 means only look at the address, so always a hit */ + return true; + + if (len !=3D p->len) + /* address-range must be precise for a hit */ + return false; + + if (p->wildcard) + /* all else equal, wildcard is always a hit */ + return true; + + /* otherwise, we have to actually compare the data */ + + WARN_ON_ONCE(!IS_ALIGNED((unsigned long)val, len)); + + switch (len) { + case 1: + _val =3D *(u8 *)val; + break; + case 2: + _val =3D *(u16 *)val; + break; + case 4: + _val =3D *(u32 *)val; + break; + case 8: + _val =3D *(u64 *)val; + break; + default: + return false; + } + + return _val =3D=3D p->datamatch; +} + +static int gzvm_deassign_ioeventfd(struct gzvm *gzvm, + struct gzvm_ioeventfd *args) +{ + struct gzvm_ioevent *p, *tmp; + struct eventfd_ctx *evt_ctx; + int ret =3D -ENOENT; + bool wildcard; + + evt_ctx =3D eventfd_ctx_fdget(args->fd); + if (IS_ERR(evt_ctx)) + return PTR_ERR(evt_ctx); + + wildcard =3D !(args->flags & GZVM_IOEVENTFD_FLAG_DATAMATCH); + + mutex_lock(&gzvm->ioevent_lock); + list_for_each_entry_safe(p, tmp, &gzvm->ioevents, list) { + if (p->evt_ctx !=3D evt_ctx || + p->addr !=3D args->addr || + p->len !=3D args->len || + p->wildcard !=3D wildcard) + continue; + + if (!p->wildcard && p->datamatch !=3D args->datamatch) + continue; + + gzvm_ioevent_release(p); + ret =3D 0; + break; + } + + mutex_unlock(&gzvm->ioevent_lock); + + /* got in the front of this function */ + eventfd_ctx_put(evt_ctx); + + return ret; +} + +static int gzvm_assign_ioeventfd(struct gzvm *gzvm, struct gzvm_ioeventfd = *args) +{ + struct eventfd_ctx *evt_ctx; + struct gzvm_ioevent *evt; + int ret; + + evt_ctx =3D eventfd_ctx_fdget(args->fd); + if (IS_ERR(evt_ctx)) + return PTR_ERR(evt_ctx); + + evt =3D kmalloc(sizeof(*evt), GFP_KERNEL); + if (!evt) + return -ENOMEM; + *evt =3D (struct gzvm_ioevent) { + .addr =3D args->addr, + .len =3D args->len, + .evt_ctx =3D evt_ctx, + }; + if (args->flags & GZVM_IOEVENTFD_FLAG_DATAMATCH) { + evt->datamatch =3D args->datamatch; + evt->wildcard =3D false; + } else { + evt->wildcard =3D true; + } + + mutex_lock(&gzvm->ioevent_lock); + if (ioeventfd_check_collision(gzvm, evt)) { + ret =3D -EEXIST; + mutex_unlock(&gzvm->ioevent_lock); + goto err_free; + } + + list_add_tail(&evt->list, &gzvm->ioevents); + mutex_unlock(&gzvm->ioevent_lock); + + return 0; + +err_free: + kfree(evt); + eventfd_ctx_put(evt_ctx); + return ret; +} + +/** + * gzvm_ioeventfd_check_valid() - Check user arguments is valid. + * @args: Pointer to gzvm_ioeventfd. + * + * Return: + * * true if user arguments are valid. + * * false if user arguments are invalid. + */ +static bool gzvm_ioeventfd_check_valid(struct gzvm_ioeventfd *args) +{ + /* must be natural-word sized, or 0 to ignore length */ + switch (args->len) { + case 0: + case 1: + case 2: + case 4: + case 8: + break; + default: + return false; + } + + /* check for range overflow */ + if (args->addr + args->len < args->addr) + return false; + + /* check for extra flags that we don't understand */ + if (args->flags & ~GZVM_IOEVENTFD_VALID_FLAG_MASK) + return false; + + /* ioeventfd with no length can't be combined with DATAMATCH */ + if (!args->len && (args->flags & GZVM_IOEVENTFD_FLAG_DATAMATCH)) + return false; + + /* gzvm does not support pio bus ioeventfd */ + if (args->flags & GZVM_IOEVENTFD_FLAG_PIO) + return false; + + return true; +} + +/** + * gzvm_ioeventfd() - Register ioevent to ioevent list. + * @gzvm: Pointer to gzvm. + * @args: Pointer to gzvm_ioeventfd. + * + * Return: + * * 0 - Success. + * * Negative - Failure. + */ +int gzvm_ioeventfd(struct gzvm *gzvm, struct gzvm_ioeventfd *args) +{ + if (gzvm_ioeventfd_check_valid(args) =3D=3D false) + return -EINVAL; + + if (args->flags & GZVM_IOEVENTFD_FLAG_DEASSIGN) + return gzvm_deassign_ioeventfd(gzvm, args); + return gzvm_assign_ioeventfd(gzvm, args); +} + +/** + * gzvm_ioevent_write() - Travers this vm's registered ioeventfd to see if + * need notifying it. + * @vcpu: Pointer to vcpu. + * @addr: mmio address. + * @len: mmio size. + * @val: Pointer to void. + * + * Return: + * * true if this io is already sent to ioeventfd's listener. + * * false if we cannot find any ioeventfd registering this mmio write. + */ +bool gzvm_ioevent_write(struct gzvm_vcpu *vcpu, __u64 addr, int len, + const void *val) +{ + struct gzvm_ioevent *e; + + mutex_lock(&vcpu->gzvm->ioevent_lock); + list_for_each_entry(e, &vcpu->gzvm->ioevents, list) { + if (gzvm_ioevent_in_range(e, addr, len, val)) { + eventfd_signal(e->evt_ctx); + mutex_unlock(&vcpu->gzvm->ioevent_lock); + return true; + } + } + + mutex_unlock(&vcpu->gzvm->ioevent_lock); + return false; +} + +int gzvm_init_ioeventfd(struct gzvm *gzvm) +{ + INIT_LIST_HEAD(&gzvm->ioevents); + mutex_init(&gzvm->ioevent_lock); + + return 0; +} diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index 7e1e16d0f3a1..446c0e42dec6 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -50,6 +50,30 @@ static long gzvm_vcpu_update_one_reg(struct gzvm_vcpu *v= cpu, return 0; } =20 +/** + * gzvm_vcpu_handle_mmio() - Handle mmio in kernel space. + * @vcpu: Pointer to vcpu. + * + * Return: + * * true - This mmio exit has been processed. + * * false - This mmio exit has not been processed, require userspace. + */ +static bool gzvm_vcpu_handle_mmio(struct gzvm_vcpu *vcpu) +{ + __u64 addr; + __u32 len; + const void *val_ptr; + + /* So far, we don't have in-kernel mmio read handler */ + if (!vcpu->run->mmio.is_write) + return false; + addr =3D vcpu->run->mmio.phys_addr; + len =3D vcpu->run->mmio.size; + val_ptr =3D &vcpu->run->mmio.data; + + return gzvm_ioevent_write(vcpu, addr, len, val_ptr); +} + /** * gzvm_vcpu_run() - Handle vcpu run ioctl, entry point to guest and exit * point from guest @@ -81,7 +105,8 @@ static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, void _= _user *argp) =20 switch (exit_reason) { case GZVM_EXIT_MMIO: - need_userspace =3D true; + if (!gzvm_vcpu_handle_mmio(vcpu)) + need_userspace =3D true; break; /** * it's geniezone's responsibility to fill corresponding data diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index df1d666d5bcb..27275d44b7a4 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -254,6 +254,16 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned = int ioctl, ret =3D gzvm_irqfd(gzvm, &data); break; } + case GZVM_IOEVENTFD: { + struct gzvm_ioeventfd data; + + if (copy_from_user(&data, argp, sizeof(data))) { + ret =3D -EFAULT; + goto out; + } + ret =3D gzvm_ioeventfd(gzvm, &data); + break; + } case GZVM_ENABLE_CAP: { struct gzvm_enable_cap cap; =20 @@ -330,6 +340,13 @@ static struct gzvm *gzvm_create_vm(struct gzvm_driver = *drv, unsigned long vm_typ return ERR_PTR(ret); } =20 + ret =3D gzvm_init_ioeventfd(gzvm); + if (ret) { + pr_err("Failed to initialize ioeventfd\n"); + kfree(gzvm); + return ERR_PTR(ret); + } + mutex_lock(&gzvm_list_lock); list_add(&gzvm->vm_list, &gzvm_list); mutex_unlock(&gzvm_list_lock); diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index c19035ff7975..85ac8bb3a4fa 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -6,6 +6,7 @@ #ifndef __GZVM_DRV_H__ #define __GZVM_DRV_H__ =20 +#include #include #include #include @@ -120,6 +121,8 @@ struct gzvm_vcpu { * @memslot: VM's memory slot descriptor * @lock: lock for list_add * @irqfds: the data structure is used to keep irqfds's information + * @ioevents: list head for ioevents + * @ioevent_lock: lock for ioevent list * @vm_list: list head for vm list * @vm_id: vm id * @irq_ack_notifier_list: list head for irq ack notifier @@ -140,6 +143,9 @@ struct gzvm { struct mutex resampler_lock; } irqfds; =20 + struct list_head ioevents; + struct mutex ioevent_lock; + struct list_head vm_list; u16 vm_id; =20 @@ -191,4 +197,13 @@ void gzvm_drv_irqfd_exit(void); int gzvm_vm_irqfd_init(struct gzvm *gzvm); void gzvm_vm_irqfd_release(struct gzvm *gzvm); =20 +int gzvm_init_ioeventfd(struct gzvm *gzvm); +int gzvm_ioeventfd(struct gzvm *gzvm, struct gzvm_ioeventfd *args); +bool gzvm_ioevent_write(struct gzvm_vcpu *vcpu, __u64 addr, int len, + const void *val); +void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt); +struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr= ); +void add_wait_queue_priority(struct wait_queue_head *wq_head, + struct wait_queue_entry *wq_entry); + #endif /* __GZVM_DRV_H__ */ diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index aa61ece00cac..6e102cbfec98 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -339,4 +339,29 @@ struct gzvm_irqfd { =20 #define GZVM_IRQFD _IOW(GZVM_IOC_MAGIC, 0x76, struct gzvm_irqfd) =20 +enum { + gzvm_ioeventfd_flag_nr_datamatch =3D 0, + gzvm_ioeventfd_flag_nr_pio =3D 1, + gzvm_ioeventfd_flag_nr_deassign =3D 2, + gzvm_ioeventfd_flag_nr_max, +}; + +#define GZVM_IOEVENTFD_FLAG_DATAMATCH (1 << gzvm_ioeventfd_flag_nr_datamat= ch) +#define GZVM_IOEVENTFD_FLAG_PIO (1 << gzvm_ioeventfd_flag_nr_pio) +#define GZVM_IOEVENTFD_FLAG_DEASSIGN (1 << gzvm_ioeventfd_flag_nr_deassign) +#define GZVM_IOEVENTFD_VALID_FLAG_MASK ((1 << gzvm_ioeventfd_flag_nr_max) = - 1) + +struct gzvm_ioeventfd { + __u64 datamatch; + /* private: legal pio/mmio address */ + __u64 addr; + /* private: 1, 2, 4, or 8 bytes; or 0 to ignore length */ + __u32 len; + __s32 fd; + __u32 flags; + __u8 pad[36]; +}; + +#define GZVM_IOEVENTFD _IOW(GZVM_IOC_MAGIC, 0x79, struct gzvm_ioeventfd) + #endif /* __GZVM_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4FCD41F893E; Thu, 14 Nov 2024 10:08:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; cv=none; b=fB48+Re4U/0MrWvYsKc0N+biLRoFiL0xBN5cn2Lo+wQtGsELJrkWweBDZfaLviMaQhXNaRdRAMCb691wEcSn9egGnEws3SkqNRGeJKBlcK5EqgR5uBVD6la0Ak5en6Ux01Z8eMyHq3lJ8tqV0/HzHBVSH8ULrojAQLeM/W891xI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; c=relaxed/simple; bh=lfs9v6JWw3ofrtFrRrrDy2qCu/PTF2gE6z0UXcsAbAc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ilvru+qpj2Hdsv/Fhqm9LP3vX0kZuTWEO2CNHZEuuqybS3b7Mgtv2eDUBaD8WK0Xkqcn6etkI3x3WQ504u4ezJFzH+14KhLmIreeeoDKuN+/xuZQEijx2g+iXKAINGS0mssGuJStgAPlYRz9vs27ttZ5D51BEvwQVo97la0vUUE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=GnxuB4RW; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="GnxuB4RW" X-UUID: 583954fca27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=MHCUzgNzvRYpdtn0+aXqa8vcEJ2ZuUHgIfAQYwIndAM=; b=GnxuB4RWrqXIla4p5QEkVPYD935/7Y/b+TATvIRmS9sW6L6lLrjDaL+PvAOmjqdFdN0m83YYYRz4HT6imxR5HgXOcrbxHlU5p5ahfUCcZCZgp2dfPQmtSkSyqU/nRPM9mvf4bz0z1JiGO7dN4t8luvyvxbo/082Yam1zG68JAqg=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:91eb236f-e2ba-4c6b-bfc0-623749cc221c,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:3d3fa25c-f18b-4d56-b49c-93279ee09144,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 583954fca27011ef99858b75a2457dd9-20241114 Received: from mtkmbs09n2.mediatek.inc [(172.21.101.94)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1908025639; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS14N1.mediatek.inc (172.21.101.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:04 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:04 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , "Catalin Marinas" , Will Deacon , "Steven Rostedt" , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 12/25] virt: geniezone: Add memory region purpose for hypervisor Date: Thu, 14 Nov 2024 18:07:49 +0800 Message-ID: <20241114100802.4116-13-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--3.824400-8.000000 X-TMASE-MatchedRID: Bo0EIJTmAYww2a0RxGqSGyVypP66BP0QNNuh+5zmS68Cgjr7b0ytGZas fA8Y/RCF8B1Eq8wDKAEQzM3Grt8RghUBkTmMruyZhK8o4aoss8pKPIx+MJF9o99RlPzeVuQQpc2 xgJAY6Lr/EdEp4HtkngHGJy9aPQkxszLAY5oHhBDd+fuf9kcapoLFgHaE9Li9myiLZetSf8mfop 0ytGwvXiq2rl3dzGQ19+9ZqEp9FTjbIpd/FKSDlJsJ98yktZKjDFej/B3xT7KOXRJoEQaneGkvT FWLTL2hKBJ/fQnHuR9UuZzX1SryYb7MpHk3WinNOvpYxzItg+EXRoPmWO3jekxwdkPqCq7vDEyN +J8hd+jCS9WgDXVPCp6oP1a0mRIj X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--3.824400-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: 15492F276D697DA72D1DBB9A899C85FE50092AE46761A00D0B8A572DC4E8477F2000:8 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jerry Wang Hypervisor might need to know the precise purpose of each memory region, so that it can provide specific memory protection. We add a new uapi to pass address and size of a memory region and its purpose. Signed-off-by: Jerry Wang Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 2 ++ arch/arm64/geniezone/vm.c | 10 ++++++++++ drivers/virt/geniezone/gzvm_vm.c | 7 +++++++ include/linux/soc/mediatek/gzvm_drv.h | 3 +++ 4 files changed, 22 insertions(+) diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index d4b49a4b283a..dabd11438e94 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -22,6 +22,7 @@ enum { GZVM_FUNC_PROBE =3D 12, GZVM_FUNC_ENABLE_CAP =3D 13, GZVM_FUNC_INFORM_EXIT =3D 14, + GZVM_FUNC_MEMREGION_PURPOSE =3D 15, NR_GZVM_FUNC, }; =20 @@ -44,6 +45,7 @@ enum { #define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) #define MT_HVC_GZVM_ENABLE_CAP GZVM_HCALL_ID(GZVM_FUNC_ENABLE_CAP) #define MT_HVC_GZVM_INFORM_EXIT GZVM_HCALL_ID(GZVM_FUNC_INFORM_EXIT) +#define MT_HVC_GZVM_MEMREGION_PURPOSE GZVM_HCALL_ID(GZVM_FUNC_MEMREGION_PU= RPOSE) =20 #define GIC_V3_NR_LRS 16 =20 diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 743951aa8ec3..fe1caf841de8 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -153,6 +153,16 @@ int gzvm_arch_destroy_vm(u16 vm_id) 0, 0, &res); } =20 +int gzvm_arch_memregion_purpose(struct gzvm *gzvm, + struct gzvm_userspace_memory_region *mem) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_MEMREGION_PURPOSE, gzvm->vm_id, + mem->guest_phys_addr, mem->memory_size, + mem->flags, 0, 0, 0, &res); +} + static int gzvm_vm_arch_enable_cap(struct gzvm *gzvm, struct gzvm_enable_cap *cap, struct arm_smccc_res *res) diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 27275d44b7a4..c2e4568d2d3f 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -105,6 +105,7 @@ static int gzvm_vm_ioctl_set_memory_region(struct gzvm *gzvm, struct gzvm_userspace_memory_region *mem) { + int ret; struct vm_area_struct *vma; struct gzvm_memslot *memslot; unsigned long size; @@ -128,6 +129,12 @@ gzvm_vm_ioctl_set_memory_region(struct gzvm *gzvm, memslot->vma =3D vma; memslot->flags =3D mem->flags; memslot->slot_id =3D mem->slot; + + ret =3D gzvm_arch_memregion_purpose(gzvm, mem); + if (ret) { + pr_err("Failed to config memory region for the specified purpose\n"); + return -EFAULT; + } return register_memslot_addr_range(gzvm, memslot); } =20 diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 85ac8bb3a4fa..8e98b3145881 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -197,6 +197,9 @@ void gzvm_drv_irqfd_exit(void); int gzvm_vm_irqfd_init(struct gzvm *gzvm); void gzvm_vm_irqfd_release(struct gzvm *gzvm); =20 +int gzvm_arch_memregion_purpose(struct gzvm *gzvm, + struct gzvm_userspace_memory_region *mem); + int gzvm_init_ioeventfd(struct gzvm *gzvm); int gzvm_ioeventfd(struct gzvm *gzvm, struct gzvm_ioeventfd *args); bool gzvm_ioevent_write(struct gzvm_vcpu *vcpu, __u64 addr, int len, --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3955C1F8185; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; cv=none; b=k90zUU3cIRthR622CpNljzYCw16sVIvqREv1i6nDUzCnqijqMuQPi4IeCcTPAS21BNzjyIbP2Vu7ey9eC8uXPwGBcgQP5L8l/Jz5Zempeyy/3zADsnDVIcryZvD/7VoMR/f9mjjeI4a9TQMK2xzmdtYM1Xogp8Mx/wmPSnZDhqw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; c=relaxed/simple; bh=i6g3yWWs+R++mCu9o5sYrJWPBGAq1Ow716mRhc54kYI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=X1ywQnQjVHWLnbySvhFpCkKRiCwpzLeimsDWs4EhxI5Psncf/fB8OHmU/9TiCUsv5E4s1tacNgA3kS6QWeHBt+l80zYKnuage3gy71cxKtMaKNGxABXZgQ76umIXEkp8b6YEANmu2xgw/bYY5AC9fkI52ruhVswke6roEshjMEM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=LinfFUaX; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="LinfFUaX" X-UUID: 576e7e62a27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=VVCImlwKUuC7utEP6+QkS0VxR9+gKiYUNCGA0LPcTLU=; b=LinfFUaXcf3qjb7s+iHvKAqQ9nhS7GSxQE1GFuG7lYTtVixpAUwSXHM8f51R8Qq9kmRwan/LFI8qBS8+c4/IYcJ5r7LkI85lg+DfklgJniZwmO3a8fqcY3cCpZkgkSmAFRX6nPL3xjs/OjyBqvo3wtjWeN15+vUdqGOSw+Ja1LY=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:b7ace51d-4c8e-4365-92ce-3cfaa8395521,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:3e3fa25c-f18b-4d56-b49c-93279ee09144,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 576e7e62a27011ef99858b75a2457dd9-20241114 Received: from mtkmbs09n1.mediatek.inc [(172.21.101.35)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1899540010; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 02:08:05 -0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:05 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 13/25] virt: geniezone: Add dtb config support Date: Thu, 14 Nov 2024 18:07:50 +0800 Message-ID: <20241114100802.4116-14-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jerry Wang Hypervisor might need to know the accurate address and size of dtb passed from userspace. And then hypervisor would parse the dtb and get vm information. Signed-off-by: Jerry Wang Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 2 ++ arch/arm64/geniezone/vm.c | 9 +++++++++ drivers/virt/geniezone/gzvm_vm.c | 10 ++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 1 + include/uapi/linux/gzvm.h | 14 ++++++++++++++ 5 files changed, 36 insertions(+) diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index dabd11438e94..4366618cdc0a 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -23,6 +23,7 @@ enum { GZVM_FUNC_ENABLE_CAP =3D 13, GZVM_FUNC_INFORM_EXIT =3D 14, GZVM_FUNC_MEMREGION_PURPOSE =3D 15, + GZVM_FUNC_SET_DTB_CONFIG =3D 16, NR_GZVM_FUNC, }; =20 @@ -46,6 +47,7 @@ enum { #define MT_HVC_GZVM_ENABLE_CAP GZVM_HCALL_ID(GZVM_FUNC_ENABLE_CAP) #define MT_HVC_GZVM_INFORM_EXIT GZVM_HCALL_ID(GZVM_FUNC_INFORM_EXIT) #define MT_HVC_GZVM_MEMREGION_PURPOSE GZVM_HCALL_ID(GZVM_FUNC_MEMREGION_PU= RPOSE) +#define MT_HVC_GZVM_SET_DTB_CONFIG GZVM_HCALL_ID(GZVM_FUNC_SET_DTB_CONFIG) =20 #define GIC_V3_NR_LRS 16 =20 diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index fe1caf841de8..44cf1c5bfdb9 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -163,6 +163,15 @@ int gzvm_arch_memregion_purpose(struct gzvm *gzvm, mem->flags, 0, 0, 0, &res); } =20 +int gzvm_arch_set_dtb_config(struct gzvm *gzvm, struct gzvm_dtb_config *cf= g) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_SET_DTB_CONFIG, gzvm->vm_id, + cfg->dtb_addr, cfg->dtb_size, 0, 0, 0, 0, + &res); +} + static int gzvm_vm_arch_enable_cap(struct gzvm *gzvm, struct gzvm_enable_cap *cap, struct arm_smccc_res *res) diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index c2e4568d2d3f..5fc0167d2776 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -281,6 +281,16 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned = int ioctl, ret =3D gzvm_vm_ioctl_enable_cap(gzvm, &cap, argp); break; } + case GZVM_SET_DTB_CONFIG: { + struct gzvm_dtb_config cfg; + + if (copy_from_user(&cfg, argp, sizeof(cfg))) { + ret =3D -EFAULT; + goto out; + } + ret =3D gzvm_arch_set_dtb_config(gzvm, &cfg); + break; + } default: ret =3D -ENOTTY; } diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 8e98b3145881..835706586e93 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -199,6 +199,7 @@ void gzvm_vm_irqfd_release(struct gzvm *gzvm); =20 int gzvm_arch_memregion_purpose(struct gzvm *gzvm, struct gzvm_userspace_memory_region *mem); +int gzvm_arch_set_dtb_config(struct gzvm *gzvm, struct gzvm_dtb_config *ar= gs); =20 int gzvm_init_ioeventfd(struct gzvm *gzvm); int gzvm_ioeventfd(struct gzvm *gzvm, struct gzvm_ioeventfd *args); diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 6e102cbfec98..7aec4adf2206 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -364,4 +364,18 @@ struct gzvm_ioeventfd { =20 #define GZVM_IOEVENTFD _IOW(GZVM_IOC_MAGIC, 0x79, struct gzvm_ioeventfd) =20 +/** + * struct gzvm_dtb_config: store address and size of dtb passed from users= pace + * + * @dtb_addr: dtb address set by VMM (guset memory) + * @dtb_size: dtb size + */ +struct gzvm_dtb_config { + __u64 dtb_addr; + __u64 dtb_size; +}; + +#define GZVM_SET_DTB_CONFIG _IOW(GZVM_IOC_MAGIC, 0xff, \ + struct gzvm_dtb_config) + #endif /* __GZVM_H__ */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F3D321E47A5; Thu, 14 Nov 2024 10:08:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578896; cv=none; b=KyOh3+HNjpn4oD10sM3uu1nRTV9AaRozRcZxMpybKVL0KdsQsXM9RgrK04J+MZnpPGBdq9ZssGMDHldy8TPWfk+qhrnERPcQjsV22tw8reuOBX9ZpiDqBm1gEQeArbmL+7Vacj2iZgfcznQh8/nHQvznqP+yrWK1rP5JrRB+wjk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578896; c=relaxed/simple; bh=AqWIqcZQNv5b2b/J/2pTfXd0accT1kVf3/axRIU+Nmc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DKNiLaikZfp1C46aqCvYo0hj0ZLcWEjNyPveE4xKNA46KOyw9i57zoh5Svh+g1KNz1gdz4lLrrVrQ5ENPu8/NiyKdcTiko+nqlj5qHWq4el+jzNvf8BYdk0pBDHdlct5tdKS5AcCHfHKB6MfeEYov/Q/O1QNpfWwTGtOAnPk1p8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=aFmTI0Wi; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="aFmTI0Wi" X-UUID: 5770d838a27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=fFsbtSrPsSuZ1BAYfrEE3l+4l9FiYC7OgSCPyunYV3Q=; b=aFmTI0WiDvJRJ887pDBGSe5PWvBA8Slr3MUTGLWPO5U21NlLEAFA8SB1X5Yg1PWuHdgwX8f1A7OSCQLoOv4I4VHKQWXOqs3nXuL2aQo9IsNh8tudUUfhK5J/IliBLNfYAKh+g+ccM59v3uiRsYyS5pMnId5k49mV6Fb4mvGnk8E=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:b390f7b4-7b0f-4deb-a3e2-043919c2ae5f,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:d55e0c4f-a2ae-4b53-acd4-c3dc8f449198,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 5770d838a27011ef99858b75a2457dd9-20241114 Received: from mtkmbs09n1.mediatek.inc [(172.21.101.35)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1329927388; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 02:08:05 -0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:05 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 14/25] virt: geniezone: Optimize performance of protected VM memory Date: Thu, 14 Nov 2024 18:07:51 +0800 Message-ID: <20241114100802.4116-15-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan The memory protection mechanism performs better with batch operations on memory pages. To leverage this, we pre-allocate memory for VMs that are set to protected mode. As a result, the memory protection mechanism can proactively protect the pre-allocated memory in advance through batch operations, leading to improved performance during VM booting. Signed-off-by: Yingshiuan Pan Co-developed-by: Jerry Wang Signed-off-by: Jerry Wang Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/vm.c | 127 ++++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 1 + 2 files changed, 128 insertions(+) diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 44cf1c5bfdb9..cc6c7e99851c 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -11,6 +11,8 @@ #include #include "gzvm_arch_common.h" =20 +#define PAR_PA47_MASK GENMASK_ULL(47, 12) + /** * gzvm_hypcall_wrapper() - the wrapper for hvc calls * @a0: arguments passed in registers 0 @@ -210,6 +212,126 @@ static int gzvm_vm_ioctl_get_pvmfw_size(struct gzvm *= gzvm, return 0; } =20 +/** + * fill_constituents() - Populate pa to buffer until full + * @consti: Pointer to struct mem_region_addr_range. + * @consti_cnt: Constituent count. + * @max_nr_consti: Maximum number of constituent count. + * @gfn: Guest frame number. + * @total_pages: Total page numbers. + * @slot: Pointer to struct gzvm_memslot. + * + * Return: how many pages we've fill in, negative if error + */ +static int fill_constituents(struct mem_region_addr_range *consti, + int *consti_cnt, int max_nr_consti, u64 gfn, + u32 total_pages, struct gzvm_memslot *slot) +{ + u64 pfn =3D 0, prev_pfn =3D 0, gfn_end =3D 0; + int nr_pages =3D 0; + int i =3D -1; + + if (unlikely(total_pages =3D=3D 0)) + return -EINVAL; + gfn_end =3D gfn + total_pages; + + while (i < max_nr_consti && gfn < gfn_end) { + if (pfn =3D=3D (prev_pfn + 1)) { + consti[i].pg_cnt++; + } else { + i++; + if (i >=3D max_nr_consti) + break; + consti[i].address =3D PFN_PHYS(pfn); + consti[i].pg_cnt =3D 1; + } + prev_pfn =3D pfn; + gfn++; + nr_pages++; + } + if (i !=3D max_nr_consti) + i++; + *consti_cnt =3D i; + + return nr_pages; +} + +/** + * gzvm_vm_populate_mem_region() - Iterate all mem slot and populate pa to + * buffer until it's full + * @gzvm: Pointer to struct gzvm. + * @slot_id: Memory slot id to be populated. + * + * Return: 0 if it is successful, negative if error + */ +int gzvm_vm_populate_mem_region(struct gzvm *gzvm, int slot_id) +{ + struct gzvm_memslot *memslot =3D &gzvm->memslot[slot_id]; + struct gzvm_memory_region_ranges *region; + int max_nr_consti, remain_pages; + u64 gfn, gfn_end; + u32 buf_size; + + buf_size =3D PAGE_SIZE * 2; + region =3D alloc_pages_exact(buf_size, GFP_KERNEL); + if (!region) + return -ENOMEM; + + max_nr_consti =3D (buf_size - sizeof(*region)) / + sizeof(struct mem_region_addr_range); + + region->slot =3D memslot->slot_id; + remain_pages =3D memslot->npages; + gfn =3D memslot->base_gfn; + gfn_end =3D gfn + remain_pages; + + while (gfn < gfn_end) { + int nr_pages; + + nr_pages =3D fill_constituents(region->constituents, + ®ion->constituent_cnt, + max_nr_consti, gfn, + remain_pages, memslot); + + if (nr_pages < 0) { + pr_err("Failed to fill constituents\n"); + free_pages_exact(region, buf_size); + return -EFAULT; + } + + region->gpa =3D PFN_PHYS(gfn); + region->total_pages =3D nr_pages; + remain_pages -=3D nr_pages; + gfn +=3D nr_pages; + + if (gzvm_arch_set_memregion(gzvm->vm_id, buf_size, + virt_to_phys(region))) { + pr_err("Failed to register memregion to hypervisor\n"); + free_pages_exact(region, buf_size); + return -EFAULT; + } + } + free_pages_exact(region, buf_size); + + return 0; +} + +static int populate_all_mem_regions(struct gzvm *gzvm) +{ + int ret, i; + + for (i =3D 0; i < GZVM_MAX_MEM_REGION; i++) { + if (gzvm->memslot[i].npages =3D=3D 0) + continue; + + ret =3D gzvm_vm_populate_mem_region(gzvm, i); + if (ret !=3D 0) + return ret; + } + + return 0; +} + /** * gzvm_vm_ioctl_cap_pvm() - Proceed GZVM_CAP_PROTECTED_VM's subcommands * @gzvm: Pointer to struct gzvm. @@ -231,6 +353,11 @@ static int gzvm_vm_ioctl_cap_pvm(struct gzvm *gzvm, case GZVM_CAP_PVM_SET_PVMFW_GPA: fallthrough; case GZVM_CAP_PVM_SET_PROTECTED_VM: + /* + * To improve performance for protected VM, we have to populate VM's mem= ory + * before VM booting + */ + populate_all_mem_regions(gzvm); ret =3D gzvm_vm_arch_enable_cap(gzvm, cap, &res); return ret; case GZVM_CAP_PVM_GET_PVMFW_SIZE: diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 835706586e93..07ab42357328 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -177,6 +177,7 @@ int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, =20 int gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot, u64 gfn, u64 *hva_memslot); +int gzvm_vm_populate_mem_region(struct gzvm *gzvm, int slot_id); =20 int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cpuid); int gzvm_arch_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, __u64 reg_id, --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6C0961F9A9B; Thu, 14 Nov 2024 10:08:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578904; cv=none; b=C8WjXV3r5Yd0T8KyxUJrblR+8jd2Pa1OfdmxK2UnwcakH36nR3y+FKWw/w+1YZfE4DJe0f6oy0qJ/+kES9pGNMqJgl2yrRNnbkLAuiaV9WoVyarKFF+Iqu2551QPEmRqGxn+Z0S6dkhh2FOqIUS4jt2qGzG0jlbk8fWOqyzURiM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578904; c=relaxed/simple; bh=LMUBORxUBo5WE020SeHL9JsiXsgaxDKW6MJpTr95rxM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MN1NqLqAkDrcertCoE9P4YpsF7f4UOV4Mr5rrtEC02QnknMHqaJZ1h9PIOEMQ7BYZ+fFBku+W5VYQxgSyHS7P61EdeObq4D6jW1LiekbXfDPpVTJ1N65GVY6rzXdzkUoGXq5qDkPAQCMksgniUM8XhXLkiJq2l8M3iV6hjyeiL8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=KOfAHSeo; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="KOfAHSeo" X-UUID: 588a7e40a27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=uhy8vnz2E6hISHcdfPnY9jgEbX+8LIczIgL6BPP6uT4=; b=KOfAHSeo3PWKGDJLnH+YNMIBknvmdewZW66nEAfttXoO89tMVh5C2nAyrgzHDRFXXKszOWI+ZZxyS9Ieq3T7CtzlMNfW/nY56Cmmtywp7vtfc8KPWsPsQ1ItGolo6tJEkSIGvtxR2j+KdrVey93FlZdbdM72wlUl1xytahXy/NI=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:92473346-f80a-4eaa-9d38-97b46905c015,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:fa6b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 588a7e40a27011efbd192953cf12861f-20241114 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1163765824; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:05 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , "Catalin Marinas" , Will Deacon , "Steven Rostedt" , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 15/25] virt: geniezone: Add memory pin/unpin support Date: Thu, 14 Nov 2024 18:07:52 +0800 Message-ID: <20241114100802.4116-16-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--4.660800-8.000000 X-TMASE-MatchedRID: ohmy6aWyl/8/TqR73SoO885Scd0yVs+bbd6rGhWOAwQCSZrAnTS0Brps GokK+C//AuwgUdYPZkXW0e5KCL9fbo0GdWKgGbBhMIiU395I8H3QeN4A2h64ncA5YKm8dwM63AG yPNT+2THhlCpgdm2rGFijcb6u/Gs1qjvsBy5CHDsD2WXLXdz+Ae3+iQEtoSj4FLXUWU5hGiF0Pi IFfRms6CFGk2ccyuPFSJ1jQcCKXwZPDPfmo+ftx8Ed6AVHFtpjK5Mx6KzrJcNKb99LaADG+tzuz yvdSEu2w3bvXc5S63u0rE5AMK32BLSYnj+K473ZyeVujmXuYYXzWEMQjooUzQZbeEWcL03VnvoH IZ6bqqQpFI+5rucNwRcDcEF6XUZOHyzWFbk8FLXDa1qWPNOExoED+PNzPecBCAfRfqq1Gm6fWSI EJ+NgXTH5/F/NumlT/4RBY1ijhrA9S3IiQd+eNWYNYtsE5knDx3lyq2zCKQB/ssGgjAUC6uLSdV P2tZn5acNSxwfY1qesJ2NEVUY7679ZdlL8eonaC24oEZ6SpSk6XEE7Yhw4Fl7j2ig40J1MkIceI oqo9ejHpz/MkUWhTf9py3CiC4ZosawLDy0EZGChW+djmSPci7GZzxBnu1zcAB4dioFGoVgXpfdF BARnq7dKECLo/klXhRFX0MbNzemQ4JrfEHpLweZmgnjb/yyM1RkHasLA4hI= X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--4.660800-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: D3B62EDEE17B739CB8B3F8D1514BD8D06D2EBF306DEA2DC8133B51E12BB8F5152000:8 X-MTK: N From: Jerry Wang Protected VM's memory cannot be swapped out because the memory pages are protected from host access. Once host accesses to those protected pages, the hardware exception is triggered and may crash the host. So, we have to make those protected pages be ineligible for swapping or merging by the host kernel to avoid host access. To do so, we pin the page when it is assigned (donated) to VM and unpin when VM relinquish the pages or is destroyed. Besides, the protected VM=E2=80=99s memory requires hypervisor to clear the content befo= re returning to host, but VMM may free those memory before clearing, it will result in those memory pages are reclaimed and reused before totally clearing. Using pin/unpin can also avoid the above problems. The implementation is described as follows. - Use rb_tree to store pinned memory pages. - Pin the page when handling page fault. - Unpin the pages when VM relinquish the pages or is destroyed. Signed-off-by: Jerry Wang Co-developed-by: Yingshiuan Pan Signed-off-by: Yingshiuan Pan Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/vm.c | 8 +- drivers/virt/geniezone/Makefile | 2 +- drivers/virt/geniezone/gzvm_mmu.c | 103 ++++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_vm.c | 21 ++++++ include/linux/soc/mediatek/gzvm_drv.h | 14 ++++ 5 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 drivers/virt/geniezone/gzvm_mmu.c diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index cc6c7e99851c..ac3d163a40fd 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -220,12 +220,14 @@ static int gzvm_vm_ioctl_get_pvmfw_size(struct gzvm *= gzvm, * @gfn: Guest frame number. * @total_pages: Total page numbers. * @slot: Pointer to struct gzvm_memslot. + * @gzvm: Pointer to struct gzvm. * * Return: how many pages we've fill in, negative if error */ static int fill_constituents(struct mem_region_addr_range *consti, int *consti_cnt, int max_nr_consti, u64 gfn, - u32 total_pages, struct gzvm_memslot *slot) + u32 total_pages, struct gzvm_memslot *slot, + struct gzvm *gzvm) { u64 pfn =3D 0, prev_pfn =3D 0, gfn_end =3D 0; int nr_pages =3D 0; @@ -236,6 +238,8 @@ static int fill_constituents(struct mem_region_addr_ran= ge *consti, gfn_end =3D gfn + total_pages; =20 while (i < max_nr_consti && gfn < gfn_end) { + if (gzvm_vm_allocate_guest_page(gzvm, slot, gfn, &pfn) !=3D 0) + return -EFAULT; if (pfn =3D=3D (prev_pfn + 1)) { consti[i].pg_cnt++; } else { @@ -291,7 +295,7 @@ int gzvm_vm_populate_mem_region(struct gzvm *gzvm, int = slot_id) nr_pages =3D fill_constituents(region->constituents, ®ion->constituent_cnt, max_nr_consti, gfn, - remain_pages, memslot); + remain_pages, memslot, gzvm); =20 if (nr_pages < 0) { pr_err("Failed to fill constituents\n"); diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makef= ile index bc5ae49f2407..e0451145215d 100644 --- a/drivers/virt/geniezone/Makefile +++ b/drivers/virt/geniezone/Makefile @@ -8,4 +8,4 @@ GZVM_DIR ?=3D ../../../drivers/virt/geniezone =20 gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o \ $(GZVM_DIR)/gzvm_vcpu.o $(GZVM_DIR)/gzvm_irqfd.o \ - $(GZVM_DIR)/gzvm_ioeventfd.o + $(GZVM_DIR)/gzvm_ioeventfd.o $(GZVM_DIR)/gzvm_mmu.o diff --git a/drivers/virt/geniezone/gzvm_mmu.c b/drivers/virt/geniezone/gzv= m_mmu.c new file mode 100644 index 000000000000..743df8976dfd --- /dev/null +++ b/drivers/virt/geniezone/gzvm_mmu.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include + +static int cmp_ppages(struct rb_node *node, const struct rb_node *parent) +{ + struct gzvm_pinned_page *a =3D container_of(node, + struct gzvm_pinned_page, + node); + struct gzvm_pinned_page *b =3D container_of(parent, + struct gzvm_pinned_page, + node); + + if (a->ipa < b->ipa) + return -1; + if (a->ipa > b->ipa) + return 1; + return 0; +} + +/* Invoker of this function is responsible for locking */ +static int gzvm_insert_ppage(struct gzvm *vm, struct gzvm_pinned_page *ppa= ge) +{ + if (rb_find_add(&ppage->node, &vm->pinned_pages, cmp_ppages)) + return -EEXIST; + return 0; +} + +static int pin_one_page(struct gzvm *vm, unsigned long hva, u64 gpa, + struct page **out_page) +{ + unsigned int flags =3D FOLL_HWPOISON | FOLL_LONGTERM | FOLL_WRITE; + struct gzvm_pinned_page *ppage =3D NULL; + struct mm_struct *mm =3D current->mm; + struct page *page =3D NULL; + int ret; + + ppage =3D kmalloc(sizeof(*ppage), GFP_KERNEL_ACCOUNT); + if (!ppage) + return -ENOMEM; + + mmap_read_lock(mm); + ret =3D pin_user_pages(hva, 1, flags, &page); + mmap_read_unlock(mm); + + if (ret !=3D 1 || !page) { + kfree(ppage); + return -EFAULT; + } + + ppage->page =3D page; + ppage->ipa =3D gpa; + + mutex_lock(&vm->mem_lock); + ret =3D gzvm_insert_ppage(vm, ppage); + + /** + * The return of -EEXIST from gzvm_insert_ppage is considered an + * expected behavior in this context. + * This situation arises when two or more VCPUs are concurrently + * engaged in demand paging handling. The initial VCPU has already + * allocated and pinned a page, while the subsequent VCPU attempts + * to pin the same page again. As a result, we prompt the unpinning + * and release of the allocated structure, followed by a return 0. + */ + if (ret =3D=3D -EEXIST) { + kfree(ppage); + unpin_user_pages(&page, 1); + ret =3D 0; + } + mutex_unlock(&vm->mem_lock); + *out_page =3D page; + + return ret; +} + +int gzvm_vm_allocate_guest_page(struct gzvm *vm, struct gzvm_memslot *slot, + u64 gfn, u64 *pfn) +{ + struct page *page =3D NULL; + unsigned long hva; + int ret; + + if (gzvm_gfn_to_hva_memslot(slot, gfn, (u64 *)&hva) !=3D 0) + return -EINVAL; + + ret =3D pin_one_page(vm, hva, PFN_PHYS(gfn), &page); + if (ret !=3D 0) + return ret; + + if (page =3D=3D NULL) + return -EFAULT; + /** + * As `pin_user_pages` already gets the page struct, we don't need to + * call other APIs to reduce function call overhead. + */ + *pfn =3D page_to_pfn(page); + + return 0; +} diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 5fc0167d2776..12f2c3c3810f 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -298,6 +298,22 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned = int ioctl, return ret; } =20 +/* Invoker of this function is responsible for locking */ +static void gzvm_destroy_all_ppage(struct gzvm *gzvm) +{ + struct gzvm_pinned_page *ppage; + struct rb_node *node; + + node =3D rb_first(&gzvm->pinned_pages); + while (node) { + ppage =3D rb_entry(node, struct gzvm_pinned_page, node); + unpin_user_pages_dirty_lock(&ppage->page, 1, true); + node =3D rb_next(node); + rb_erase(&ppage->node, &gzvm->pinned_pages); + kfree(ppage); + } +} + static void gzvm_destroy_vm(struct gzvm *gzvm) { pr_debug("VM-%u is going to be destroyed\n", gzvm->vm_id); @@ -314,6 +330,9 @@ static void gzvm_destroy_vm(struct gzvm *gzvm) =20 mutex_unlock(&gzvm->lock); =20 + /* No need to lock here becauese it's single-threaded execution */ + gzvm_destroy_all_ppage(gzvm); + kfree(gzvm); } =20 @@ -349,6 +368,8 @@ static struct gzvm *gzvm_create_vm(struct gzvm_driver *= drv, unsigned long vm_typ gzvm->vm_id =3D ret; gzvm->mm =3D current->mm; mutex_init(&gzvm->lock); + mutex_init(&gzvm->mem_lock); + gzvm->pinned_pages =3D RB_ROOT; =20 ret =3D gzvm_vm_irqfd_init(gzvm); if (ret) { diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 07ab42357328..920af91ea576 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -12,6 +12,7 @@ #include #include #include +#include =20 /* GZVM version encode */ #define GZVM_DRV_MAJOR_VERSION 16 @@ -112,6 +113,12 @@ struct gzvm_vcpu { struct gzvm_vcpu_hwstate *hwstate; }; =20 +struct gzvm_pinned_page { + struct rb_node node; + struct page *page; + u64 ipa; +}; + /** * struct gzvm: the following data structures are for data transferring be= tween * driver and hypervisor, and they're aligned with hypervisor definitions. @@ -128,6 +135,8 @@ struct gzvm_vcpu { * @irq_ack_notifier_list: list head for irq ack notifier * @irq_srcu: structure data for SRCU(sleepable rcu) * @irq_lock: lock for irq injection + * @pinned_pages: use rb-tree to record pin/unpin page + * @mem_lock: lock for memory operations */ struct gzvm { struct gzvm_driver *gzvm_drv; @@ -152,6 +161,9 @@ struct gzvm { struct hlist_head irq_ack_notifier_list; struct srcu_struct irq_srcu; struct mutex irq_lock; + + struct rb_root pinned_pages; + struct mutex mem_lock; }; =20 long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args); @@ -178,6 +190,8 @@ int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, int gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot, u64 gfn, u64 *hva_memslot); int gzvm_vm_populate_mem_region(struct gzvm *gzvm, int slot_id); +int gzvm_vm_allocate_guest_page(struct gzvm *gzvm, struct gzvm_memslot *sl= ot, + u64 gfn, u64 *pfn); =20 int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cpuid); int gzvm_arch_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, __u64 reg_id, --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87B541F9422; Thu, 14 Nov 2024 10:08:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578903; cv=none; b=usyfxWaC8vslbZjO7aIzRre/EIyfiRJ5ocSCkH3pIfl6PhY47CVcXkYaKGvuWGZdLTRYyipcVWlCwKnXwuGJA7Qch1OWZD9BfKFBuiy0iTiGTWF8ixudifMnph5NdWTWWLHYZgI8NFj8XYOWRmwa0vVNahUdRpI/kNBtXJbMCao= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578903; c=relaxed/simple; bh=azUGPq5CTQvRo8xubU95cKGSbhCCRSpSQi6iF3mJ5sA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NzZz717w4vxq5zfAGBUWLmmXGRq5Z7ihLzocIhI65zMcgrdmvosZWnJk55mJq3h3VkaRdiimNU7bZ48jrB45i/vQpWu+aUJ2/S0xlvviEiPuX1/ktjLi4mljgDelDPNcJ0s0zfFhli/RfwR4ebwM91gSXf7+od0ygKe5f/0y8zc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=Vxos/rBk; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="Vxos/rBk" X-UUID: 579a99caa27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=BZLvt6rFYTSRmrKjlh7enWtSJg9ZauHU9LAg9zI7MSY=; b=Vxos/rBkI/iMFVM5jENukpdgmYaX3B2ck9XTC/xyvrWgQtHEx2KjhbmgoVbFW5bnnfA528c7za25oyR584mZP6WxkDIucsH2kuu8XujM1u8KYPjraPWe8sXrEqirepSiDSYOQz6x7Hd+qIG8hXXnOqP9jpl+geSYlbVCml+lN9A=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:5c9bce28-b05c-4fbc-8ed1-f5ae97a4fc52,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:d96b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 579a99caa27011efbd192953cf12861f-20241114 Received: from mtkmbs13n1.mediatek.inc [(172.21.101.193)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 533159858; Thu, 14 Nov 2024 18:08:06 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs11n1.mediatek.inc (172.21.101.185) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:05 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 16/25] virt: geniezone: Add demand paging support Date: Thu, 14 Nov 2024 18:07:53 +0800 Message-ID: <20241114100802.4116-17-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan This page fault handler helps GenieZone hypervisor to do demand paging. On a lower level translation fault, GenieZone hypervisor will first check the fault GPA (guest physical address or IPA in ARM) is valid e.g. within the registered memory region, then it will setup the vcpu_run->exit_reason with necessary information for returning to gzvm driver. With the fault information, the gzvm driver looks up the physical address and call the MT_HVC_GZVM_MAP_GUEST to request the hypervisor maps the found PA to the fault GPA (IPA). There is one exception, for protected vm, we will populate full VM's memory region in advance in order to improve performance. Signed-off-by: Yingshiuan Pan Co-developed-by: Jerry Wang Signed-off-by: Jerry Wang Co-developed-by: Kevenny Hsieh Signed-off-by: Kevenny Hsieh Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 2 ++ arch/arm64/geniezone/vm.c | 13 +++++++ drivers/virt/geniezone/Makefile | 3 +- drivers/virt/geniezone/gzvm_exception.c | 39 ++++++++++++++++++++ drivers/virt/geniezone/gzvm_main.c | 2 ++ drivers/virt/geniezone/gzvm_mmu.c | 41 +++++++++++++++++++++ drivers/virt/geniezone/gzvm_vcpu.c | 6 ++-- drivers/virt/geniezone/gzvm_vm.c | 48 ++++++++++++++++++++++++- include/linux/soc/mediatek/gzvm_drv.h | 14 ++++++++ include/uapi/linux/gzvm.h | 13 +++++++ 10 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 drivers/virt/geniezone/gzvm_exception.c diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 4366618cdc0a..928191e3cdb2 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -24,6 +24,7 @@ enum { GZVM_FUNC_INFORM_EXIT =3D 14, GZVM_FUNC_MEMREGION_PURPOSE =3D 15, GZVM_FUNC_SET_DTB_CONFIG =3D 16, + GZVM_FUNC_MAP_GUEST =3D 17, NR_GZVM_FUNC, }; =20 @@ -48,6 +49,7 @@ enum { #define MT_HVC_GZVM_INFORM_EXIT GZVM_HCALL_ID(GZVM_FUNC_INFORM_EXIT) #define MT_HVC_GZVM_MEMREGION_PURPOSE GZVM_HCALL_ID(GZVM_FUNC_MEMREGION_PU= RPOSE) #define MT_HVC_GZVM_SET_DTB_CONFIG GZVM_HCALL_ID(GZVM_FUNC_SET_DTB_CONFIG) +#define MT_HVC_GZVM_MAP_GUEST GZVM_HCALL_ID(GZVM_FUNC_MAP_GUEST) =20 #define GIC_V3_NR_LRS 16 =20 diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index ac3d163a40fd..53e487912d2c 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -378,15 +378,28 @@ int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, struct gzvm_enable_cap *cap, void __user *argp) { + struct arm_smccc_res res =3D {0}; int ret; =20 switch (cap->cap) { case GZVM_CAP_PROTECTED_VM: ret =3D gzvm_vm_ioctl_cap_pvm(gzvm, cap, argp); return ret; + case GZVM_CAP_ENABLE_DEMAND_PAGING: + ret =3D gzvm_vm_arch_enable_cap(gzvm, cap, &res); + return ret; default: break; } =20 return -EINVAL; } + +int gzvm_arch_map_guest(u16 vm_id, int memslot_id, u64 pfn, u64 gfn, + u64 nr_pages) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_MAP_GUEST, vm_id, memslot_id, + pfn, gfn, nr_pages, 0, 0, &res); +} diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makef= ile index e0451145215d..f62f91f02640 100644 --- a/drivers/virt/geniezone/Makefile +++ b/drivers/virt/geniezone/Makefile @@ -8,4 +8,5 @@ GZVM_DIR ?=3D ../../../drivers/virt/geniezone =20 gzvm-y :=3D $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o \ $(GZVM_DIR)/gzvm_vcpu.o $(GZVM_DIR)/gzvm_irqfd.o \ - $(GZVM_DIR)/gzvm_ioeventfd.o $(GZVM_DIR)/gzvm_mmu.o + $(GZVM_DIR)/gzvm_ioeventfd.o $(GZVM_DIR)/gzvm_mmu.o \ + $(GZVM_DIR)/gzvm_exception.o diff --git a/drivers/virt/geniezone/gzvm_exception.c b/drivers/virt/geniezo= ne/gzvm_exception.c new file mode 100644 index 000000000000..2f5c05045e61 --- /dev/null +++ b/drivers/virt/geniezone/gzvm_exception.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include + +/** + * gzvm_handle_guest_exception() - Handle guest exception + * @vcpu: Pointer to struct gzvm_vcpu_run in userspace + * Return: + * * true - This exception has been processed, no need to back to VMM. + * * false - This exception has not been processed, require userspace. + */ +bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu) +{ + int ret; + + for (int i =3D 0; i < ARRAY_SIZE(vcpu->run->exception.reserved); i++) { + if (vcpu->run->exception.reserved[i]) + return false; + } + + switch (vcpu->run->exception.exception) { + case GZVM_EXCEPTION_PAGE_FAULT: + ret =3D gzvm_handle_page_fault(vcpu); + break; + case GZVM_EXCEPTION_UNKNOWN: + fallthrough; + default: + ret =3D -EFAULT; + } + + if (!ret) + return true; + else + return false; +} diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index 60348b88cd24..6142d1d792a4 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -36,6 +36,8 @@ int gzvm_err_to_errno(unsigned long err) return 0; case ERR_NO_MEMORY: return -ENOMEM; + case ERR_INVALID_ARGS: + return -EINVAL; case ERR_NOT_SUPPORTED: fallthrough; case ERR_NOT_IMPLEMENTED: diff --git a/drivers/virt/geniezone/gzvm_mmu.c b/drivers/virt/geniezone/gzv= m_mmu.c index 743df8976dfd..dcc8c4d7be83 100644 --- a/drivers/virt/geniezone/gzvm_mmu.c +++ b/drivers/virt/geniezone/gzvm_mmu.c @@ -101,3 +101,44 @@ int gzvm_vm_allocate_guest_page(struct gzvm *vm, struc= t gzvm_memslot *slot, =20 return 0; } + +static int handle_single_demand_page(struct gzvm *vm, int memslot_id, u64 = gfn) +{ + int ret; + u64 pfn; + + ret =3D gzvm_vm_allocate_guest_page(vm, &vm->memslot[memslot_id], gfn, &p= fn); + if (unlikely(ret)) + return -EFAULT; + + ret =3D gzvm_arch_map_guest(vm->vm_id, memslot_id, pfn, gfn, 1); + if (unlikely(ret)) + return -EFAULT; + return ret; +} + +/** + * gzvm_handle_page_fault() - Handle guest page fault, find corresponding = page + * for the faulting gpa + * @vcpu: Pointer to struct gzvm_vcpu_run of the faulting vcpu + * + * Return: + * * 0 - Success to handle guest page fault + * * -EFAULT - Failed to map phys addr to guest's GPA + */ +int gzvm_handle_page_fault(struct gzvm_vcpu *vcpu) +{ + struct gzvm *vm =3D vcpu->gzvm; + int memslot_id; + u64 gfn; + + gfn =3D PHYS_PFN(vcpu->run->exception.fault_gpa); + memslot_id =3D gzvm_find_memslot(vm, gfn); + if (unlikely(memslot_id < 0)) + return -EFAULT; + + if (unlikely(vm->mem_alloc_mode =3D=3D GZVM_FULLY_POPULATED)) + return -EFAULT; + + return handle_single_demand_page(vm, memslot_id, gfn); +} diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index 446c0e42dec6..3f6bffbafc7a 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -112,9 +112,11 @@ static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, void= __user *argp) * it's geniezone's responsibility to fill corresponding data * structure */ - case GZVM_EXIT_HYPERCALL: - fallthrough; case GZVM_EXIT_EXCEPTION: + if (!gzvm_handle_guest_exception(vcpu)) + need_userspace =3D true; + break; + case GZVM_EXIT_HYPERCALL: fallthrough; case GZVM_EXIT_DEBUG: fallthrough; diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 12f2c3c3810f..f63487809148 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -29,6 +29,31 @@ int gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot= , u64 gfn, return 0; } =20 +/** + * gzvm_find_memslot() - Find memslot containing this @gpa + * @vm: Pointer to struct gzvm + * @gfn: Guest frame number + * + * Return: + * * >=3D0 - Index of memslot + * * -EFAULT - Not found + */ +int gzvm_find_memslot(struct gzvm *vm, u64 gfn) +{ + int i; + + for (i =3D 0; i < GZVM_MAX_MEM_REGION; i++) { + if (vm->memslot[i].npages =3D=3D 0) + continue; + + if (gfn >=3D vm->memslot[i].base_gfn && + gfn < vm->memslot[i].base_gfn + vm->memslot[i].npages) + return i; + } + + return -EFAULT; +} + /** * register_memslot_addr_range() - Register memory region to GenieZone * @gzvm: Pointer to struct gzvm @@ -60,7 +85,10 @@ register_memslot_addr_range(struct gzvm *gzvm, struct gz= vm_memslot *memslot) } =20 free_pages_exact(region, buf_size); - return 0; + + if (gzvm->mem_alloc_mode =3D=3D GZVM_DEMAND_PAGING) + return 0; + return gzvm_vm_populate_mem_region(gzvm, memslot->slot_id); } =20 /** @@ -349,6 +377,22 @@ static const struct file_operations gzvm_vm_fops =3D { .unlocked_ioctl =3D gzvm_vm_ioctl, }; =20 +static int setup_mem_alloc_mode(struct gzvm *vm) +{ + int ret; + struct gzvm_enable_cap cap =3D {0}; + + cap.cap =3D GZVM_CAP_ENABLE_DEMAND_PAGING; + + ret =3D gzvm_vm_ioctl_enable_cap(vm, &cap, NULL); + if (!ret) + vm->mem_alloc_mode =3D GZVM_DEMAND_PAGING; + else + vm->mem_alloc_mode =3D GZVM_FULLY_POPULATED; + + return 0; +} + static struct gzvm *gzvm_create_vm(struct gzvm_driver *drv, unsigned long = vm_type) { int ret; @@ -385,6 +429,8 @@ static struct gzvm *gzvm_create_vm(struct gzvm_driver *= drv, unsigned long vm_typ return ERR_PTR(ret); } =20 + setup_mem_alloc_mode(gzvm); + mutex_lock(&gzvm_list_lock); list_add(&gzvm->vm_list, &gzvm_list); mutex_unlock(&gzvm_list_lock); diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 920af91ea576..1a722121ff82 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -45,6 +45,7 @@ struct gzvm_driver { */ #define NO_ERROR (0) #define ERR_NO_MEMORY (-5) +#define ERR_INVALID_ARGS (-8) #define ERR_NOT_SUPPORTED (-24) #define ERR_NOT_IMPLEMENTED (-27) #define ERR_FAULT (-40) @@ -59,6 +60,11 @@ struct gzvm_driver { =20 #define GZVM_VCPU_RUN_MAP_SIZE (PAGE_SIZE * 2) =20 +enum gzvm_demand_paging_mode { + GZVM_FULLY_POPULATED =3D 0, + GZVM_DEMAND_PAGING =3D 1, +}; + /** * struct mem_region_addr_range: identical to ffa memory constituent * @address: the base IPA of the constituent memory region, aligned to 4 k= iB @@ -137,6 +143,7 @@ struct gzvm_pinned_page { * @irq_lock: lock for irq injection * @pinned_pages: use rb-tree to record pin/unpin page * @mem_lock: lock for memory operations + * @mem_alloc_mode: memory allocation mode - fully allocated or demand pag= ing */ struct gzvm { struct gzvm_driver *gzvm_drv; @@ -161,6 +168,7 @@ struct gzvm { struct hlist_head irq_ack_notifier_list; struct srcu_struct irq_srcu; struct mutex irq_lock; + u32 mem_alloc_mode; =20 struct rb_root pinned_pages; struct mutex mem_lock; @@ -183,6 +191,8 @@ int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, int gzvm_arch_check_extension(struct gzvm *gzvm, __u64 cap, void __user *a= rgp); int gzvm_arch_create_vm(unsigned long vm_type); int gzvm_arch_destroy_vm(u16 vm_id); +int gzvm_arch_map_guest(u16 vm_id, int memslot_id, u64 pfn, u64 gfn, + u64 nr_pages); int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, struct gzvm_enable_cap *cap, void __user *argp); @@ -201,6 +211,10 @@ int gzvm_arch_vcpu_run(struct gzvm_vcpu *vcpu, __u64 *= exit_reason); int gzvm_arch_destroy_vcpu(u16 vm_id, int vcpuid); int gzvm_arch_inform_exit(u16 vm_id); =20 +int gzvm_find_memslot(struct gzvm *vm, u64 gpa); +int gzvm_handle_page_fault(struct gzvm_vcpu *vcpu); +bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu); + int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev= ); int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, u32 irq, bool level); diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 7aec4adf2206..61a7a87b3d23 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -18,6 +18,7 @@ =20 #define GZVM_CAP_VM_GPA_SIZE 0xa5 #define GZVM_CAP_PROTECTED_VM 0xffbadab1 +#define GZVM_CAP_ENABLE_DEMAND_PAGING 0x9202 =20 /* sub-commands put in args[0] for GZVM_CAP_PROTECTED_VM */ #define GZVM_CAP_PVM_SET_PVMFW_GPA 0 @@ -186,6 +187,12 @@ enum { GZVM_EXIT_GZ =3D 0x9292000a, }; =20 +/* exception definitions of GZVM_EXIT_EXCEPTION */ +enum { + GZVM_EXCEPTION_UNKNOWN =3D 0x0, + GZVM_EXCEPTION_PAGE_FAULT =3D 0x1, +}; + /** * struct gzvm_vcpu_run: Same purpose as kvm_run, this struct is * shared between userspace, kernel and @@ -250,6 +257,12 @@ struct gzvm_vcpu_run { __u32 exception; /* Exception error codes */ __u32 error_code; + /* Fault GPA (guest physical address or IPA in ARM) */ + __u64 fault_gpa; + /* Future-proof reservation and reset to zero in hypervisor. + * Fill up to the union size, 256 bytes. + */ + __u64 reserved[30]; } exception; /* GZVM_EXIT_HYPERCALL */ struct { --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 011711F8F1B; Thu, 14 Nov 2024 10:08:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578904; cv=none; b=fdFp2BmSlJceemf3Wm0HODdTczX5/+BV8IsA8PT1RqDdzT5rP4+/6VBQLxTejSJQBvPnjsG1Ra5Fd24rw2Ol5N2g6XmswJ1DgnuRklssmbXOxiYJ7fcIFnq7f7CIi0KXbHfMtUQ9BSZwt8kOZPIKW+LrcHB/uP98jiUl1Oyp9xU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578904; c=relaxed/simple; bh=4Lglm5d2xxsHsbj3pbQnida7I1cYcwnsAqZ6hL50FYQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=a8/KCtUlQQflZsMCNaMBTdx+GpVI9Z/BOMqpRM2HP5y+mxo5wLw8aPBoWzRBbqmgDiC5pb7orJYShT8+oT72S23laGqtGq4gNsfGdawGnyL0p0Lb5Stl5or9b0CLFt6s7lCoPhJuR5VXikOYyeKYgfIzAo1ixMkT7w85fyCUzIc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=VOWcf5a1; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="VOWcf5a1" X-UUID: 582c8150a27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=HgxzXXBoyvOV03PMO3sb/CWleSew5G/aZSc/s+MAXMk=; b=VOWcf5a1I5Reiu7W6TUCkMZ1X+V42N1Dn6IoNABpcyaXpYid6fpOP/vzsmlc9UU2cLx31pOcBcsBIt8S+Isxc0wYG13y/rptp4bJMnNLSoEJyYwiQJIyt6n5j3RJNfquMW7zzNA/Sw4nKWTGh4de89Xv5UzyGjr20XgWRdx2YO8=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:921921d3-862f-4961-8a5f-2082d75fbbae,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:613fa25c-f18b-4d56-b49c-93279ee09144,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 582c8150a27011efbd192953cf12861f-20241114 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1861760093; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n2.mediatek.inc (172.21.101.108) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:05 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:05 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 17/25] virt: geniezone: Add block-based demand paging support Date: Thu, 14 Nov 2024 18:07:54 +0800 Message-ID: <20241114100802.4116-18-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yingshiuan Pan To balance memory usage and performance, GenieZone supports larger granularity demand paging, called block-based demand paging. Gzvm driver uses enable_cap to query the hypervisor if it supports block-based demand paging and the given granularity or not. Meanwhile, the gzvm driver allocates a shared buffer for storing the physical pages later. If the hypervisor supports, every time the gzvm driver handles guest page faults, it allocates more memory in advance (default: 2MB) for demand paging. And fills those physical pages into the allocated shared memory, then calls the hypervisor to map to guest's memory. The physical pages allocated for block-based demand paging is not necessary to be contiguous because in many cases, 2MB block is not followed. 1st, the memory is allocated because of VMM's page fault (VMM loads kernel image to guest memory before running). In this case, the page is allocated by the host kernel and using PAGE_SIZE. 2nd is that guest may return memory to host via ballooning and that is still 4KB (or PAGE_SIZE) granularity. Therefore, we do not have to allocate physically contiguous 2MB pages. Signed-off-by: Yingshiuan Pan Co-developed-by: Kevenny Hsieh Signed-off-by: Kevenny Hsieh Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 2 + arch/arm64/geniezone/vm.c | 47 ++++++++++++- drivers/virt/geniezone/gzvm_main.c | 91 +++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_mmu.c | 58 +++++++++++++++- drivers/virt/geniezone/gzvm_vm.c | 56 ++++++++++++++- include/linux/soc/mediatek/gzvm_drv.h | 22 +++++- include/uapi/linux/gzvm.h | 3 + 7 files changed, 272 insertions(+), 7 deletions(-) diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 928191e3cdb2..8a082ba808a4 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -25,6 +25,7 @@ enum { GZVM_FUNC_MEMREGION_PURPOSE =3D 15, GZVM_FUNC_SET_DTB_CONFIG =3D 16, GZVM_FUNC_MAP_GUEST =3D 17, + GZVM_FUNC_MAP_GUEST_BLOCK =3D 18, NR_GZVM_FUNC, }; =20 @@ -50,6 +51,7 @@ enum { #define MT_HVC_GZVM_MEMREGION_PURPOSE GZVM_HCALL_ID(GZVM_FUNC_MEMREGION_PU= RPOSE) #define MT_HVC_GZVM_SET_DTB_CONFIG GZVM_HCALL_ID(GZVM_FUNC_SET_DTB_CONFIG) #define MT_HVC_GZVM_MAP_GUEST GZVM_HCALL_ID(GZVM_FUNC_MAP_GUEST) +#define MT_HVC_GZVM_MAP_GUEST_BLOCK GZVM_HCALL_ID(GZVM_FUNC_MAP_GUEST_BLOC= K) =20 #define GIC_V3_NR_LRS 16 =20 diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 53e487912d2c..91c6e4e2caf2 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -184,6 +184,35 @@ static int gzvm_vm_arch_enable_cap(struct gzvm *gzvm, res); } =20 +static int gzvm_arch_enable_cap(struct gzvm_enable_cap *cap, + struct arm_smccc_res *res) +{ + return gzvm_hypcall_wrapper(MT_HVC_GZVM_ENABLE_CAP, 0, + cap->cap, cap->args[0], cap->args[1], + cap->args[2], cap->args[3], cap->args[4], + res); +} + +int gzvm_arch_query_hyp_batch_pages(struct gzvm_enable_cap *cap, + void __user *argp) +{ + struct arm_smccc_res res =3D {0}; + int ret; + + ret =3D gzvm_arch_enable_cap(cap, &res); + + if (ret) + return ret; + + if (res.a1 =3D=3D 0 || + GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE % (PAGE_SIZE * res.a1) !=3D 0) + return -EFAULT; + + cap->args[0] =3D res.a1; + + return ret; +} + /** * gzvm_vm_ioctl_get_pvmfw_size() - Get pvmfw size from hypervisor, return * in x1, and return to userspace in args @@ -358,10 +387,11 @@ static int gzvm_vm_ioctl_cap_pvm(struct gzvm *gzvm, fallthrough; case GZVM_CAP_PVM_SET_PROTECTED_VM: /* - * To improve performance for protected VM, we have to populate VM's mem= ory - * before VM booting + * If the hypervisor doesn't support block-based demand paging, we + * populate memory in advance to improve performance for protected VM. */ - populate_all_mem_regions(gzvm); + if (gzvm->demand_page_gran =3D=3D PAGE_SIZE) + populate_all_mem_regions(gzvm); ret =3D gzvm_vm_arch_enable_cap(gzvm, cap, &res); return ret; case GZVM_CAP_PVM_GET_PVMFW_SIZE: @@ -385,7 +415,10 @@ int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, case GZVM_CAP_PROTECTED_VM: ret =3D gzvm_vm_ioctl_cap_pvm(gzvm, cap, argp); return ret; + case GZVM_CAP_ENABLE_DEMAND_PAGING: + fallthrough; + case GZVM_CAP_BLOCK_BASED_DEMAND_PAGING: ret =3D gzvm_vm_arch_enable_cap(gzvm, cap, &res); return ret; default: @@ -403,3 +436,11 @@ int gzvm_arch_map_guest(u16 vm_id, int memslot_id, u64= pfn, u64 gfn, return gzvm_hypcall_wrapper(MT_HVC_GZVM_MAP_GUEST, vm_id, memslot_id, pfn, gfn, nr_pages, 0, 0, &res); } + +int gzvm_arch_map_guest_block(u16 vm_id, int memslot_id, u64 gfn, u64 nr_p= ages) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_MAP_GUEST_BLOCK, vm_id, + memslot_id, gfn, nr_pages, 0, 0, 0, &res); +} diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index 6142d1d792a4..c975912cd594 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -6,10 +6,12 @@ #include #include #include +#include #include #include #include #include +#include #include =20 static struct gzvm_driver gzvm_drv =3D { @@ -20,6 +22,64 @@ static struct gzvm_driver gzvm_drv =3D { }, }; =20 +static ssize_t demand_paging_batch_pages_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", gzvm_drv.demand_paging_batch_pages); +} + +static ssize_t demand_paging_batch_pages_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int ret; + u32 temp; + + ret =3D kstrtoint(buf, 10, &temp); + if (ret < 0) + return ret; + + if (temp =3D=3D 0 || (PMD_SIZE % (PAGE_SIZE * temp)) !=3D 0) + return -EINVAL; + + gzvm_drv.demand_paging_batch_pages =3D temp; + + return count; +} + +/* /sys/kernel/gzvm/demand_paging_batch_pages */ +static struct kobj_attribute demand_paging_batch_pages_attr =3D { + .attr =3D { + .name =3D "demand_paging_batch_pages", + .mode =3D 0660, + }, + .show =3D demand_paging_batch_pages_show, + .store =3D demand_paging_batch_pages_store, +}; + +static int gzvm_drv_sysfs_init(void) +{ + int ret =3D 0; + + gzvm_drv.sysfs_root_dir =3D kobject_create_and_add("gzvm", kernel_kobj); + + if (!gzvm_drv.sysfs_root_dir) + return -ENOMEM; + + ret =3D sysfs_create_file(gzvm_drv.sysfs_root_dir, + &demand_paging_batch_pages_attr.attr); + if (ret) + pr_debug("failed to create demand_batch_pages in /sys/kernel/gzvm\n"); + + return ret; +} + +static void gzvm_drv_sysfs_exit(void) +{ + kobject_del(gzvm_drv.sysfs_root_dir); +} + /** * gzvm_err_to_errno() - Convert geniezone return value to standard errno * @@ -119,6 +179,27 @@ static struct miscdevice gzvm_dev =3D { .fops =3D &gzvm_chardev_ops, }; =20 +static int gzvm_query_hyp_batch_pages(void) +{ + struct gzvm_enable_cap cap =3D {0}; + int ret; + + gzvm_drv.demand_paging_batch_pages =3D GZVM_DRV_DEMAND_PAGING_BATCH_PAGES; + cap.cap =3D GZVM_CAP_QUERY_HYP_BATCH_PAGES; + + ret =3D gzvm_arch_query_hyp_batch_pages(&cap, NULL); + if (!ret) + gzvm_drv.demand_paging_batch_pages =3D cap.args[0]; + + /* + * We have initialized demand_paging_batch_pages, and to maintain + * compatibility with older GZ version, we can ignore the return value. + */ + if (ret =3D=3D -EINVAL) + return 0; + return ret; +} + static int gzvm_drv_probe(struct platform_device *pdev) { int ret; @@ -139,6 +220,15 @@ static int gzvm_drv_probe(struct platform_device *pdev) ret =3D gzvm_drv_irqfd_init(); if (ret) return ret; + + ret =3D gzvm_drv_sysfs_init(); + if (ret) + return ret; + + ret =3D gzvm_query_hyp_batch_pages(); + if (ret) + return ret; + return 0; } =20 @@ -146,6 +236,7 @@ static void gzvm_drv_remove(struct platform_device *pde= v) { gzvm_drv_irqfd_exit(); misc_deregister(&gzvm_dev); + gzvm_drv_sysfs_exit(); } =20 static const struct of_device_id gzvm_of_match[] =3D { diff --git a/drivers/virt/geniezone/gzvm_mmu.c b/drivers/virt/geniezone/gzv= m_mmu.c index dcc8c4d7be83..a5aa296ca790 100644 --- a/drivers/virt/geniezone/gzvm_mmu.c +++ b/drivers/virt/geniezone/gzvm_mmu.c @@ -114,6 +114,59 @@ static int handle_single_demand_page(struct gzvm *vm, = int memslot_id, u64 gfn) ret =3D gzvm_arch_map_guest(vm->vm_id, memslot_id, pfn, gfn, 1); if (unlikely(ret)) return -EFAULT; + + return ret; +} + +static int handle_block_demand_page(struct gzvm *vm, int memslot_id, u64 g= fn) +{ + u32 nr_entries_all =3D GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE / PAGE_SIZE; + u32 nr_entries =3D vm->gzvm_drv->demand_paging_batch_pages; + struct gzvm_memslot *memslot =3D &vm->memslot[memslot_id]; + u64 start_gfn =3D ALIGN_DOWN(gfn, nr_entries_all); + u32 total_pages =3D memslot->npages; + u64 base_gfn =3D memslot->base_gfn; + u64 pfn, __gfn; + int ret, i; + + if (start_gfn < base_gfn) + start_gfn =3D base_gfn; + + u64 end_gfn =3D start_gfn + nr_entries_all; + + if (start_gfn + nr_entries_all > base_gfn + total_pages) + end_gfn =3D base_gfn + total_pages; + + mutex_lock(&vm->demand_paging_lock); + for (; start_gfn < end_gfn; start_gfn +=3D nr_entries) { + /* + * If the start/end gfn of this demand paging block is outside the + * memory region of memslot, adjust the start_gfn/nr_entries. + */ + if (start_gfn + nr_entries > base_gfn + total_pages) + nr_entries =3D base_gfn + total_pages - start_gfn; + + for (i =3D 0, __gfn =3D start_gfn; i < nr_entries; i++, __gfn++) { + ret =3D gzvm_vm_allocate_guest_page(vm, memslot, __gfn, + &pfn); + if (unlikely(ret)) { + pr_notice("VM-%u failed to allocate page for GFN 0x%llx (%d)\n", + vm->vm_id, __gfn, ret); + ret =3D -ERR_FAULT; + goto err_unlock; + } + vm->demand_page_buffer[i] =3D pfn; + } + + ret =3D gzvm_arch_map_guest_block(vm->vm_id, memslot_id, + start_gfn, nr_entries); + if (unlikely(ret)) { + ret =3D -EFAULT; + goto err_unlock; + } + } +err_unlock: + mutex_unlock(&vm->demand_paging_lock); return ret; } =20 @@ -140,5 +193,8 @@ int gzvm_handle_page_fault(struct gzvm_vcpu *vcpu) if (unlikely(vm->mem_alloc_mode =3D=3D GZVM_FULLY_POPULATED)) return -EFAULT; =20 - return handle_single_demand_page(vm, memslot_id, gfn); + if (vm->demand_page_gran =3D=3D PAGE_SIZE) + return handle_single_demand_page(vm, memslot_id, gfn); + else + return handle_block_demand_page(vm, memslot_id, gfn); } diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index f63487809148..e44ee2d04ed8 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -344,6 +344,8 @@ static void gzvm_destroy_all_ppage(struct gzvm *gzvm) =20 static void gzvm_destroy_vm(struct gzvm *gzvm) { + size_t allocated_size; + pr_debug("VM-%u is going to be destroyed\n", gzvm->vm_id); =20 mutex_lock(&gzvm->lock); @@ -356,6 +358,12 @@ static void gzvm_destroy_vm(struct gzvm *gzvm) list_del(&gzvm->vm_list); mutex_unlock(&gzvm_list_lock); =20 + if (gzvm->demand_page_buffer) { + allocated_size =3D GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE / PAGE_SIZE * + sizeof(u64); + free_pages_exact(gzvm->demand_page_buffer, allocated_size); + } + mutex_unlock(&gzvm->lock); =20 /* No need to lock here becauese it's single-threaded execution */ @@ -377,6 +385,48 @@ static const struct file_operations gzvm_vm_fops =3D { .unlocked_ioctl =3D gzvm_vm_ioctl, }; =20 +/** + * setup_vm_demand_paging() - Query hypervisor suitable demand page size a= nd set + * @vm: gzvm instance for setting up demand page size + * + * Return: void + */ +static void setup_vm_demand_paging(struct gzvm *vm) +{ + struct gzvm_enable_cap cap =3D {0}; + u32 buf_size; + void *buffer; + int ret; + + buf_size =3D (GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE / PAGE_SIZE) * + sizeof(pte_t); + mutex_init(&vm->demand_paging_lock); + buffer =3D alloc_pages_exact(buf_size, GFP_KERNEL); + if (!buffer) { + /* Fall back to use default page size for demand paging */ + vm->demand_page_gran =3D PAGE_SIZE; + vm->demand_page_buffer =3D NULL; + return; + } + + cap.cap =3D GZVM_CAP_BLOCK_BASED_DEMAND_PAGING; + cap.args[0] =3D GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE; + cap.args[1] =3D (__u64)virt_to_phys(buffer); + /* demand_page_buffer is freed when destroy VM */ + vm->demand_page_buffer =3D buffer; + + ret =3D gzvm_vm_ioctl_enable_cap(vm, &cap, NULL); + if (ret =3D=3D 0) { + vm->demand_page_gran =3D GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE; + /* freed when destroy vm */ + vm->demand_page_buffer =3D buffer; + } else { + vm->demand_page_gran =3D PAGE_SIZE; + vm->demand_page_buffer =3D NULL; + free_pages_exact(buffer, buf_size); + } +} + static int setup_mem_alloc_mode(struct gzvm *vm) { int ret; @@ -385,10 +435,12 @@ static int setup_mem_alloc_mode(struct gzvm *vm) cap.cap =3D GZVM_CAP_ENABLE_DEMAND_PAGING; =20 ret =3D gzvm_vm_ioctl_enable_cap(vm, &cap, NULL); - if (!ret) + if (!ret) { vm->mem_alloc_mode =3D GZVM_DEMAND_PAGING; - else + setup_vm_demand_paging(vm); + } else { vm->mem_alloc_mode =3D GZVM_FULLY_POPULATED; + } =20 return 0; } diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 1a722121ff82..14c1adfbb204 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -27,6 +27,9 @@ struct gzvm_version { struct gzvm_driver { struct gzvm_version hyp_version; struct gzvm_version drv_version; + + struct kobject *sysfs_root_dir; + u32 demand_paging_batch_pages; }; =20 /* @@ -58,7 +61,11 @@ struct gzvm_driver { #define GZVM_MAX_VCPUS 8 #define GZVM_MAX_MEM_REGION 10 =20 -#define GZVM_VCPU_RUN_MAP_SIZE (PAGE_SIZE * 2) +#define GZVM_VCPU_RUN_MAP_SIZE (PAGE_SIZE * 2) + +#define GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE (PMD_SIZE) /* 2MB */ +#define GZVM_DRV_DEMAND_PAGING_BATCH_PAGES \ + (GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE / PAGE_SIZE) =20 enum gzvm_demand_paging_mode { GZVM_FULLY_POPULATED =3D 0, @@ -144,6 +151,11 @@ struct gzvm_pinned_page { * @pinned_pages: use rb-tree to record pin/unpin page * @mem_lock: lock for memory operations * @mem_alloc_mode: memory allocation mode - fully allocated or demand pag= ing + * @demand_page_gran: demand page granularity: how much memory we allocate= for + * VM in a single page fault + * @demand_page_buffer: the mailbox for transferring large portion pages + * @demand_paging_lock: lock for preventing multiple cpu using the same de= mand + * page mailbox at the same time */ struct gzvm { struct gzvm_driver *gzvm_drv; @@ -172,6 +184,10 @@ struct gzvm { =20 struct rb_root pinned_pages; struct mutex mem_lock; + + u32 demand_page_gran; + u64 *demand_page_buffer; + struct mutex demand_paging_lock; }; =20 long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args); @@ -186,6 +202,9 @@ void gzvm_destroy_vcpus(struct gzvm *gzvm); /* arch-dependant functions */ int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version); +int gzvm_arch_query_hyp_batch_pages(struct gzvm_enable_cap *cap, + void __user *argp); + int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, phys_addr_t region); int gzvm_arch_check_extension(struct gzvm *gzvm, __u64 cap, void __user *a= rgp); @@ -193,6 +212,7 @@ int gzvm_arch_create_vm(unsigned long vm_type); int gzvm_arch_destroy_vm(u16 vm_id); int gzvm_arch_map_guest(u16 vm_id, int memslot_id, u64 pfn, u64 gfn, u64 nr_pages); +int gzvm_arch_map_guest_block(u16 vm_id, int memslot_id, u64 gfn, u64 nr_p= ages); int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, struct gzvm_enable_cap *cap, void __user *argp); diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 61a7a87b3d23..5e21d64a2f4f 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -18,7 +18,10 @@ =20 #define GZVM_CAP_VM_GPA_SIZE 0xa5 #define GZVM_CAP_PROTECTED_VM 0xffbadab1 +/* query hypervisor supported block-based demand page */ +#define GZVM_CAP_BLOCK_BASED_DEMAND_PAGING 0x9201 #define GZVM_CAP_ENABLE_DEMAND_PAGING 0x9202 +#define GZVM_CAP_QUERY_HYP_BATCH_PAGES 0x9204 =20 /* sub-commands put in args[0] for GZVM_CAP_PROTECTED_VM */ #define GZVM_CAP_PVM_SET_PVMFW_GPA 0 --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87E0D1F9424; Thu, 14 Nov 2024 10:08:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578903; cv=none; b=thbmGcE5rXqY6kikdP03xk94Mzi907eqc3fzwJA2JoqxtQE207za9m/mgBII8t1NuEqijvEy9HI+wkTw1jQocIetibXwXzbN/QIO9lkseQIinKFdnmeuuat7EI4TVAJBC/laQNnlnvL86IsHTxFicDnSMI/TlYjAOm1ROtHcnA8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578903; c=relaxed/simple; bh=QFLs+HISQbemMjLoBmvybAt7pFNLshpFKDMZVikH+s0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=mAh4jUWVb0GzyX+gFHgPzh9RKpGh5KBPgH7677HolmbmMVTupPbLEj4JFoyGA/D1ldA4VrxJ1PMSz38wThvFgxI2sAxFKkufCbYsDR2IUL+m+7o1IS239r005TV0JNC7bK0BLEDR59o0H7a5fspYirp/ioFExkAgrXQiASneFAw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=pztUO89i; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="pztUO89i" X-UUID: 58446dd8a27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=rfrSg5TXYgeImzWP2C0/VdIyU5X7aar/KANT6p7ZSdc=; b=pztUO89iBSnWzS0Gnp/27y7cJvh65sIMPc0t258qn6kExuRRmyMxnwJsd18sZb1QFtqWPklBHSA02pGwDs7OGmv6b2SAnw7HtVLqVgx25aWq4/NWhEWJTlcH5iMuE7z18ytbhDDK5aDnrEmJtecPf97WSq2Vl0od02PqoGou258=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:5132c685-0a47-471f-ab0f-4c10c206d203,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:ff5e0c4f-a2ae-4b53-acd4-c3dc8f449198,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 58446dd8a27011efbd192953cf12861f-20241114 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 16869970; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 02:08:05 -0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:05 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 18/25] virt: geniezone: Add memory relinquish support Date: Thu, 14 Nov 2024 18:07:55 +0800 Message-ID: <20241114100802.4116-19-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jerry Wang Unpin the pages when VM relinquish the pages or is destroyed. Signed-off-by: Jerry Wang Co-developed-by: Yingshiuan Pan Signed-off-by: Yingshiuan Pan Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- drivers/virt/geniezone/gzvm_exception.c | 23 ++++++++++++ drivers/virt/geniezone/gzvm_mmu.c | 49 +++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_vcpu.c | 6 ++- include/linux/soc/mediatek/gzvm_drv.h | 2 + include/uapi/linux/gzvm.h | 5 +++ 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/drivers/virt/geniezone/gzvm_exception.c b/drivers/virt/geniezo= ne/gzvm_exception.c index 2f5c05045e61..cdfc99d24ded 100644 --- a/drivers/virt/geniezone/gzvm_exception.c +++ b/drivers/virt/geniezone/gzvm_exception.c @@ -37,3 +37,26 @@ bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu) else return false; } + +/** + * gzvm_handle_guest_hvc() - Handle guest hvc + * @vcpu: Pointer to struct gzvm_vcpu struct + * Return: + * * true - This hvc has been processed, no need to back to VMM. + * * false - This hvc has not been processed, require userspace. + */ +bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu) +{ + unsigned long ipa; + int ret; + + switch (vcpu->run->hypercall.args[0]) { + case GZVM_HVC_MEM_RELINQUISH: + ipa =3D vcpu->run->hypercall.args[1]; + ret =3D gzvm_handle_relinquish(vcpu, ipa); + return (ret =3D=3D 0) ? true : false; + default: + break; + } + return false; +} diff --git a/drivers/virt/geniezone/gzvm_mmu.c b/drivers/virt/geniezone/gzv= m_mmu.c index a5aa296ca790..25b13665617d 100644 --- a/drivers/virt/geniezone/gzvm_mmu.c +++ b/drivers/virt/geniezone/gzvm_mmu.c @@ -29,6 +29,36 @@ static int gzvm_insert_ppage(struct gzvm *vm, struct gzv= m_pinned_page *ppage) return 0; } =20 +static int rb_ppage_cmp(const void *key, const struct rb_node *node) +{ + struct gzvm_pinned_page *p =3D container_of(node, + struct gzvm_pinned_page, + node); + phys_addr_t ipa =3D (phys_addr_t)key; + + return (ipa < p->ipa) ? -1 : (ipa > p->ipa); +} + +/* Invoker of this function is responsible for locking */ +static int gzvm_remove_ppage(struct gzvm *vm, phys_addr_t ipa) +{ + struct gzvm_pinned_page *ppage; + struct rb_node *node; + + node =3D rb_find((void *)ipa, &vm->pinned_pages, rb_ppage_cmp); + + if (node) + rb_erase(node, &vm->pinned_pages); + else + return 0; + + ppage =3D container_of(node, struct gzvm_pinned_page, node); + unpin_user_pages_dirty_lock(&ppage->page, 1, true); + kfree(ppage); + + return 0; +} + static int pin_one_page(struct gzvm *vm, unsigned long hva, u64 gpa, struct page **out_page) { @@ -77,6 +107,25 @@ static int pin_one_page(struct gzvm *vm, unsigned long = hva, u64 gpa, return ret; } =20 +/** + * gzvm_handle_relinquish() - Handle memory relinquish request from hyperv= isor + * + * @vcpu: Pointer to struct gzvm_vcpu_run in userspace + * @ipa: Start address(gpa) of a reclaimed page + * + * Return: Always return 0 because there are no cases of failure + */ +int gzvm_handle_relinquish(struct gzvm_vcpu *vcpu, phys_addr_t ipa) +{ + struct gzvm *vm =3D vcpu->gzvm; + + mutex_lock(&vm->mem_lock); + gzvm_remove_ppage(vm, ipa); + mutex_unlock(&vm->mem_lock); + + return 0; +} + int gzvm_vm_allocate_guest_page(struct gzvm *vm, struct gzvm_memslot *slot, u64 gfn, u64 *pfn) { diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index 3f6bffbafc7a..b0dc3e4f47d7 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -112,12 +112,14 @@ static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, voi= d __user *argp) * it's geniezone's responsibility to fill corresponding data * structure */ + case GZVM_EXIT_HYPERCALL: + if (!gzvm_handle_guest_hvc(vcpu)) + need_userspace =3D true; + break; case GZVM_EXIT_EXCEPTION: if (!gzvm_handle_guest_exception(vcpu)) need_userspace =3D true; break; - case GZVM_EXIT_HYPERCALL: - fallthrough; case GZVM_EXIT_DEBUG: fallthrough; case GZVM_EXIT_FAIL_ENTRY: diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 14c1adfbb204..7065ec36f190 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -234,6 +234,8 @@ int gzvm_arch_inform_exit(u16 vm_id); int gzvm_find_memslot(struct gzvm *vm, u64 gpa); int gzvm_handle_page_fault(struct gzvm_vcpu *vcpu); bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu); +int gzvm_handle_relinquish(struct gzvm_vcpu *vcpu, phys_addr_t ipa); +bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu); =20 int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev= ); int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 5e21d64a2f4f..f23266055140 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -196,6 +196,11 @@ enum { GZVM_EXCEPTION_PAGE_FAULT =3D 0x1, }; =20 +/* hypercall definitions of GZVM_EXIT_HYPERCALL */ +enum { + GZVM_HVC_MEM_RELINQUISH =3D 0xc6000009, +}; + /** * struct gzvm_vcpu_run: Same purpose as kvm_run, this struct is * shared between userspace, kernel and --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B2DC91F709C; Thu, 14 Nov 2024 10:08:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578899; cv=none; b=fgaWDwP9FXi8kJg9gaqLBpNc/O8uBJDhDiAYx8DZIqa6f66SQ64cst46KB8t76SbY2uty3j3EbbkM2YJEbX/9ZfFbFBoUBuMWTjqJnu4AMyOoVf7u0BmMoBi0m6gh0skCq9JU+M/xU29MgN+5olwr+0QgwyoaJUFhwg8d4/BNZo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578899; c=relaxed/simple; bh=ppWa141RBzp+4xVKTTHSWtjnUrVY1afE9Qcv3MtiL2w=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qtUds9pAs8KM+UaHmAVZp6GO0LdsRMATzE7A6vlssr4PowCrKwFQ3AB85WwOBNc9hUxO5Dkp71sGd4/lmthaOtLqgR3JaIt+1++8RI0Zp1c1XXNBkYc04t7YswsAhkwL6YjxNexfIaNNBKVvTo12RDTl6ucGQNEBHGfIubzmttU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=T0ExJK09; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="T0ExJK09" X-UUID: 58488954a27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=pSFE6NnOIVxS5FA5GGo2UNMU8jZDgYiySjxlzLv3y7c=; b=T0ExJK099bBt7JiiAxj15xslb6W+0PDuk8Ki1Sz4cvGPByN97sWPZuaz7aZTN2HvdqlZEuiBXoSsE1q9BfCiPd9q/KlT1erfspX8+SFSiQBJ7fxYj2PR3DoA1Z3pAW6WkcHf+KRPRTCJX4c0VqCqaH9e2y2ioqv0SMnZaxGOOSc=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:cf8dac3f-4acf-4b49-bd9c-7f00f873925d,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:015f0c4f-a2ae-4b53-acd4-c3dc8f449198,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 58488954a27011efbd192953cf12861f-20241114 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 549886182; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 02:08:06 -0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:06 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 19/25] virt: geniezone: Provide individual VM memory statistics within debugfs Date: Thu, 14 Nov 2024 18:07:56 +0800 Message-ID: <20241114100802.4116-20-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jerry Wang Created a dedicated per-VM debugfs folder under gzvm, providing user-level programs with easy access to per-VM memory statistics for debugging and profiling purposes. This enables users to effectively analyze and optimize the memory usage of individual virtual machines. Two types of information can be obtained: `cat /sys/kernel/debug/gzvm/-/protected_hyp_mem` shows memory used by the hypervisor and the size of the stage 2 table in bytes. `cat /sys/kernel/debug/gzvm/-/protected_shared_mem` gives memory used by the shared resources of the guest and host in bytes. For example: console:/ # cat /sys/kernel/debug/gzvm/3417-15/protected_hyp_mem 180328 console:/ # cat /sys/kernel/debug/gzvm/3417-15/protected_shared_mem 262144 console:/ # More stats will be added in the future. Signed-off-by: Jerry Wang Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 2 + arch/arm64/geniezone/vm.c | 13 +++ drivers/virt/geniezone/gzvm_main.c | 25 ++++++ drivers/virt/geniezone/gzvm_vm.c | 115 ++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 16 ++++ 5 files changed, 171 insertions(+) diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 8a082ba808a4..192d023722e5 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -26,6 +26,7 @@ enum { GZVM_FUNC_SET_DTB_CONFIG =3D 16, GZVM_FUNC_MAP_GUEST =3D 17, GZVM_FUNC_MAP_GUEST_BLOCK =3D 18, + GZVM_FUNC_GET_STATISTICS =3D 19, NR_GZVM_FUNC, }; =20 @@ -52,6 +53,7 @@ enum { #define MT_HVC_GZVM_SET_DTB_CONFIG GZVM_HCALL_ID(GZVM_FUNC_SET_DTB_CONFIG) #define MT_HVC_GZVM_MAP_GUEST GZVM_HCALL_ID(GZVM_FUNC_MAP_GUEST) #define MT_HVC_GZVM_MAP_GUEST_BLOCK GZVM_HCALL_ID(GZVM_FUNC_MAP_GUEST_BLOC= K) +#define MT_HVC_GZVM_GET_STATISTICS GZVM_HCALL_ID(GZVM_FUNC_GET_STATISTICS) =20 #define GIC_V3_NR_LRS 16 =20 diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 91c6e4e2caf2..0350d9444c18 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -444,3 +444,16 @@ int gzvm_arch_map_guest_block(u16 vm_id, int memslot_i= d, u64 gfn, u64 nr_pages) return gzvm_hypcall_wrapper(MT_HVC_GZVM_MAP_GUEST_BLOCK, vm_id, memslot_id, gfn, nr_pages, 0, 0, 0, &res); } + +int gzvm_arch_get_statistics(struct gzvm *gzvm) +{ + struct arm_smccc_res res; + int ret; + + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_GET_STATISTICS, gzvm->vm_id, + 0, 0, 0, 0, 0, 0, &res); + + gzvm->stat.protected_hyp_mem =3D ((ret =3D=3D 0) ? res.a1 : 0); + gzvm->stat.protected_shared_mem =3D ((ret =3D=3D 0) ? res.a2 : 0); + return ret; +} diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index c975912cd594..1816eecfcefb 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -3,6 +3,7 @@ * Copyright (c) 2023 MediaTek Inc. */ =20 +#include #include #include #include @@ -80,6 +81,25 @@ static void gzvm_drv_sysfs_exit(void) kobject_del(gzvm_drv.sysfs_root_dir); } =20 +static int gzvm_drv_debug_init(void) +{ + if (!debugfs_initialized()) { + pr_warn("debugfs not initialized!\n"); + return 0; + } + + gzvm_drv.gzvm_debugfs_dir =3D debugfs_create_dir("gzvm", NULL); + if (!gzvm_drv.gzvm_debugfs_dir) + return -ENOMEM; + + return 0; +} + +static void gzvm_drv_debug_exit(void) +{ + debugfs_remove_recursive(gzvm_drv.gzvm_debugfs_dir); +} + /** * gzvm_err_to_errno() - Convert geniezone return value to standard errno * @@ -221,6 +241,10 @@ static int gzvm_drv_probe(struct platform_device *pdev) if (ret) return ret; =20 + ret =3D gzvm_drv_debug_init(); + if (ret) + return ret; + ret =3D gzvm_drv_sysfs_init(); if (ret) return ret; @@ -236,6 +260,7 @@ static void gzvm_drv_remove(struct platform_device *pde= v) { gzvm_drv_irqfd_exit(); misc_deregister(&gzvm_dev); + gzvm_drv_debug_exit(); gzvm_drv_sysfs_exit(); } =20 diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index e44ee2d04ed8..2ce36ad8791b 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -4,6 +4,7 @@ */ =20 #include +#include #include #include #include @@ -342,6 +343,12 @@ static void gzvm_destroy_all_ppage(struct gzvm *gzvm) } } =20 +static int gzvm_destroy_vm_debugfs(struct gzvm *vm) +{ + debugfs_remove_recursive(vm->debug_dir); + return 0; +} + static void gzvm_destroy_vm(struct gzvm *gzvm) { size_t allocated_size; @@ -369,6 +376,8 @@ static void gzvm_destroy_vm(struct gzvm *gzvm) /* No need to lock here becauese it's single-threaded execution */ gzvm_destroy_all_ppage(gzvm); =20 + gzvm_destroy_vm_debugfs(gzvm); + kfree(gzvm); } =20 @@ -427,6 +436,108 @@ static void setup_vm_demand_paging(struct gzvm *vm) } } =20 +/** + * hyp_mem_read() - Get size of hypervisor-allocated memory and stage 2 ta= ble + * @file: Pointer to struct file + * @buf: User space buffer for storing the return value + * @len: Size of @buf, in bytes + * @offset: Pointer to loff_t + * + * Return: Size of hypervisor-allocated memory and stage 2 table, in bytes + */ +static ssize_t hyp_mem_read(struct file *file, char __user *buf, size_t le= n, + loff_t *offset) +{ + char tmp_buffer[GZVM_MAX_DEBUGFS_VALUE_SIZE] =3D {0}; + struct gzvm *vm =3D file->private_data; + int ret; + + if (*offset =3D=3D 0) { + ret =3D gzvm_arch_get_statistics(vm); + if (ret) + return ret; + snprintf(tmp_buffer, sizeof(tmp_buffer), "%llu\n", + vm->stat.protected_hyp_mem); + if (copy_to_user(buf, tmp_buffer, sizeof(tmp_buffer))) + return -EFAULT; + *offset +=3D sizeof(tmp_buffer); + return sizeof(tmp_buffer); + } + return 0; +} + +/** + * shared_mem_read() - Get size of memory shared between host and guest + * @file: Pointer to struct file + * @buf: User space buffer for storing the return value + * @len: Size of @buf, in bytes + * @offset: Pointer to loff_t + * + * Return: Size of memory shared between host and guest, in bytes + */ +static ssize_t shared_mem_read(struct file *file, char __user *buf, size_t= len, + loff_t *offset) +{ + char tmp_buffer[GZVM_MAX_DEBUGFS_VALUE_SIZE] =3D {0}; + struct gzvm *vm =3D file->private_data; + int ret; + + if (*offset =3D=3D 0) { + ret =3D gzvm_arch_get_statistics(vm); + if (ret) + return ret; + snprintf(tmp_buffer, sizeof(tmp_buffer), "%llu\n", + vm->stat.protected_shared_mem); + if (copy_to_user(buf, tmp_buffer, sizeof(tmp_buffer))) + return -EFAULT; + *offset +=3D sizeof(tmp_buffer); + return sizeof(tmp_buffer); + } + return 0; +} + +static const struct file_operations hyp_mem_fops =3D { + .open =3D simple_open, + .read =3D hyp_mem_read, +}; + +static const struct file_operations shared_mem_fops =3D { + .open =3D simple_open, + .read =3D shared_mem_read, +}; + +static int gzvm_create_vm_debugfs(struct gzvm *vm) +{ + struct dentry *dent; + char dir_name[GZVM_MAX_DEBUGFS_DIR_NAME_SIZE]; + + if (!vm->gzvm_drv->gzvm_debugfs_dir) { + pr_warn("VM debugfs directory is not exist\n"); + return -EFAULT; + } + + if (vm->debug_dir) { + pr_warn("VM debugfs directory is duplicated\n"); + return 0; + } + + snprintf(dir_name, sizeof(dir_name), "%d-%d", task_pid_nr(current), vm->v= m_id); + + dent =3D debugfs_lookup(dir_name, vm->gzvm_drv->gzvm_debugfs_dir); + if (dent) { + pr_warn("Debugfs directory is duplicated\n"); + dput(dent); + return 0; + } + dent =3D debugfs_create_dir(dir_name, vm->gzvm_drv->gzvm_debugfs_dir); + vm->debug_dir =3D dent; + + debugfs_create_file("protected_shared_mem", 0444, dent, vm, &shared_mem_f= ops); + debugfs_create_file("protected_hyp_mem", 0444, dent, vm, &hyp_mem_fops); + + return 0; +} + static int setup_mem_alloc_mode(struct gzvm *vm) { int ret; @@ -487,6 +598,10 @@ static struct gzvm *gzvm_create_vm(struct gzvm_driver = *drv, unsigned long vm_typ list_add(&gzvm->vm_list, &gzvm_list); mutex_unlock(&gzvm_list_lock); =20 + ret =3D gzvm_create_vm_debugfs(gzvm); + if (ret) + pr_debug("Failed to create debugfs for VM-%u\n", gzvm->vm_id); + pr_debug("VM-%u is created\n", gzvm->vm_id); =20 return gzvm; diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 7065ec36f190..bafdd7c2bdc8 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -30,6 +30,8 @@ struct gzvm_driver { =20 struct kobject *sysfs_root_dir; u32 demand_paging_batch_pages; + + struct dentry *gzvm_debugfs_dir; }; =20 /* @@ -67,6 +69,9 @@ struct gzvm_driver { #define GZVM_DRV_DEMAND_PAGING_BATCH_PAGES \ (GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE / PAGE_SIZE) =20 +#define GZVM_MAX_DEBUGFS_DIR_NAME_SIZE 20 +#define GZVM_MAX_DEBUGFS_VALUE_SIZE 20 + enum gzvm_demand_paging_mode { GZVM_FULLY_POPULATED =3D 0, GZVM_DEMAND_PAGING =3D 1, @@ -132,6 +137,11 @@ struct gzvm_pinned_page { u64 ipa; }; =20 +struct gzvm_vm_stat { + u64 protected_hyp_mem; + u64 protected_shared_mem; +}; + /** * struct gzvm: the following data structures are for data transferring be= tween * driver and hypervisor, and they're aligned with hypervisor definitions. @@ -156,6 +166,8 @@ struct gzvm_pinned_page { * @demand_page_buffer: the mailbox for transferring large portion pages * @demand_paging_lock: lock for preventing multiple cpu using the same de= mand * page mailbox at the same time + * @stat: information for VM memory statistics + * @debug_dir: debugfs directory node for VM memory statistics */ struct gzvm { struct gzvm_driver *gzvm_drv; @@ -188,6 +200,9 @@ struct gzvm { u32 demand_page_gran; u64 *demand_page_buffer; struct mutex demand_paging_lock; + + struct gzvm_vm_stat stat; + struct dentry *debug_dir; }; =20 long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args); @@ -213,6 +228,7 @@ int gzvm_arch_destroy_vm(u16 vm_id); int gzvm_arch_map_guest(u16 vm_id, int memslot_id, u64 pfn, u64 gfn, u64 nr_pages); int gzvm_arch_map_guest_block(u16 vm_id, int memslot_id, u64 gfn, u64 nr_p= ages); +int gzvm_arch_get_statistics(struct gzvm *gzvm); int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, struct gzvm_enable_cap *cap, void __user *argp); --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 525741F893F; Thu, 14 Nov 2024 10:08:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; cv=none; b=roJraVobWjPSPhDJ4/KgHz9OJiUqJdZk/A9HRetzyzkV1mobZ+bbcWj1Y32K+HQ7b1Z8ZDd97QZLkstEy0yyNxFTaluDyTcQZM80shwyERlhMnaxO7Fli1TgKvpkGPoXcyBMPjQ5Zh7zuTwgZkbsZYTvRNyHjtg2NE0teB2Yjx4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578901; c=relaxed/simple; bh=Zjt7fBQtLgMlW6MzTLZ8+OwkYRvacRfMQCdKXXE8hZc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XDWWhNFIPzHUxDRh9t76O81amlnu0LYgrbv0P3YRG4c4F2b22QdNZOiQnsqEOB7827NSHKDkrTghRTlyxfCZ+lkHD7jHpPOKvZsI/6XZePnid4NWXFxWPXjZSt2NZHQVexuU8XO4i/ql2P2yGPixrRUAK70nemo233vHLzeNAs4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=hu+AMsdy; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="hu+AMsdy" X-UUID: 58860766a27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=TOxnymXbfRT1DhUocscm0skShCOMFhsJtkf5CuwCaMY=; b=hu+AMsdy2tn2xX6PXB2f8FcToozYM6fGzsT0UQxsk0+w9F9mAKpdPSh4/RpvQKaeXgpl8dFHMOX/TVPP1+eo0LexgW+hFQKGtJCb9PnNg2foZf7+aFtdeYaekMWPd/EOOULSh/rlO2xDvQnMROprj8Rhdak3zotiiorF/7C2oU8=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:1fd6c40c-41f9-4969-a300-b8e140aabc9e,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:5b3fa25c-f18b-4d56-b49c-93279ee09144,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 58860766a27011efbd192953cf12861f-20241114 Received: from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 826411859; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs11n2.mediatek.inc (172.21.101.187) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:06 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:06 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 20/25] virt: geniezone: Add tracing support for hyp call and vcpu exit_reason Date: Thu, 14 Nov 2024 18:07:57 +0800 Message-ID: <20241114100802.4116-21-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Liju Chen Add tracepoints for hypervisor calls and VCPU exit reasons in GenieZone driver. It aids performance debugging by providing more information about hypervisor operations and VCPU behavior. Command Usage: echo geniezone:* >> /sys/kernel/tracing/set_event echo 1 > /sys/kernel/tracing/tracing_on echo 0 > /sys/kernel/tracing/tracing_on cat /sys/kernel/tracing/trace For example: crosvm_vcpu0-4874 [007] ..... 94.757349: mtk_hypcall_enter: id=3D0xfb= 001005 crosvm_vcpu0-4874 [007] ..... 94.760902: mtk_hypcall_leave: id=3D0xfb= 001005 invalid=3D0 crosvm_vcpu0-4874 [007] ..... 94.760902: mtk_vcpu_exit: vcpu exit_rea= son=3DIRQ(0x92920003) This example tracks a hypervisor function call by an ID (`0xbb001005`) from initiation to termination, which is supported (invalid=3D0). A vCPU exit is triggered by an Interrupt Request (IRQ) (exit reason: 0x92920003). /* VM exit reason */ enum { GZVM_EXIT_UNKNOWN =3D 0x92920000, GZVM_EXIT_MMIO =3D 0x92920001, GZVM_EXIT_HYPERCALL =3D 0x92920002, GZVM_EXIT_IRQ =3D 0x92920003, GZVM_EXIT_EXCEPTION =3D 0x92920004, GZVM_EXIT_DEBUG =3D 0x92920005, GZVM_EXIT_FAIL_ENTRY =3D 0x92920006, GZVM_EXIT_INTERNAL_ERROR =3D 0x92920007, GZVM_EXIT_SYSTEM_EVENT =3D 0x92920008, GZVM_EXIT_SHUTDOWN =3D 0x92920009, GZVM_EXIT_GZ =3D 0x9292000a, }; Reviewed-by: Steven Rostedt (Google) Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/vm.c | 4 ++ drivers/virt/geniezone/gzvm_vcpu.c | 3 ++ include/trace/events/geniezone.h | 84 ++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 include/trace/events/geniezone.h diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 0350d9444c18..026c1980d054 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -7,6 +7,8 @@ #include #include =20 +#define CREATE_TRACE_POINTS +#include #include #include #include "gzvm_arch_common.h" @@ -44,11 +46,13 @@ int gzvm_hypcall_wrapper(unsigned long a0, unsigned lon= g a1, .a6 =3D a6, .a7 =3D a7, }; + trace_mtk_hypcall_enter(a0); arm_smccc_1_2_hvc(&args, &res_1_2); res->a0 =3D res_1_2.a0; res->a1 =3D res_1_2.a1; res->a2 =3D res_1_2.a2; res->a3 =3D res_1_2.a3; + trace_mtk_hypcall_leave(a0, (res->a0 !=3D ERR_NOT_SUPPORTED) ? 0 : 1); =20 return gzvm_err_to_errno(res->a0); } diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index b0dc3e4f47d7..3b146148abf3 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -9,6 +9,8 @@ #include #include #include + +#include #include =20 /* maximum size needed for holding an integer */ @@ -102,6 +104,7 @@ static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, void = __user *argp) =20 while (!need_userspace && !signal_pending(current)) { gzvm_arch_vcpu_run(vcpu, &exit_reason); + trace_mtk_vcpu_exit(exit_reason); =20 switch (exit_reason) { case GZVM_EXIT_MMIO: diff --git a/include/trace/events/geniezone.h b/include/trace/events/geniez= one.h new file mode 100644 index 000000000000..4fffd826ba67 --- /dev/null +++ b/include/trace/events/geniezone.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM geniezone + +#define _TRACE_GENIEZONE_H + +#include +#include + +#define GZVM_EXIT_REASONS \ +EM(UNKNOWN)\ +EM(MMIO)\ +EM(HYPERCALL)\ +EM(IRQ)\ +EM(EXCEPTION)\ +EM(DEBUG)\ +EM(FAIL_ENTRY)\ +EM(INTERNAL_ERROR)\ +EM(SYSTEM_EVENT)\ +EM(SHUTDOWN)\ +EMe(GZ) + +#undef EM +#undef EMe +#define EM(a) TRACE_DEFINE_ENUM(GZVM_EXIT_##a); +#define EMe(a) TRACE_DEFINE_ENUM(GZVM_EXIT_##a); + +GZVM_EXIT_REASONS + +#undef EM +#undef EMe + +#define EM(a) { GZVM_EXIT_##a, #a }, +#define EMe(a) { GZVM_EXIT_##a, #a } + +TRACE_EVENT(mtk_hypcall_enter, + TP_PROTO(unsigned long id), + + TP_ARGS(id), + + TP_STRUCT__entry(__field(unsigned long, id)), + + TP_fast_assign(__entry->id =3D id;), + + TP_printk("id=3D0x%lx", __entry->id) +); + +TRACE_EVENT(mtk_hypcall_leave, + TP_PROTO(unsigned long id, unsigned long invalid), + + TP_ARGS(id, invalid), + + TP_STRUCT__entry(__field(unsigned long, id) + __field(unsigned long, invalid) + ), + + TP_fast_assign(__entry->id =3D id; + __entry->invalid =3D invalid; + ), + + TP_printk("id=3D0x%lx invalid=3D%lu", __entry->id, __entry->invalid) +); + +TRACE_EVENT(mtk_vcpu_exit, + TP_PROTO(unsigned long exit_reason), + + TP_ARGS(exit_reason), + + TP_STRUCT__entry(__field(unsigned long, exit_reason)), + + TP_fast_assign(__entry->exit_reason =3D exit_reason;), + + TP_printk("vcpu exit_reason=3D%s(0x%lx)", + __print_symbolic(__entry->exit_reason, GZVM_EXIT_REASONS), + __entry->exit_reason) + +); + +/* This part must be outside protection */ +#include --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0BE661F7540; Thu, 14 Nov 2024 10:08:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; cv=none; b=HXJIUX81tcHv1DHLys1xqSRrIM03b/XsMcYGcXMA6Q484wZdqwgouWbzCD5SM3Qoq5QNWjfsU205GCKRBW/zCRAJRQJVhdXI8oIdNu1+kDnpjXQeVLjLoP6DywK9DBTs3tCv7k8JdDxpC+sFgTXFxEeCTJ2Z8tNHBJ+VgUTLHzE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; c=relaxed/simple; bh=nCOKQafPOR44WFReYRaeFJZMPdTExDqsZ1+vi3f4SK0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=J2Tj/EQt48NwwmziKrgpYj+HDJhhy+7vFT7JL0hcC+i+Yl2Sb+eRKZQ6XXWS0NWqbrR9i5XPKKDourtWweeGh8BDcYfhmjpZ0KniMmQiRtNxiVr1uxfTG6LQz91uM3x14B2CjJMCEoORCloMlvh/1CuFH6nC4OJBc7uj01A9iM0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=dYLGsQci; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="dYLGsQci" X-UUID: 58a12618a27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=3Uu4/eeOI9rxd4n8eOIqzxIhcXvcT+8sELRQpzpmMiE=; b=dYLGsQciMlQGniVFLOAfugq9bzfsy0onmWtFBh/2zpqO49juRpqyxjFz7leF9gMzSib44f8tR1J0WSvfwaOfeRtRSa/jVmRV82fxFR+g8sn65mCKolZbn6yuIdNVprbgTM8dF7QVXuRQlyLmridzdVUfT7FMwGcp5sXRZKULuvE=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:1d4f684c-eb2c-464f-b813-aac5521cde9a,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:d25e0c4f-a2ae-4b53-acd4-c3dc8f449198,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 58a12618a27011ef99858b75a2457dd9-20241114 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 987784873; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:06 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:06 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 21/25] virt: geniezone: Enable PTP for synchronizing time between host and guest VMs Date: Thu, 14 Nov 2024 18:07:58 +0800 Message-ID: <20241114100802.4116-22-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kevenny Hsieh Enabled Precision Time Protocol (PTP) for improved host-guest VM time synchronization, optimizing operations needing precise clock sync in virtual environment. Signed-off-by: Kevenny Hsieh Signed-off-by: Yi-De Wu Signed-off-by: Liju Chen --- arch/arm64/geniezone/Makefile | 2 +- arch/arm64/geniezone/gzvm_arch_common.h | 3 + arch/arm64/geniezone/hvc.c | 73 +++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_exception.c | 3 +- include/linux/soc/mediatek/gzvm_drv.h | 1 + include/uapi/linux/gzvm.h | 1 + 6 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 arch/arm64/geniezone/hvc.c diff --git a/arch/arm64/geniezone/Makefile b/arch/arm64/geniezone/Makefile index 0e4f1087f9de..553a64a926dc 100644 --- a/arch/arm64/geniezone/Makefile +++ b/arch/arm64/geniezone/Makefile @@ -4,6 +4,6 @@ # include $(srctree)/drivers/virt/geniezone/Makefile =20 -gzvm-y +=3D vm.o vcpu.o vgic.o +gzvm-y +=3D vm.o vcpu.o vgic.o hvc.o =20 obj-$(CONFIG_MTK_GZVM) +=3D gzvm.o diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 192d023722e5..8f5d8528ab96 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -83,6 +83,8 @@ int gzvm_hypcall_wrapper(unsigned long a0, unsigned long = a1, * @__pad: add an explicit '__u32 __pad;' in the middle to make it clear * what the actual layout is. * @lr: The array of LRs(list registers). + * @vtimer_offset: The offset maintained by hypervisor that is host cycle = count + * when guest VM startup. * * - Keep the same layout of hypervisor data struct. * - Sync list registers back for acking virtual device interrupt status. @@ -91,6 +93,7 @@ struct gzvm_vcpu_hwstate { __le32 nr_lrs; __le32 __pad; __le64 lr[GIC_V3_NR_LRS]; + __le64 vtimer_offset; }; =20 static inline unsigned int diff --git a/arch/arm64/geniezone/hvc.c b/arch/arm64/geniezone/hvc.c new file mode 100644 index 000000000000..3d7f71f20dce --- /dev/null +++ b/arch/arm64/geniezone/hvc.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ +#include +#include +#include +#include +#include "gzvm_arch_common.h" + +#define GZVM_PTP_VIRT_COUNTER 0 +#define GZVM_PTP_PHYS_COUNTER 1 +/** + * gzvm_handle_ptp_time() - Sync time between host and guest VM + * @vcpu: Pointer to struct gzvm_vcpu_run in userspace + * @counter: Counter type from guest VM + * Return: Always return 0 because there are no cases of failure + * + * The following register values will be passed to the guest VM + * for time synchronization: + * regs->x0 (upper 32 bits) wall clock time + * regs->x1 (lower 32 bits) wall clock time + * regs->x2 (upper 32 bits) cycles + * regs->x3 (lower 32 bits) cycles + */ +static int gzvm_handle_ptp_time(struct gzvm_vcpu *vcpu, int counter) +{ + struct system_time_snapshot snapshot; + u64 cycles =3D 0; + + ktime_get_snapshot(&snapshot); + + switch (counter) { + case GZVM_PTP_VIRT_COUNTER: + cycles =3D snapshot.cycles - + le64_to_cpu(vcpu->hwstate->vtimer_offset); + break; + case GZVM_PTP_PHYS_COUNTER: + cycles =3D snapshot.cycles; + break; + default: + break; + } + + vcpu->run->hypercall.args[0] =3D upper_32_bits(snapshot.real); + vcpu->run->hypercall.args[1] =3D lower_32_bits(snapshot.real); + vcpu->run->hypercall.args[2] =3D upper_32_bits(cycles); + vcpu->run->hypercall.args[3] =3D lower_32_bits(cycles); + + return 0; +} + +/** + * gzvm_arch_handle_guest_hvc() - Handle architecture-related guest hvc + * @vcpu: Pointer to struct gzvm_vcpu_run in userspace + * Return: + * * true - This hvc has been processed, no need to back to VMM. + * * false - This hvc has not been processed, require userspace. + */ +bool gzvm_arch_handle_guest_hvc(struct gzvm_vcpu *vcpu) +{ + int ret, counter; + + switch (vcpu->run->hypercall.args[0]) { + case GZVM_HVC_PTP: + counter =3D vcpu->run->hypercall.args[1]; + ret =3D gzvm_handle_ptp_time(vcpu, counter); + return (ret =3D=3D 0) ? true : false; + default: + break; + } + return false; +} diff --git a/drivers/virt/geniezone/gzvm_exception.c b/drivers/virt/geniezo= ne/gzvm_exception.c index cdfc99d24ded..5ffee863e378 100644 --- a/drivers/virt/geniezone/gzvm_exception.c +++ b/drivers/virt/geniezone/gzvm_exception.c @@ -56,7 +56,6 @@ bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu) ret =3D gzvm_handle_relinquish(vcpu, ipa); return (ret =3D=3D 0) ? true : false; default: - break; + return gzvm_arch_handle_guest_hvc(vcpu); } - return false; } diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index bafdd7c2bdc8..62e00fb06269 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -252,6 +252,7 @@ int gzvm_handle_page_fault(struct gzvm_vcpu *vcpu); bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu); int gzvm_handle_relinquish(struct gzvm_vcpu *vcpu, phys_addr_t ipa); bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu); +bool gzvm_arch_handle_guest_hvc(struct gzvm_vcpu *vcpu); =20 int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev= ); int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index f23266055140..ce73735f0be2 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -198,6 +198,7 @@ enum { =20 /* hypercall definitions of GZVM_EXIT_HYPERCALL */ enum { + GZVM_HVC_PTP =3D 0x86000001, GZVM_HVC_MEM_RELINQUISH =3D 0xc6000009, }; =20 --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ABC721F6669; Thu, 14 Nov 2024 10:08:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578897; cv=none; b=cgbzwq6LS3DsIF99ZVy6ltdotrmKZaUt7AhZOddliTfkat3udvlO4fMRXPsJNSIJ2EKQa66y5mvLXF9LirLDazE45pnB/LAnyUoaiIBwTO0YsbFxDlyDQJQChiXZCERors6UEM5O+2y4J8U/qWjTkkaPLgXaQGkRL9eFdIkpXro= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578897; c=relaxed/simple; bh=VqcJfXoXXFBv3SqkuzVK7YJDLjCRRhHL433r9h10lg0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VD2hwdk4kSs7SMgr2HQCBQT0/Rc+LMsdK3ZZq5TzL2uMlfW473QSvPlnlYXqvZS2FQA8vmfZ6zicyVuYYJxM8S0pZGXDtxWdmoPhGnJz7dTfVdHs7skxKNQWbzaCxQHUkn2PfwMib+7yvSozCFsju/p7W9lqk02V4OMork3ccIg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=SKeGhNQX; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="SKeGhNQX" X-UUID: 58a48182a27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=slipo85jeU4x0/6UQp38NN3nKrQSFTaT3dRImDEbsFI=; b=SKeGhNQX8Wh52YyOyWLxO2JQcSdzfnZA7oDOJgxDlYviKQX/ycSuV+/DTtWiFNvkQ3yGAnGOtj/TsP2sgCyxAcyZAkxTcQKt59Bg/9vh/7IjBeY9iTVyGh9aXf/0szEbfhpl+ztMP2zBiLdz0ar6hAm93HijMKGFl6V3WnjwTk8=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:319f6a7f-2c6b-47a9-b3cf-8d874c3fed72,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:e56b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 58a48182a27011ef99858b75a2457dd9-20241114 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1720630925; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:06 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:06 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 22/25] virt: geniezone: Add support for virtual timer migration Date: Thu, 14 Nov 2024 18:07:59 +0800 Message-ID: <20241114100802.4116-23-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Willix Yeh Introduce a mechanism to migrate the ARM64 virtual timer from the guest VM to the host Linux system when the execution context switches from the guest VM to the host. Ensure that the guest VM's virtual timer continues to operate seamlessly after the context switch, given that ARM64 has only one virtual timer. Translate the remaining time before the VM timer expires into the host Linux system by setting the remaining time on an hrtimer. This allows the guest VM to maintain its timer operations without interruption. Enable seamless timer operation during idle states. When a VM enters an idle state and the execution context returns to the host Linux, ensure that the timer continues to operate seamlessly, preventing disruption to the guest VM's timing operations. Signed-off-by: Willix Yeh Co-developed-by: Kevenny Hsieh Signed-off-by: Kevenny Hsieh Signed-off-by: Liju Chen --- arch/arm64/geniezone/gzvm_arch_common.h | 15 +++++++++++++++ arch/arm64/geniezone/vcpu.c | 16 ++++++++++++++++ arch/arm64/geniezone/vm.c | 24 ++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_main.c | 4 ++++ drivers/virt/geniezone/gzvm_vcpu.c | 24 ++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 7 +++++++ 6 files changed, 90 insertions(+) diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone= /gzvm_arch_common.h index 8f5d8528ab96..df16e33f6b74 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -7,6 +7,7 @@ #define __GZVM_ARCH_COMMON_H__ =20 #include +#include =20 enum { GZVM_FUNC_CREATE_VM =3D 0, @@ -85,6 +86,10 @@ int gzvm_hypcall_wrapper(unsigned long a0, unsigned long= a1, * @lr: The array of LRs(list registers). * @vtimer_offset: The offset maintained by hypervisor that is host cycle = count * when guest VM startup. + * @vtimer_delay: The remaining time before the next timer tick is trigger= ed + * while the VM is running. + * @vtimer_migrate: Indicates whether the guest virtual timer needs to be + * migrated to the host software timer. * * - Keep the same layout of hypervisor data struct. * - Sync list registers back for acking virtual device interrupt status. @@ -94,8 +99,18 @@ struct gzvm_vcpu_hwstate { __le32 __pad; __le64 lr[GIC_V3_NR_LRS]; __le64 vtimer_offset; + __le64 vtimer_delay; + __le32 vtimer_migrate; }; =20 +struct timecycle { + u32 mult; + u32 shift; +}; + +u32 gzvm_vtimer_get_clock_mult(void); +u32 gzvm_vtimer_get_clock_shift(void); + static inline unsigned int assemble_vm_vcpu_tuple(u16 vmid, u16 vcpuid) { diff --git a/arch/arm64/geniezone/vcpu.c b/arch/arm64/geniezone/vcpu.c index e12ea9cb4941..595f16904b99 100644 --- a/arch/arm64/geniezone/vcpu.c +++ b/arch/arm64/geniezone/vcpu.c @@ -11,6 +11,22 @@ #include #include "gzvm_arch_common.h" =20 +u64 gzvm_vcpu_arch_get_timer_delay_ns(struct gzvm_vcpu *vcpu) +{ + u64 ns; + + if (vcpu->hwstate->vtimer_migrate) { + ns =3D clocksource_cyc2ns(le64_to_cpu(vcpu->hwstate->vtimer_delay), + gzvm_vtimer_get_clock_mult(), + gzvm_vtimer_get_clock_shift()); + } else { + ns =3D 0; + } + + /* 0: no migrate, otherwise: migrate */ + return ns; +} + int gzvm_arch_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, __u64 reg_id, bool is_write, __u64 *data) { diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index 026c1980d054..fccdcd5b8c75 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -15,6 +15,18 @@ =20 #define PAR_PA47_MASK GENMASK_ULL(47, 12) =20 +static struct timecycle clock_scale_factor; + +u32 gzvm_vtimer_get_clock_mult(void) +{ + return clock_scale_factor.mult; +} + +u32 gzvm_vtimer_get_clock_shift(void) +{ + return clock_scale_factor.shift; +} + /** * gzvm_hypcall_wrapper() - the wrapper for hvc calls * @a0: arguments passed in registers 0 @@ -90,6 +102,18 @@ int gzvm_arch_probe(struct gzvm_version drv_version, return 0; } =20 +int gzvm_arch_drv_init(void) +{ + /* timecycle init mult shift */ + clocks_calc_mult_shift(&clock_scale_factor.mult, + &clock_scale_factor.shift, + arch_timer_get_cntfrq(), + NSEC_PER_SEC, + 30); + + return 0; +} + int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, phys_addr_t region) { diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index 1816eecfcefb..0ec15c33111e 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -233,6 +233,10 @@ static int gzvm_drv_probe(struct platform_device *pdev) gzvm_drv.hyp_version.major, gzvm_drv.hyp_version.minor, gzvm_drv.hyp_version.sub); =20 + ret =3D gzvm_arch_drv_init(); + if (ret) + return ret; + ret =3D misc_register(&gzvm_dev); if (ret) return ret; diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index 3b146148abf3..ba85a6ae04a0 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -16,6 +16,28 @@ /* maximum size needed for holding an integer */ #define ITOA_MAX_LEN 12 =20 +static enum hrtimer_restart gzvm_vtimer_expire(struct hrtimer *hrt) +{ + return HRTIMER_NORESTART; +} + +static void gzvm_vtimer_init(struct gzvm_vcpu *vcpu) +{ + /* gzvm_vtimer init based on hrtimer */ + hrtimer_init(&vcpu->gzvm_vtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); + vcpu->gzvm_vtimer.function =3D gzvm_vtimer_expire; +} + +void gzvm_vtimer_set(struct gzvm_vcpu *vcpu, u64 ns) +{ + hrtimer_start(&vcpu->gzvm_vtimer, ktime_add_ns(ktime_get(), ns), HRTIMER_= MODE_ABS_HARD); +} + +void gzvm_vtimer_release(struct gzvm_vcpu *vcpu) +{ + hrtimer_cancel(&vcpu->gzvm_vtimer); +} + static long gzvm_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, void __user *argp, bool is_write) @@ -193,6 +215,7 @@ static void gzvm_destroy_vcpu(struct gzvm_vcpu *vcpu) if (!vcpu) return; =20 + hrtimer_cancel(&vcpu->gzvm_vtimer); gzvm_arch_destroy_vcpu(vcpu->gzvm->vm_id, vcpu->vcpuid); /* clean guest's data */ memset(vcpu->run, 0, GZVM_VCPU_RUN_MAP_SIZE); @@ -271,6 +294,7 @@ int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cp= uid) goto free_vcpu_run; gzvm->vcpus[cpuid] =3D vcpu; =20 + gzvm_vtimer_init(vcpu); return ret; =20 free_vcpu_run: diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 62e00fb06269..901bc2fe28f1 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -129,6 +129,7 @@ struct gzvm_vcpu { struct mutex lock; struct gzvm_vcpu_run *run; struct gzvm_vcpu_hwstate *hwstate; + struct hrtimer gzvm_vtimer; }; =20 struct gzvm_pinned_page { @@ -242,11 +243,17 @@ int gzvm_vm_allocate_guest_page(struct gzvm *gzvm, st= ruct gzvm_memslot *slot, int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cpuid); int gzvm_arch_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, __u64 reg_id, bool is_write, __u64 *data); +int gzvm_arch_drv_init(void); int gzvm_arch_create_vcpu(u16 vm_id, int vcpuid, void *run); int gzvm_arch_vcpu_run(struct gzvm_vcpu *vcpu, __u64 *exit_reason); int gzvm_arch_destroy_vcpu(u16 vm_id, int vcpuid); int gzvm_arch_inform_exit(u16 vm_id); =20 +u64 gzvm_vcpu_arch_get_timer_delay_ns(struct gzvm_vcpu *vcpu); + +void gzvm_vtimer_set(struct gzvm_vcpu *vcpu, u64 ns); +void gzvm_vtimer_release(struct gzvm_vcpu *vcpu); + int gzvm_find_memslot(struct gzvm *vm, u64 gpa); int gzvm_handle_page_fault(struct gzvm_vcpu *vcpu); bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu); --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9E0791F8EFE; Thu, 14 Nov 2024 10:08:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; cv=none; b=kTmHKwZj2RITnXuWQ1PUajGAN4ztLuU5YenTZZL+hyLAnEfyOH1KNluKfD7ngDZ5QJ2npRb2nUE/Y9WA0CgShO14xwUZktSk02mBFUPMykD6yggzt+DvJn4/HzVO48fkNm4hFPw1d7cMNJtC1bVJRkWW+FTqtxxqaT2yfB9INso= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; c=relaxed/simple; bh=tjd8/2IdrUx5zkHtd1BboRgePsaDImBstNxO1aM9JSU=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DZPAN+QLxY+cY+4e6RAEAVGEvm3ZLqqL/Q48l46p/NrFzir+EMfW/kcG03dvLD5mHaqT8WxlrN+M+HU+TX+Rj8YY7MRvcluLpDLIdMRBUwOrBjtsLfQz2wFKGSg2/LZ14Tptj1nnjA37tTDVEh74weu6eIyXwc/bB4/VlBCfBh4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=C2N3zW6o; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="C2N3zW6o" X-UUID: 588bd3daa27011efbd192953cf12861f-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=GqgHf1P44U6+iXgzbbPS+DGRuZ/JJ1n6EooYA/AkJPM=; b=C2N3zW6okpN9jReT9HE+88JEzioc7MIBZKXrlyqiTiJSlg/kmF6Jw/w9qtUEbK2Ib73VoccjNQXgoPMAc7UirZWoatN7kz+cFIWA1tfLRSY7Jlp74ySUHne5TLkVwMRYetPK6NIlP1j3icmGWb1iLXC/TtEmjFZi0int+yY8bEI=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:ae5bd0e8-9713-4a88-b0d7-f6d8b146c9c1,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:f96b1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 588bd3daa27011efbd192953cf12861f-20241114 Received: from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 272967371; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs11n2.mediatek.inc (172.21.101.187) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:06 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:06 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 23/25] virt: geniezone: Add support for guest VM CPU idle Date: Thu, 14 Nov 2024 18:08:00 +0800 Message-ID: <20241114100802.4116-24-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kevenny Hsieh Implement CPU idle functionality for guest VMs, allowing the guest VM's CPU to relinquish control to the host when it enters an idle state. Enable the host to schedule other processes, thereby reducing CPU usage and achieving power savings. Introduce a new capability (`enable_idle_support`) to support the idle feature. Emulate the WFI (Wait For Interrupt) instruction for the guest VM when it enters an idle state. Allow the host Linux kernel to schedule other processes and enable the vCPU to enter the `wait` state. Ensure that the vCPU can be woken up by interrupts such as the virtual timer (vtimer) and virtio interrupts. With the idle feature, the vCPU can efficiently enter a lower power state, such as decreasing CPU frequency or even entering an idle state, thereby reducing CPU usage and improving overall system power efficiency. Signed-off-by: Kevenny Hsieh Signed-off-by: Liju Chen --- arch/arm64/geniezone/vm.c | 3 ++ drivers/virt/geniezone/gzvm_exception.c | 46 +++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_vcpu.c | 26 +++++++++++++- drivers/virt/geniezone/gzvm_vm.c | 15 ++++++++ include/linux/soc/mediatek/gzvm_drv.h | 7 ++++ include/uapi/linux/gzvm.h | 2 ++ 6 files changed, 98 insertions(+), 1 deletion(-) diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index fccdcd5b8c75..cfd0aeb865e5 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -449,6 +449,9 @@ int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm, case GZVM_CAP_BLOCK_BASED_DEMAND_PAGING: ret =3D gzvm_vm_arch_enable_cap(gzvm, cap, &res); return ret; + case GZVM_CAP_ENABLE_IDLE: + ret =3D gzvm_vm_arch_enable_cap(gzvm, cap, &res); + return ret; default: break; } diff --git a/drivers/virt/geniezone/gzvm_exception.c b/drivers/virt/geniezo= ne/gzvm_exception.c index 5ffee863e378..391168a3f737 100644 --- a/drivers/virt/geniezone/gzvm_exception.c +++ b/drivers/virt/geniezone/gzvm_exception.c @@ -5,6 +5,8 @@ =20 #include #include +#include +#include =20 /** * gzvm_handle_guest_exception() - Handle guest exception @@ -59,3 +61,47 @@ bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu) return gzvm_arch_handle_guest_hvc(vcpu); } } + +static void vcpu_block_wait(struct gzvm_vcpu *vcpu) +{ + struct rcuwait *wait =3D &vcpu->wait; + + prepare_to_rcuwait(wait); + + while (true) { + set_current_state(TASK_INTERRUPTIBLE); + if (vcpu->idle_events.virtio_irq) { + vcpu->idle_events.virtio_irq =3D 0; + break; + } + if (vcpu->idle_events.vtimer_irq) { + vcpu->idle_events.vtimer_irq =3D 0; + break; + } + if (signal_pending(current)) + break; + schedule(); + } + finish_rcuwait(wait); +} + +/** + * gzvm_handle_guest_idle() - Handle guest vm entering idle + * @vcpu: Pointer to struct gzvm_vcpu struct + * Return: + */ +int gzvm_handle_guest_idle(struct gzvm_vcpu *vcpu) +{ + int ret =3D 0; + u64 ns =3D 0; + + ns =3D gzvm_vcpu_arch_get_timer_delay_ns(vcpu); + + if (ns) { + gzvm_vtimer_set(vcpu, ns); + vcpu_block_wait(vcpu); + gzvm_vtimer_release(vcpu); + } + + return ret; +} diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index ba85a6ae04a0..247848ee126c 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -16,8 +16,29 @@ /* maximum size needed for holding an integer */ #define ITOA_MAX_LEN 12 =20 +/** + * gzvm_vcpu_wakeup_all - wakes up all vCPUs associated with the specified + * gzvm. + * @gzvm: Pointer to gzvm structure. + */ +void gzvm_vcpu_wakeup_all(struct gzvm *gzvm) +{ + for (int i =3D 0; i < GZVM_MAX_VCPUS; i++) { + if (gzvm->vcpus[i]) { + gzvm->vcpus[i]->idle_events.virtio_irq +=3D 1; + rcuwait_wake_up(&gzvm->vcpus[i]->wait); + } + } +} + static enum hrtimer_restart gzvm_vtimer_expire(struct hrtimer *hrt) { + struct gzvm_vcpu *vcpu; + + vcpu =3D container_of(hrt, struct gzvm_vcpu, gzvm_vtimer); + + gzvm_vcpu_wakeup_all(vcpu->gzvm); + return HRTIMER_NORESTART; } =20 @@ -111,7 +132,7 @@ static bool gzvm_vcpu_handle_mmio(struct gzvm_vcpu *vcp= u) static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, void __user *argp) { bool need_userspace =3D false; - u64 exit_reason =3D 0; + u64 exit_reason; =20 if (copy_from_user(vcpu->run, argp, sizeof(struct gzvm_vcpu_run))) return -EFAULT; @@ -160,6 +181,9 @@ static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, void = __user *argp) fallthrough; case GZVM_EXIT_GZ: break; + case GZVM_EXIT_IDLE: + gzvm_handle_guest_idle(vcpu); + break; case GZVM_EXIT_UNKNOWN: fallthrough; default: diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 2ce36ad8791b..999c8c586d7b 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -170,6 +170,7 @@ gzvm_vm_ioctl_set_memory_region(struct gzvm *gzvm, int gzvm_irqchip_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, u32 irq, bool level) { + gzvm_vcpu_wakeup_all(gzvm); return gzvm_arch_inject_irq(gzvm, vcpu_idx, irq, level); } =20 @@ -556,6 +557,18 @@ static int setup_mem_alloc_mode(struct gzvm *vm) return 0; } =20 +static int enable_idle_support(struct gzvm *vm) +{ + int ret; + struct gzvm_enable_cap cap =3D {0}; + + cap.cap =3D GZVM_CAP_ENABLE_IDLE; + ret =3D gzvm_vm_ioctl_enable_cap(vm, &cap, NULL); + if (ret) + pr_info("Hypervisor doesn't support idle\n"); + return ret; +} + static struct gzvm *gzvm_create_vm(struct gzvm_driver *drv, unsigned long = vm_type) { int ret; @@ -604,6 +617,8 @@ static struct gzvm *gzvm_create_vm(struct gzvm_driver *= drv, unsigned long vm_typ =20 pr_debug("VM-%u is created\n", gzvm->vm_id); =20 + enable_idle_support(gzvm); + return gzvm; } =20 diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 901bc2fe28f1..54fa7aea7245 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -130,6 +130,11 @@ struct gzvm_vcpu { struct gzvm_vcpu_run *run; struct gzvm_vcpu_hwstate *hwstate; struct hrtimer gzvm_vtimer; + struct { + u32 vtimer_irq; + u32 virtio_irq; + } idle_events; + struct rcuwait wait; }; =20 struct gzvm_pinned_page { @@ -260,6 +265,8 @@ bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu= ); int gzvm_handle_relinquish(struct gzvm_vcpu *vcpu, phys_addr_t ipa); bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu); bool gzvm_arch_handle_guest_hvc(struct gzvm_vcpu *vcpu); +int gzvm_handle_guest_idle(struct gzvm_vcpu *vcpu); +void gzvm_vcpu_wakeup_all(struct gzvm *gzvm); =20 int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev= ); int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index ce73735f0be2..61ce53cd9448 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -21,6 +21,7 @@ /* query hypervisor supported block-based demand page */ #define GZVM_CAP_BLOCK_BASED_DEMAND_PAGING 0x9201 #define GZVM_CAP_ENABLE_DEMAND_PAGING 0x9202 +#define GZVM_CAP_ENABLE_IDLE 0x9203 #define GZVM_CAP_QUERY_HYP_BATCH_PAGES 0x9204 =20 /* sub-commands put in args[0] for GZVM_CAP_PROTECTED_VM */ @@ -188,6 +189,7 @@ enum { GZVM_EXIT_SYSTEM_EVENT =3D 0x92920008, GZVM_EXIT_SHUTDOWN =3D 0x92920009, GZVM_EXIT_GZ =3D 0x9292000a, + GZVM_EXIT_IDLE =3D 0x9292000b, }; =20 /* exception definitions of GZVM_EXIT_EXCEPTION */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A4401F80CB; Thu, 14 Nov 2024 10:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; cv=none; b=ZG5obQDgwPvZFbJabi+qG8NZAk7xAQG3GP4sItRwUNACraMAV8I24gKZTcm/5yd7ufBzu60LBYFT5Mft25a3dl0uzKwNUce+/3Ge5ldf/kcxtivgfnvFmWWA6yoNEw1uGhsD8aV2n6ulGxE011YNecqWQfG+1j6YN6MfKCA305I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578900; c=relaxed/simple; bh=xvgaCmvoiR8tTXAiLoKCPODCJkm3RmTKP3UKdTEhCRI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WS3VJFPpMGru348umkI5CMdD4BsOzJgRl5jLlq01v3Y/Sc2kWJ4d0w0rWanJbtxc/QZpvBdVjoha6ioYlRJ1WPbft+3+1eFTAq4pK8l/e+haKIVl/OVqJlq6z9JEMCumpE8x1ICRs5kV9/fe9VFiV9iFq5xmQPjY7r4Wpz2JLUM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=hNYMMSml; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="hNYMMSml" X-UUID: 58a7c752a27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=olVph3cQeOWUn5eJcsuo5CyNUNQwKw8vhf+nxFUdb9U=; b=hNYMMSml3TVdCv1deOp8ZeB1Klm1wT2IPaSOPOlnQgRpazooVDJwlz37WvOi1m7T2aMf4a8+j44paU2tsEWgdVSHUZjMP1e3Dn1jMN//UPUiyH1paljRoEto8HRINdT47pTnk1YHQI6tCJ0kl9YwrJu/YeP7yAX3wwgh7TxGQh4=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:52cfc9e9-5a7e-4ee6-91dd-9577aff92326,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:136c1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0, LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 58a7c752a27011ef99858b75a2457dd9-20241114 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1522867474; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 18:08:07 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:07 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 24/25] virt: geniezone: Emulate IPI for guest VM Date: Thu, 14 Nov 2024 18:08:01 +0800 Message-ID: <20241114100802.4116-25-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kevenny Hsieh Emulate Inter-Processor Interrupts (IPI) handling for guest VMs. Ensure that when a vCPU thread enters an idle state and relinquishes CPU control to the host, it can be woken up by IPIs issued by other vCPUs through the gzvm driver. Add a new wake-up mechanism, `GZVM_EXIT_IPI`, to handle IPIs. Ensure that idle vCPUs can be woken up not only by virtual timer (vtimer) and virtio interrupts but also by IPIs issued by other vCPUs. Ensure proper handling of IPIs, allowing idle vCPUs to be woken up and respond to interrupts, thereby maintaining correct and efficient inter-processor communication within the guest VM. Signed-off-by: Kevenny Hsieh Signed-off-by: Liju Chen --- drivers/virt/geniezone/gzvm_exception.c | 5 +++++ drivers/virt/geniezone/gzvm_vcpu.c | 3 +++ include/linux/soc/mediatek/gzvm_drv.h | 1 + include/uapi/linux/gzvm.h | 1 + 4 files changed, 10 insertions(+) diff --git a/drivers/virt/geniezone/gzvm_exception.c b/drivers/virt/geniezo= ne/gzvm_exception.c index 391168a3f737..7a4e3d76aa7a 100644 --- a/drivers/virt/geniezone/gzvm_exception.c +++ b/drivers/virt/geniezone/gzvm_exception.c @@ -105,3 +105,8 @@ int gzvm_handle_guest_idle(struct gzvm_vcpu *vcpu) =20 return ret; } + +void gzvm_handle_guest_ipi(struct gzvm_vcpu *vcpu) +{ + gzvm_vcpu_wakeup_all(vcpu->gzvm); +} diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gz= vm_vcpu.c index 247848ee126c..5cdd6ccbe76d 100644 --- a/drivers/virt/geniezone/gzvm_vcpu.c +++ b/drivers/virt/geniezone/gzvm_vcpu.c @@ -184,6 +184,9 @@ static long gzvm_vcpu_run(struct gzvm_vcpu *vcpu, void = __user *argp) case GZVM_EXIT_IDLE: gzvm_handle_guest_idle(vcpu); break; + case GZVM_EXIT_IPI: + gzvm_handle_guest_ipi(vcpu); + break; case GZVM_EXIT_UNKNOWN: fallthrough; default: diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 54fa7aea7245..8fc6c6f54227 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -266,6 +266,7 @@ int gzvm_handle_relinquish(struct gzvm_vcpu *vcpu, phys= _addr_t ipa); bool gzvm_handle_guest_hvc(struct gzvm_vcpu *vcpu); bool gzvm_arch_handle_guest_hvc(struct gzvm_vcpu *vcpu); int gzvm_handle_guest_idle(struct gzvm_vcpu *vcpu); +void gzvm_handle_guest_ipi(struct gzvm_vcpu *vcpu); void gzvm_vcpu_wakeup_all(struct gzvm *gzvm); =20 int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev= ); diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index 61ce53cd9448..d69e1abb21a0 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -190,6 +190,7 @@ enum { GZVM_EXIT_SHUTDOWN =3D 0x92920009, GZVM_EXIT_GZ =3D 0x9292000a, GZVM_EXIT_IDLE =3D 0x9292000b, + GZVM_EXIT_IPI =3D 0x9292000d, }; =20 /* exception definitions of GZVM_EXIT_EXCEPTION */ --=20 2.18.0 From nobody Sat Nov 23 05:09:46 2024 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 156A31F8F1D; Thu, 14 Nov 2024 10:08:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; cv=none; b=XzNJbqfeR7LZ7LSXVzf5NL/+BvpWPWZsDXFaT0Rq5cbQl6b70/Zc80FcT1Bocdkqq9S7f+ChiUFLzT75uNliQbv1maXEH7JgcPGtWUshBb+sr38dlXJ3i8GX8qDz9OjMpIzuaX2hZSdNawwxglEuP5HdaTbc64hAE/KdXw3J8IQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731578902; c=relaxed/simple; bh=8NKuoOg75JhwHkLKnxA1sr9ZsZYcDBPVWjHlfiLi0rE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nXUijFVwTwBood87wqInWPFhMMHrHtx8kOes6baVml3q4mBrA6VrpyqpNT38Z09xJULdJgwBb/b0MmPqLis8qq6X4TfpiTqkc9hCOLK6iUSdKzyynfcil66C0PpTIHTm+86xfI/iMVmfxNck0a4RFNDysqboe87cnZ1TeM+fJ5I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=U5dWbKxG; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="U5dWbKxG" X-UUID: 590c1deca27011ef99858b75a2457dd9-20241114 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=kJib80vtMQ+j8z3Fr/DFzZp66roaGSj4aK6eGZ/xOt0=; b=U5dWbKxGD9R61cqlMsTR5Q/JPSz7YTafL6r+hIezdZAJypDUrT21tFDT4m0Nfon/c1mn9JP0T0Ov9BrEqPDSrsMgJl5RvFWjE6u8BUXWGsPxPg+1dIcrdHpk8e8fh096cFscYgpFbdqQn9PotaT7iBrYhQOcz0pUtrGoYAKK/50=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:95cc1b4a-5f90-49d2-a999-43f096e58e85,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:156c1307-6ce0-4172-9755-bd2287e50583,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0,EDM:-3,IP :nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_ULN,TF_CID_SPAM_SNR X-UUID: 590c1deca27011ef99858b75a2457dd9-20241114 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 778533351; Thu, 14 Nov 2024 18:08:08 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 14 Nov 2024 02:08:07 -0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 14 Nov 2024 18:08:07 +0800 From: Liju-clr Chen To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Catalin Marinas , Will Deacon , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Richard Cochran , Matthias Brugger , AngeloGioacchino Del Regno , Liju-clr Chen , Yingshiuan Pan , Ze-yu Wang CC: , , , , , , , Shawn Hsiao , PeiLun Suei , Chi-shen Yeh , Kevenny Hsieh Subject: [PATCH v13 25/25] virt: geniezone: Reduce blocked duration in hypervisor when destroying a VM Date: Thu, 14 Nov 2024 18:08:02 +0800 Message-ID: <20241114100802.4116-26-liju-clr.chen@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241114100802.4116-1-liju-clr.chen@mediatek.com> References: <20241114100802.4116-1-liju-clr.chen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jerry Wang Reduce the blocked duration in the hypervisor when destroying a VM by splitting a single hypercall into multiple calls. Previously, the hypervisor could be blocked for an extended period when destroying a VM, as the entire process was handled in a single hypercall. This could lead to performance degradation because the scheduler does not have chances to schedule other tasks when the hypercall is processing by the hypervisor. By splitting the destruction process into multiple smaller hypercalls, significantly reduce the blocked duration in the hypervisor. Additionally, making the amount of each call adjustable provides flexibility to optimize the process based on different workloads and system configurations. Signed-off-by: Jerry Wang Signed-off-by: Liju Chen --- arch/arm64/geniezone/vm.c | 27 ++++++++++-- drivers/virt/geniezone/gzvm_main.c | 62 +++++++++++++++++++++++++++ drivers/virt/geniezone/gzvm_vm.c | 2 +- include/linux/soc/mediatek/gzvm_drv.h | 7 ++- include/uapi/linux/gzvm.h | 1 + 5 files changed, 94 insertions(+), 5 deletions(-) diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index cfd0aeb865e5..fb4e5dd41002 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -175,12 +175,18 @@ int gzvm_arch_create_vm(unsigned long vm_type) return ret ? ret : res.a1; } =20 -int gzvm_arch_destroy_vm(u16 vm_id) +int gzvm_arch_destroy_vm(u16 vm_id, u64 destroy_page_gran) { struct arm_smccc_res res; + int ret; + + do { + ret =3D gzvm_hypcall_wrapper(MT_HVC_GZVM_DESTROY_VM, vm_id, + destroy_page_gran, 0, 0, + 0, 0, 0, &res); + } while (ret =3D=3D -EAGAIN); =20 - return gzvm_hypcall_wrapper(MT_HVC_GZVM_DESTROY_VM, vm_id, 0, 0, 0, 0, - 0, 0, &res); + return ret; } =20 int gzvm_arch_memregion_purpose(struct gzvm *gzvm, @@ -241,6 +247,21 @@ int gzvm_arch_query_hyp_batch_pages(struct gzvm_enable= _cap *cap, return ret; } =20 +int gzvm_arch_query_destroy_batch_pages(struct gzvm_enable_cap *cap, + void __user *argp) +{ + struct arm_smccc_res res =3D {0}; + int ret; + + ret =3D gzvm_arch_enable_cap(cap, &res); + // destroy page batch size should be power of 2 + if (ret || ((res.a1 & (res.a1 - 1)) !=3D 0)) + return -EINVAL; + + cap->args[0] =3D res.a1; + return ret; +} + /** * gzvm_vm_ioctl_get_pvmfw_size() - Get pvmfw size from hypervisor, return * in x1, and return to userspace in args diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gz= vm_main.c index 0ec15c33111e..38a2406a16bd 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -49,6 +49,33 @@ static ssize_t demand_paging_batch_pages_store(struct ko= bject *kobj, return count; } =20 +static ssize_t destroy_batch_pages_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", gzvm_drv.destroy_batch_pages); +} + +static ssize_t destroy_batch_pages_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int ret; + u32 temp; + + ret =3D kstrtoint(buf, 10, &temp); + if (ret < 0) + return ret; + + // destroy page batch size should be power of 2 + if ((temp & (temp - 1)) !=3D 0) + return -EINVAL; + + gzvm_drv.destroy_batch_pages =3D temp; + + return count; +} + /* /sys/kernel/gzvm/demand_paging_batch_pages */ static struct kobj_attribute demand_paging_batch_pages_attr =3D { .attr =3D { @@ -59,6 +86,16 @@ static struct kobj_attribute demand_paging_batch_pages_a= ttr =3D { .store =3D demand_paging_batch_pages_store, }; =20 +/* /sys/kernel/gzvm/destroy_batch_pages */ +static struct kobj_attribute destroy_batch_pages_attr =3D { + .attr =3D { + .name =3D "destroy_batch_pages", + .mode =3D 0660, + }, + .show =3D destroy_batch_pages_show, + .store =3D destroy_batch_pages_store, +}; + static int gzvm_drv_sysfs_init(void) { int ret =3D 0; @@ -73,6 +110,11 @@ static int gzvm_drv_sysfs_init(void) if (ret) pr_debug("failed to create demand_batch_pages in /sys/kernel/gzvm\n"); =20 + ret =3D sysfs_create_file(gzvm_drv.sysfs_root_dir, + &destroy_batch_pages_attr.attr); + if (ret) + pr_debug("failed to create destroy_batch_pages in /sys/kernel/gzvm\n"); + return ret; } =20 @@ -124,6 +166,8 @@ int gzvm_err_to_errno(unsigned long err) return -EOPNOTSUPP; case ERR_FAULT: return -EFAULT; + case ERR_BUSY: + return -EAGAIN; default: break; } @@ -220,6 +264,20 @@ static int gzvm_query_hyp_batch_pages(void) return ret; } =20 +static int gzvm_query_destroy_batch_pages(void) +{ + int ret; + struct gzvm_enable_cap cap =3D {0}; + + gzvm_drv.destroy_batch_pages =3D GZVM_DRV_DESTROY_PAGING_BATCH_PAGES; + cap.cap =3D GZVM_CAP_QUERY_DESTROY_BATCH_PAGES; + + ret =3D gzvm_arch_query_destroy_batch_pages(&cap, NULL); + if (!ret) + gzvm_drv.destroy_batch_pages =3D cap.args[0]; + return ret; +} + static int gzvm_drv_probe(struct platform_device *pdev) { int ret; @@ -257,6 +315,10 @@ static int gzvm_drv_probe(struct platform_device *pdev) if (ret) return ret; =20 + ret =3D gzvm_query_destroy_batch_pages(); + if (ret) + return ret; + return 0; } =20 diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm= _vm.c index 999c8c586d7b..43b6cf8b7d3f 100644 --- a/drivers/virt/geniezone/gzvm_vm.c +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -360,7 +360,7 @@ static void gzvm_destroy_vm(struct gzvm *gzvm) =20 gzvm_vm_irqfd_release(gzvm); gzvm_destroy_vcpus(gzvm); - gzvm_arch_destroy_vm(gzvm->vm_id); + gzvm_arch_destroy_vm(gzvm->vm_id, gzvm->gzvm_drv->destroy_batch_pages); =20 mutex_lock(&gzvm_list_lock); list_del(&gzvm->vm_list); diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/medi= atek/gzvm_drv.h index 8fc6c6f54227..b234edb3b9f3 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -30,6 +30,7 @@ struct gzvm_driver { =20 struct kobject *sysfs_root_dir; u32 demand_paging_batch_pages; + u32 destroy_batch_pages; =20 struct dentry *gzvm_debugfs_dir; }; @@ -53,6 +54,7 @@ struct gzvm_driver { #define ERR_INVALID_ARGS (-8) #define ERR_NOT_SUPPORTED (-24) #define ERR_NOT_IMPLEMENTED (-27) +#define ERR_BUSY (-33) #define ERR_FAULT (-40) #define GZVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 =20 @@ -68,6 +70,7 @@ struct gzvm_driver { #define GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE (PMD_SIZE) /* 2MB */ #define GZVM_DRV_DEMAND_PAGING_BATCH_PAGES \ (GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE / PAGE_SIZE) +#define GZVM_DRV_DESTROY_PAGING_BATCH_PAGES (128) =20 #define GZVM_MAX_DEBUGFS_DIR_NAME_SIZE 20 #define GZVM_MAX_DEBUGFS_VALUE_SIZE 20 @@ -225,12 +228,14 @@ int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version); int gzvm_arch_query_hyp_batch_pages(struct gzvm_enable_cap *cap, void __user *argp); +int gzvm_arch_query_destroy_batch_pages(struct gzvm_enable_cap *cap, + void __user *argp); =20 int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size, phys_addr_t region); int gzvm_arch_check_extension(struct gzvm *gzvm, __u64 cap, void __user *a= rgp); int gzvm_arch_create_vm(unsigned long vm_type); -int gzvm_arch_destroy_vm(u16 vm_id); +int gzvm_arch_destroy_vm(u16 vm_id, u64 destroy_page_gran); int gzvm_arch_map_guest(u16 vm_id, int memslot_id, u64 pfn, u64 gfn, u64 nr_pages); int gzvm_arch_map_guest_block(u16 vm_id, int memslot_id, u64 gfn, u64 nr_p= ages); diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h index d69e1abb21a0..87574bdc5c48 100644 --- a/include/uapi/linux/gzvm.h +++ b/include/uapi/linux/gzvm.h @@ -23,6 +23,7 @@ #define GZVM_CAP_ENABLE_DEMAND_PAGING 0x9202 #define GZVM_CAP_ENABLE_IDLE 0x9203 #define GZVM_CAP_QUERY_HYP_BATCH_PAGES 0x9204 +#define GZVM_CAP_QUERY_DESTROY_BATCH_PAGES 0x9205 =20 /* sub-commands put in args[0] for GZVM_CAP_PROTECTED_VM */ #define GZVM_CAP_PVM_SET_PVMFW_GPA 0 --=20 2.18.0