Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp6293622ybl; Mon, 23 Dec 2019 03:36:42 -0800 (PST) X-Google-Smtp-Source: APXvYqzGvqvroVP7ydLb9MN3y4+xOjkHNYFCc0T9UGyLMqzdcUbRNHtVyL/iH8LqZ8F2hwUTHRoH X-Received: by 2002:a9d:3b09:: with SMTP id z9mr32423316otb.195.1577101002702; Mon, 23 Dec 2019 03:36:42 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1577101002; cv=pass; d=google.com; s=arc-20160816; b=kyZPq3HsUcZHPyXJBtnLfKkUjTDz6RoISm1hpA4kirpqvkGDSe9BRu17QmvrRqe8sG SxPgV2TlNjDHSVMNsLSX2OSVSW00TzHwX1RP++2O15NGjgVBg62vvq22QlTorjN0X6JE 8CmpVSnXjnZC1S8L4hYRFIjLpjD4udtskmMuCupx0pzQFFppUuILK2T0JFz7NuWdNxAG mEhB+MPwALWkT2Cp33XUmXyv/5WbID4AZSHH+z15iTIn7LiLrcfKZyroFtrLZ2ZJmH74 Ql0zWGcizcmG6JV1GtR73MrS/tpFEhMjx1T8p8Ftr33cd18E+CJQv5YwDaN3Lg2vpJyW iocQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:content-transfer-encoding :wdcipoutbound:content-language:accept-language:in-reply-to :references:message-id:date:thread-index:thread-topic:subject:cc:to :from:dkim-signature:ironport-sdr:dkim-signature; bh=v2AR6H3JC8G6ut4Rr/Tz/6Bo+PYioutd8OuSlHfO4ow=; b=Atue8kqaDDBmf8Z/4tAtBRH1ncRwQwGcJoIlqeHh503paanK8yOWdK4ZkWkYV3pLl3 NWMl0J27SMAbJgVVompodH1WI07bwdVdk2jowpv35AbFjr0gMxT+6XrJQtrjWgVSNF2a HgVt/wiDgZ/g1BiFtYM9J2n1wsWu+334nrl4t8HgjsOgtYWoDCiSVQuyuk0YdJ7MNXtT wMIUOV/7IixjuI7wtLwdzzot9G//AL5bdMyvSvsL2BFjwK8SktQgYe8XUT30kXL64kav eF1UEyVBDWJhrhk4HYRoD99GCptJxqiQkYY3Z7U4Quw1Jsb3mD42ryn+yNjWv8MeKdUL y0ew== ARC-Authentication-Results: i=2; mx.google.com; dkim=fail header.i=@wdc.com header.s=dkim.wdc.com header.b=Zo1O373S; dkim=pass header.i=@sharedspace.onmicrosoft.com header.s=selector2-sharedspace-onmicrosoft-com header.b=AHp8IXbH; arc=pass (i=1 spf=pass spfdomain=wdc.com dkim=pass dkdomain=wdc.com dmarc=pass fromdomain=wdc.com); spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=wdc.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s5si1296347oic.116.2019.12.23.03.36.31; Mon, 23 Dec 2019 03:36:42 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@wdc.com header.s=dkim.wdc.com header.b=Zo1O373S; dkim=pass header.i=@sharedspace.onmicrosoft.com header.s=selector2-sharedspace-onmicrosoft-com header.b=AHp8IXbH; arc=pass (i=1 spf=pass spfdomain=wdc.com dkim=pass dkdomain=wdc.com dmarc=pass fromdomain=wdc.com); spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=wdc.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727368AbfLWLfu (ORCPT + 99 others); Mon, 23 Dec 2019 06:35:50 -0500 Received: from esa2.hgst.iphmx.com ([68.232.143.124]:29971 "EHLO esa2.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727264AbfLWLft (ORCPT ); Mon, 23 Dec 2019 06:35:49 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1577100967; x=1608636967; h=from:to:cc:subject:date:message-id:references: in-reply-to:content-transfer-encoding:mime-version; bh=XNTMnSXfnzv9tSWngOoxY4MNa+bqiOkVef14aCaNE/I=; b=Zo1O373St78k1+2DHhiJLZhCK8FX8KvjA14s6RphH63c0O6aHmbQjrzY CjZeUHO4X/KLQeApKnw5aU0GdncQPqrdeYtHpzqT2XIaxouCeN4Id+7Go n7FPcMEDliPSR4kMX2p+ZFnvJgjh9gmO/6g6wnO6jCXFIbMueFOICYGny r0CHeNn3OZhoEzvTO3gbAsdFzGGO1HFNpyll2er23oA1MIjN9VqcV9C60 pJg2z2mAcGDh/tjbkyXxbZmjlnHlVGt4PX0kGzwxYhQ0fLog/32t7RPBb 5qh5mYtcuzQ/CdMHS5fnT98Hrcyoi2OEihxgZkEWbTwdW+H3hZg6S8tjJ g==; IronPort-SDR: GFVEv32R2VXT5U82QeXD8PeChzAFN4KS+zSLiQioRV3oMRO/maMNl/DmqcFeiRPMFtNDIsx/vU HTDhfBPivjxwksluC3XwpjlXREe6DF2FHE5RA7ppzok+UfvN9ApXdBPyXkFfTTfgShvFH1Wlz3 +6pv4DTaaZ8GJL8Egd5SyIemxBcWf5PSd8QPYYTwAhv5XdHjZf6TI4Tm6Hu6fUmGoGhisXHKRd 4/EkVw4ZgjdDrBdertkDDhs7hMfNc8/3yGIxS5YEctCldE3vfDB3e2KoNnMQqn/3XF7DfPSQm4 lXo= X-IronPort-AV: E=Sophos;i="5.69,347,1571673600"; d="scan'208";a="227595123" Received: from mail-bn7nam10lp2100.outbound.protection.outlook.com (HELO NAM10-BN7-obe.outbound.protection.outlook.com) ([104.47.70.100]) by ob1.hgst.iphmx.com with ESMTP; 23 Dec 2019 19:36:05 +0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Ab8Yd+WebetaiqPsJVt4MCRdTe9bMrcm1VbM2OFLx0dZlco0SzZGOISgTXPV1G0DWjqk2T1+Nebz7Ik0oM3LyfSuKCzj/8EgNJdpfOoC0AShsxJgA6Bkvc+XaHA9vHI2cAg2VfwQ9YUHwMhC9qp+iw0zG8ORsDT70MkAPJycFcjsuL2K0IAccoDgaRwRu7PcMAKwurROiWmMJkD6ONrUgdOQOAJUPKlBXfWoP8WwetzfNwxApw/XjzUkmj9wc8fBdpaDB14xpVG8Bf/vWliguo3d2Es4COKg3yZPC7eG2BEz0Sf7f5ZUl6pCXWNWT9X+fjQOMjTiska3+55twM8B4A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=v2AR6H3JC8G6ut4Rr/Tz/6Bo+PYioutd8OuSlHfO4ow=; b=TwyMe5oIJng1IYgrq/K3gv3arCPmfGQ1k3wcpN69MZCp1fXoGZlsF/l7whUqi1HsETl6E3egeKPD4dhMgx+tXzdxHvcbryCVHqhb1agZd53Ya/cmlDvkLo68cPchVLoqaLxXhqAWb4tcUtNl/+JVoS8lYEhv/HPHz/+5mepO3MUTkq9ANG6DqbkC2OsyQFZUkk4buMB2KXxDn1g/VqHYwqmDUO2vhi0EXq1QIUKWba9Ld+79zKyl9Qqaoc/jxLCiO/P48MBRltyAZoTmMMzrg6YDwN4DC3FrXoiYZEsfAPdS39zOogXentCeTveh6ECco1mrYlwkG50jXmc8hJmhtA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=wdc.com; dmarc=pass action=none header.from=wdc.com; dkim=pass header.d=wdc.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sharedspace.onmicrosoft.com; s=selector2-sharedspace-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=v2AR6H3JC8G6ut4Rr/Tz/6Bo+PYioutd8OuSlHfO4ow=; b=AHp8IXbHujdxnOVQ8eXBPBh4Xr7gP2pgmIVbDOWjPNSNVgDsnSo+Nk7y0CcEbjxg0wisHpAmuUtJorRNvgBnndTvYbTaMRfuzlWHBn85VkN83QUncGHgwAr5w0y+xO9+7OpBTwmlIrnxQl9r7Doe1d9Q7iPwohAimwhx2AzaM58= Received: from MN2PR04MB6061.namprd04.prod.outlook.com (20.178.246.15) by MN2PR04MB7072.namprd04.prod.outlook.com (10.186.146.20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2559.15; Mon, 23 Dec 2019 11:35:47 +0000 Received: from MN2PR04MB6061.namprd04.prod.outlook.com ([fe80::a9a0:3ffa:371f:ad89]) by MN2PR04MB6061.namprd04.prod.outlook.com ([fe80::a9a0:3ffa:371f:ad89%7]) with mapi id 15.20.2559.017; Mon, 23 Dec 2019 11:35:47 +0000 Received: from wdc.com (106.51.20.238) by MA1PR01CA0077.INDPRD01.PROD.OUTLOOK.COM (2603:1096:a00::17) with Microsoft SMTP Server (version=TLS1_2, cipher=) via Frontend Transport; Mon, 23 Dec 2019 11:35:42 +0000 From: Anup Patel To: Palmer Dabbelt , Paul Walmsley , Albert Ou , Paolo Bonzini , Radim K CC: Alexander Graf , Atish Patra , Alistair Francis , Damien Le Moal , Christoph Hellwig , Anup Patel , "kvm@vger.kernel.org" , "kvm-riscv@lists.infradead.org" , "linux-riscv@lists.infradead.org" , "linux-kernel@vger.kernel.org" , Anup Patel Subject: [PATCH v10 04/19] RISC-V: Add initial skeletal KVM support Thread-Topic: [PATCH v10 04/19] RISC-V: Add initial skeletal KVM support Thread-Index: AQHVuYUetuPn+yonb0qb0Ghjk7YqPw== Date: Mon, 23 Dec 2019 11:35:46 +0000 Message-ID: <20191223113443.68969-5-anup.patel@wdc.com> References: <20191223113443.68969-1-anup.patel@wdc.com> In-Reply-To: <20191223113443.68969-1-anup.patel@wdc.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: MA1PR01CA0077.INDPRD01.PROD.OUTLOOK.COM (2603:1096:a00::17) To MN2PR04MB6061.namprd04.prod.outlook.com (2603:10b6:208:d8::15) authentication-results: spf=none (sender IP is ) smtp.mailfrom=Anup.Patel@wdc.com; x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 2.17.1 x-originating-ip: [106.51.20.238] x-ms-publictraffictype: Email x-ms-office365-filtering-ht: Tenant x-ms-office365-filtering-correlation-id: ce6a3e3a-5cc4-41c7-7b36-08d7879c40ab x-ms-traffictypediagnostic: MN2PR04MB7072: x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: wdcipoutbound: EOP-TRUE x-ms-oob-tlc-oobclassifiers: OLM:175; x-forefront-prvs: 0260457E99 x-forefront-antispam-report: SFV:NSPM;SFS:(10019020)(4636009)(136003)(366004)(376002)(396003)(346002)(39860400002)(199004)(189003)(8886007)(478600001)(52116002)(316002)(16526019)(2906002)(8936002)(1076003)(7696005)(36756003)(66946007)(66476007)(86362001)(66446008)(26005)(64756008)(66556008)(4326008)(5660300002)(8676002)(186003)(7416002)(81156014)(2616005)(956004)(71200400001)(55016002)(44832011)(55236004)(81166006)(1006002)(54906003)(30864003)(110136005)(32040200004)(579004);DIR:OUT;SFP:1102;SCL:1;SRVR:MN2PR04MB7072;H:MN2PR04MB6061.namprd04.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;A:1;MX:1; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: JBL0jV3gHE/h3WW1BCbzwqAMsVXhnAwkFuadWeTDH2mSLZoMf6QMeLjWVeWr2t82L2P4l2GrpPppz7a8YR4vaBjGy1wEpenuU1oE+O+K1xFprT5EgwsHMJoU4UNUpAbmY8D3CtLbjzki0SPkWfwUl05MCe39nkJmBn/5epc+n/nVAB2BmdMlG57hxyV5mS+5JH6dCdhEDbeEzUb5+lMXNMCmguwf20Q41vH3A8DoqimwiXHpMSnqXc1doZlaGPIAFnvIRUz66GfT6O6yuO2/z1lt2AIq0X9YYH5V9Do17nJpP+QJGhwxUIKhA3ke/XNAA0YzNEeUWLnFFRPEdbAmCUY/WAkJFTafvru8PbSrRyC1stY44Y2SV7ZOPfaPzTx6U+hNZVGMYo5ZbfsYZsrM4Pgbl10/K9ZwXwic/jnJ0dVV9T6h1prq4r6CNyazQlfuB4ts++g3LbswMnculGj82BvjXBlA6k4iOLS88asfLCStk6S4/4W8SwJjuPATGHjE Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: wdc.com X-MS-Exchange-CrossTenant-Network-Message-Id: ce6a3e3a-5cc4-41c7-7b36-08d7879c40ab X-MS-Exchange-CrossTenant-originalarrivaltime: 23 Dec 2019 11:35:46.9580 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: b61c8803-16f3-4c35-9b17-6f65f441df86 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: uudY7OZH2eEGvxWQOQWrcdvjmH3nVdPO6nePQxqbkBef45cnGq8S4gZnbKA8VPu1jUCyR8r1RdH5p2zF/d5OdA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR04MB7072 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds initial skeletal KVM RISC-V support which has: 1. A simple implementation of arch specific VM functions except kvm_vm_ioctl_get_dirty_log() which will implemeted in-future as part of stage2 page loging. 2. Stubs of required arch specific VCPU functions except kvm_arch_vcpu_ioctl_run() which is semi-complete and extended by subsequent patches. 3. Stubs for required arch specific stage2 MMU functions. Signed-off-by: Anup Patel Acked-by: Paolo Bonzini Reviewed-by: Paolo Bonzini Reviewed-by: Alexander Graf --- arch/riscv/Kconfig | 2 + arch/riscv/Makefile | 2 + arch/riscv/include/asm/kvm_host.h | 82 ++++++++ arch/riscv/include/uapi/asm/kvm.h | 47 +++++ arch/riscv/kvm/Kconfig | 33 ++++ arch/riscv/kvm/Makefile | 13 ++ arch/riscv/kvm/main.c | 93 +++++++++ arch/riscv/kvm/mmu.c | 83 ++++++++ arch/riscv/kvm/vcpu.c | 316 ++++++++++++++++++++++++++++++ arch/riscv/kvm/vcpu_exit.c | 36 ++++ arch/riscv/kvm/vm.c | 79 ++++++++ 11 files changed, 786 insertions(+) create mode 100644 arch/riscv/include/asm/kvm_host.h create mode 100644 arch/riscv/include/uapi/asm/kvm.h create mode 100644 arch/riscv/kvm/Kconfig create mode 100644 arch/riscv/kvm/Makefile create mode 100644 arch/riscv/kvm/main.c create mode 100644 arch/riscv/kvm/mmu.c create mode 100644 arch/riscv/kvm/vcpu.c create mode 100644 arch/riscv/kvm/vcpu_exit.c create mode 100644 arch/riscv/kvm/vm.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index baf0943c80d0..2e8551a9cd32 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -366,3 +366,5 @@ menu "Power management options" source "kernel/power/Kconfig" =20 endmenu + +source "arch/riscv/kvm/Kconfig" diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index b9009a2fbaf5..65b58cec9abd 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -77,6 +77,8 @@ head-y :=3D arch/riscv/kernel/head.o =20 core-y +=3D arch/riscv/ =20 +core-$(CONFIG_KVM) +=3D arch/riscv/kvm/ + libs-y +=3D arch/riscv/lib/ =20 PHONY +=3D vdso_install diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm= _host.h new file mode 100644 index 000000000000..e0b633f616a4 --- /dev/null +++ b/arch/riscv/include/asm/kvm_host.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#ifndef __RISCV_KVM_HOST_H__ +#define __RISCV_KVM_HOST_H__ + +#include +#include +#include + +#ifdef CONFIG_64BIT +#define KVM_MAX_VCPUS (1U << 16) +#else +#define KVM_MAX_VCPUS (1U << 9) +#endif + +#define KVM_USER_MEM_SLOTS 512 +#define KVM_HALT_POLL_NS_DEFAULT 500000 + +#define KVM_VCPU_MAX_FEATURES 0 + +#define KVM_REQ_SLEEP \ + KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) +#define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(1) + +struct kvm_vm_stat { + ulong remote_tlb_flush; +}; + +struct kvm_vcpu_stat { + u64 halt_successful_poll; + u64 halt_attempted_poll; + u64 halt_poll_invalid; + u64 halt_wakeup; + u64 ecall_exit_stat; + u64 wfi_exit_stat; + u64 mmio_exit_user; + u64 mmio_exit_kernel; + u64 exits; +}; + +struct kvm_arch_memory_slot { +}; + +struct kvm_arch { + /* stage2 page table */ + pgd_t *pgd; + phys_addr_t pgd_phys; +}; + +struct kvm_vcpu_arch { + /* Don't run the VCPU (blocked) */ + bool pause; + + /* SRCU lock index for in-kernel run loop */ + int srcu_idx; +}; + +static inline void kvm_arch_hardware_unsetup(void) {} +static inline void kvm_arch_sync_events(struct kvm *kvm) {} +static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} +static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} + +void kvm_riscv_stage2_flush_cache(struct kvm_vcpu *vcpu); +int kvm_riscv_stage2_alloc_pgd(struct kvm *kvm); +void kvm_riscv_stage2_free_pgd(struct kvm *kvm); +void kvm_riscv_stage2_update_hgatp(struct kvm_vcpu *vcpu); + +int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)= ; +int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long scause, unsigned long stval, + unsigned long htval, unsigned long htinst); + +static inline void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch) = {} + +#endif /* __RISCV_KVM_HOST_H__ */ diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/as= m/kvm.h new file mode 100644 index 000000000000..d15875818b6e --- /dev/null +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#ifndef __LINUX_KVM_RISCV_H +#define __LINUX_KVM_RISCV_H + +#ifndef __ASSEMBLY__ + +#include +#include + +#define __KVM_HAVE_READONLY_MEM + +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + +/* for KVM_GET_REGS and KVM_SET_REGS */ +struct kvm_regs { +}; + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { +}; + +/* KVM Debug exit structure */ +struct kvm_debug_exit_arch { +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; + +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + +/* dummy definition */ +struct kvm_sregs { +}; + +#endif + +#endif /* __LINUX_KVM_RISCV_H */ diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig new file mode 100644 index 000000000000..88edd477b3a8 --- /dev/null +++ b/arch/riscv/kvm/Kconfig @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# KVM configuration +# + +source "virt/kvm/Kconfig" + +menuconfig VIRTUALIZATION + bool "Virtualization" + help + Say Y here to get to see options for using your Linux host to run + other operating systems inside virtual machines (guests). + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and + disabled. + +if VIRTUALIZATION + +config KVM + tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)" + depends on RISCV_SBI && MMU + select PREEMPT_NOTIFIERS + select ANON_INODES + select KVM_MMIO + select HAVE_KVM_VCPU_ASYNC_IOCTL + select SRCU + help + Support hosting virtualized guest machines. + + If unsure, say N. + +endif # VIRTUALIZATION diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile new file mode 100644 index 000000000000..37b5a59d4f4f --- /dev/null +++ b/arch/riscv/kvm/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for RISC-V KVM support +# + +common-objs-y =3D $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmi= o.o) + +ccflags-y :=3D -Ivirt/kvm -Iarch/riscv/kvm + +kvm-objs :=3D $(common-objs-y) + +kvm-objs +=3D main.o vm.o mmu.o vcpu.o vcpu_exit.o + +obj-$(CONFIG_KVM) +=3D kvm.o diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c new file mode 100644 index 000000000000..f29768c82fbe --- /dev/null +++ b/arch/riscv/kvm/main.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include +#include +#include + +long kvm_arch_dev_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + return -EINVAL; +} + +int kvm_arch_check_processor_compat(void) +{ + return 0; +} + +int kvm_arch_hardware_setup(void) +{ + return 0; +} + +int kvm_arch_hardware_enable(void) +{ + unsigned long hideleg, hedeleg; + + hedeleg =3D 0; + hedeleg |=3D (1UL << EXC_INST_MISALIGNED); + hedeleg |=3D (1UL << EXC_BREAKPOINT); + hedeleg |=3D (1UL << EXC_SYSCALL); + hedeleg |=3D (1UL << EXC_INST_PAGE_FAULT); + hedeleg |=3D (1UL << EXC_LOAD_PAGE_FAULT); + hedeleg |=3D (1UL << EXC_STORE_PAGE_FAULT); + csr_write(CSR_HEDELEG, hedeleg); + + hideleg =3D 0; + hideleg |=3D (1UL << IRQ_S_SOFT); + hideleg |=3D (1UL << IRQ_S_TIMER); + hideleg |=3D (1UL << IRQ_S_EXT); + csr_write(CSR_HIDELEG, hideleg); + + csr_write(CSR_HIP, 0); + + return 0; +} + +void kvm_arch_hardware_disable(void) +{ + csr_write(CSR_HEDELEG, 0); + csr_write(CSR_HIDELEG, 0); +} + +int kvm_arch_init(void *opaque) +{ + if (!riscv_isa_extension_available(NULL, h)) { + kvm_info("hypervisor extension not available\n"); + return -ENODEV; + } + + if (sbi_spec_is_0_1()) { + kvm_info("require SBI v0.2 or higher\n"); + return -ENODEV; + } + + if (sbi_probe_extension(SBI_EXT_RFENCE) <=3D 0) { + kvm_info("require SBI RFENCE extension\n"); + return -ENODEV; + } + + kvm_info("hypervisor extension available\n"); + + return 0; +} + +void kvm_arch_exit(void) +{ +} + +static int riscv_kvm_init(void) +{ + return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); +} +module_init(riscv_kvm_init); diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c new file mode 100644 index 000000000000..04dd089b86ff --- /dev/null +++ b/arch/riscv/kvm/mmu.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free, + struct kvm_memory_slot *dont) +{ +} + +int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot, + unsigned long npages) +{ + return 0; +} + +void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) +{ +} + +void kvm_arch_flush_shadow_all(struct kvm *kvm) +{ + /* TODO: */ +} + +void kvm_arch_flush_shadow_memslot(struct kvm *kvm, + struct kvm_memory_slot *slot) +{ +} + +void kvm_arch_commit_memory_region(struct kvm *kvm, + const struct kvm_userspace_memory_region *mem, + const struct kvm_memory_slot *old, + const struct kvm_memory_slot *new, + enum kvm_mr_change change) +{ + /* TODO: */ +} + +int kvm_arch_prepare_memory_region(struct kvm *kvm, + struct kvm_memory_slot *memslot, + const struct kvm_userspace_memory_region *mem, + enum kvm_mr_change change) +{ + /* TODO: */ + return 0; +} + +void kvm_riscv_stage2_flush_cache(struct kvm_vcpu *vcpu) +{ + /* TODO: */ +} + +int kvm_riscv_stage2_alloc_pgd(struct kvm *kvm) +{ + /* TODO: */ + return 0; +} + +void kvm_riscv_stage2_free_pgd(struct kvm *kvm) +{ + /* TODO: */ +} + +void kvm_riscv_stage2_update_hgatp(struct kvm_vcpu *vcpu) +{ + /* TODO: */ +} diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c new file mode 100644 index 000000000000..bd7d6b154f61 --- /dev/null +++ b/arch/riscv/kvm/vcpu.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCP= U } + +struct kvm_stats_debugfs_item debugfs_entries[] =3D { + VCPU_STAT(ecall_exit_stat), + VCPU_STAT(wfi_exit_stat), + VCPU_STAT(mmio_exit_user), + VCPU_STAT(mmio_exit_kernel), + VCPU_STAT(exits), + { NULL } +}; + +struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) +{ + /* TODO: */ + return NULL; +} + +int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) +{ + return 0; +} + +void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) +{ +} + +int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) +{ + /* TODO: */ + return 0; +} + +void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) +{ + /* TODO: */ +} + +int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) +{ + /* TODO: */ + return 0; +} + +void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) +{ +} + +void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) +{ +} + +int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) +{ + /* TODO: */ + return 0; +} + +int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) +{ + /* TODO: */ + return 0; +} + +bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) +{ + /* TODO: */ + return false; +} + +bool kvm_arch_has_vcpu_debugfs(void) +{ + return false; +} + +int kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu) +{ + return 0; +} + +vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf= ) +{ + return VM_FAULT_SIGBUS; +} + +long kvm_arch_vcpu_async_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + /* TODO; */ + return -ENOIOCTLCMD; +} + +long kvm_arch_vcpu_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + /* TODO: */ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) +{ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) +{ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu= ) +{ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu= ) +{ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, + struct kvm_translation *tr) +{ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *r= egs) +{ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *r= egs) +{ + return -EINVAL; +} + +int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, + struct kvm_mp_state *mp_state) +{ + /* TODO: */ + return 0; +} + +int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, + struct kvm_mp_state *mp_state) +{ + /* TODO: */ + return 0; +} + +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + /* TODO; To be implemented later. */ + return -EINVAL; +} + +void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +{ + /* TODO: */ + + kvm_riscv_stage2_update_hgatp(vcpu); +} + +void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) +{ + /* TODO: */ +} + +static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu) +{ + /* TODO: */ +} + +int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + int ret; + unsigned long scause, stval, htval, htinst; + + vcpu->arch.srcu_idx =3D srcu_read_lock(&vcpu->kvm->srcu); + + /* Process MMIO value returned from user-space */ + if (run->exit_reason =3D=3D KVM_EXIT_MMIO) { + ret =3D kvm_riscv_vcpu_mmio_return(vcpu, vcpu->run); + if (ret) { + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); + return ret; + } + } + + if (run->immediate_exit) { + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); + return -EINTR; + } + + vcpu_load(vcpu); + + kvm_sigset_activate(vcpu); + + ret =3D 1; + run->exit_reason =3D KVM_EXIT_UNKNOWN; + while (ret > 0) { + /* Check conditions before entering the guest */ + cond_resched(); + + kvm_riscv_check_vcpu_requests(vcpu); + + preempt_disable(); + + local_irq_disable(); + + /* + * Exit if we have a signal pending so that we can deliver + * the signal to user space. + */ + if (signal_pending(current)) { + ret =3D -EINTR; + run->exit_reason =3D KVM_EXIT_INTR; + } + + /* + * Ensure we set mode to IN_GUEST_MODE after we disable + * interrupts and before the final VCPU requests check. + * See the comment in kvm_vcpu_exiting_guest_mode() and + * Documentation/virtual/kvm/vcpu-requests.rst + */ + vcpu->mode =3D IN_GUEST_MODE; + + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); + smp_mb__after_srcu_read_unlock(); + + if (ret <=3D 0 || + kvm_request_pending(vcpu)) { + vcpu->mode =3D OUTSIDE_GUEST_MODE; + local_irq_enable(); + preempt_enable(); + vcpu->arch.srcu_idx =3D srcu_read_lock(&vcpu->kvm->srcu); + continue; + } + + guest_enter_irqoff(); + + __kvm_riscv_switch_to(&vcpu->arch); + + vcpu->mode =3D OUTSIDE_GUEST_MODE; + vcpu->stat.exits++; + + /* + * Save SCAUSE, STVAL, HTVAL, and HTINST because we might + * get an interrupt between __kvm_riscv_switch_to() and + * local_irq_enable() which can potentially change CSRs. + */ + scause =3D csr_read(CSR_SCAUSE); + stval =3D csr_read(CSR_STVAL); + htval =3D csr_read(CSR_HTVAL); + htinst =3D csr_read(CSR_HTINST); + + /* + * We may have taken a host interrupt in VS/VU-mode (i.e. + * while executing the guest). This interrupt is still + * pending, as we haven't serviced it yet! + * + * We're now back in HS-mode with interrupts disabled + * so enabling the interrupts now will have the effect + * of taking the interrupt again, in HS-mode this time. + */ + local_irq_enable(); + + /* + * We do local_irq_enable() before calling guest_exit() so + * that if a timer interrupt hits while running the guest + * we account that tick as being spent in the guest. We + * enable preemption after calling guest_exit() so that if + * we get preempted we make sure ticks after that is not + * counted as guest time. + */ + guest_exit(); + + preempt_enable(); + + vcpu->arch.srcu_idx =3D srcu_read_lock(&vcpu->kvm->srcu); + + ret =3D kvm_riscv_vcpu_exit(vcpu, run, + scause, stval, htval, htinst); + } + + kvm_sigset_deactivate(vcpu); + + vcpu_put(vcpu); + + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); + + return ret; +} diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c new file mode 100644 index 000000000000..dcea9ce4e728 --- /dev/null +++ b/arch/riscv/kvm/vcpu_exit.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include + +/** + * kvm_riscv_vcpu_mmio_return -- Handle MMIO loads after user space emulat= ion + * or in-kernel IO emulation + * + * @vcpu: The VCPU pointer + * @run: The VCPU run struct containing the mmio data + */ +int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + /* TODO: */ + return 0; +} + +/* + * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on + * proper exit to userspace. + */ +int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long scause, unsigned long stval, + unsigned long htval, unsigned long htinst) +{ + /* TODO: */ + return 0; +} diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c new file mode 100644 index 000000000000..ac0211820521 --- /dev/null +++ b/arch/riscv/kvm/vm.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include + +int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) +{ + /* TODO: To be added later. */ + return -ENOTSUPP; +} + +int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) +{ + int r; + + r =3D kvm_riscv_stage2_alloc_pgd(kvm); + if (r) + return r; + + return 0; +} + +void kvm_arch_destroy_vm(struct kvm *kvm) +{ + int i; + + for (i =3D 0; i < KVM_MAX_VCPUS; ++i) { + if (kvm->vcpus[i]) { + kvm_arch_vcpu_destroy(kvm->vcpus[i]); + kvm->vcpus[i] =3D NULL; + } + } +} + +int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) +{ + int r; + + switch (ext) { + case KVM_CAP_DEVICE_CTRL: + case KVM_CAP_USER_MEMORY: + case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: + case KVM_CAP_ONE_REG: + case KVM_CAP_READONLY_MEM: + case KVM_CAP_MP_STATE: + case KVM_CAP_IMMEDIATE_EXIT: + r =3D 1; + break; + case KVM_CAP_NR_VCPUS: + r =3D num_online_cpus(); + break; + case KVM_CAP_MAX_VCPUS: + r =3D KVM_MAX_VCPUS; + break; + case KVM_CAP_NR_MEMSLOTS: + r =3D KVM_USER_MEM_SLOTS; + break; + default: + r =3D 0; + break; + } + + return r; +} + +long kvm_arch_vm_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + return -EINVAL; +} --=20 2.17.1