Message ID | 20230220065735.1282809-3-zhaotianrui@loongson.cn |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp1165929wrn; Sun, 19 Feb 2023 22:59:25 -0800 (PST) X-Google-Smtp-Source: AK7set/9J/Ue8IKk14pxvdYy0a36HP04Iqa+4Ahdoyqg/wlUJZjeAI2RlxuTYPOL8ghAQWVXC4UF X-Received: by 2002:a17:902:ced2:b0:19a:b57c:117 with SMTP id d18-20020a170902ced200b0019ab57c0117mr3405267plg.29.1676876364682; Sun, 19 Feb 2023 22:59:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1676876364; cv=none; d=google.com; s=arc-20160816; b=00i0vW71Dgo9JBML0yCICC+ggo9rjYYAGxdeL7HxKfoGbohYImUkBd/BflVHa14ElJ mhgtqBuDkZgjAFz4uiI/mEfXFtd7HAdPT5u/jUgOBQLUVQ0tjrPywEgt+Nxq/46lrkwT mg0iNCNgtDN5/oQS4BSTqqcAdttYWsBHEJM9JBtJ2Ee+q/lSP43cNyLTQibMYTwwLqJi ODwZZkF5nf9mY6P/U8UQJnS//wqMQY14LVaT4MkpH4y1Rk0v+ibuoSP3yVgObyLbx5Sp 0HpVqrfUE3IwOPYVDwt0Y8z2dF6PThPj7fZOayeJcsQEnZhOndPU37g4XBO21oCPsBru MdQw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=NFKz1wPL7hH2g5Ytlw2eCcUdSRa6MdToFWP6KDAI/Yw=; b=HyKxgJZbSZWDHlYEghbMFkKDRnoeVRyelKvQ5zMsHkgrTxRu6YW09CZxUWrTsNj+9s 6rJ+FNC6lWwK2+BQmxSCYI8soLmpsws9+JUf1lZLgmH5SoZjY2odZJ0ZjbIP2R7FH+2V iKNIvuHMGdQN6AKpmypUOQfj7vBMBaTUuP/qQODfSdiWBd68qAeGcBycQSEIzRu0LG2b o4lwEeFBR2dz5V6yHKhRZx4xl8SsCMMnyAzmH5eZ/vhXCwZzor6p+sDp+Q/rWgRtJu/h Js3qbLFMM+Rqz3cu6zlw8J3cGMpdywp89N6WB6vOAQikrtUEGEg27rXJBMtuNDBrYec4 e/Eg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id b5-20020a170902e94500b0019c33efefb7si7753831pll.540.2023.02.19.22.59.11; Sun, 19 Feb 2023 22:59:24 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230340AbjBTG5q (ORCPT <rfc822;kautuk.consul.80@gmail.com> + 99 others); Mon, 20 Feb 2023 01:57:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35276 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229669AbjBTG5m (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 20 Feb 2023 01:57:42 -0500 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 68E26FF35; Sun, 19 Feb 2023 22:57:38 -0800 (PST) Received: from loongson.cn (unknown [10.2.5.185]) by gateway (Coremail) with SMTP id _____8AxUU_hGfNjELQCAA--.65S3; Mon, 20 Feb 2023 14:57:37 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.5.185]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Ax+73fGfNjFvk2AA--.34690S4; Mon, 20 Feb 2023 14:57:36 +0800 (CST) From: Tianrui Zhao <zhaotianrui@loongson.cn> To: Paolo Bonzini <pbonzini@redhat.com> Cc: Huacai Chen <chenhuacai@kernel.org>, WANG Xuerui <kernel@xen0n.name>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Jens Axboe <axboe@kernel.dk>, Mark Brown <broonie@kernel.org>, Alex Deucher <alexander.deucher@amd.com>, Oliver Upton <oliver.upton@linux.dev>, maobibo@loongson.cn Subject: [PATCH v2 02/29] LoongArch: KVM: Implement kvm module related interface Date: Mon, 20 Feb 2023 14:57:08 +0800 Message-Id: <20230220065735.1282809-3-zhaotianrui@loongson.cn> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20230220065735.1282809-1-zhaotianrui@loongson.cn> References: <20230220065735.1282809-1-zhaotianrui@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CM-TRANSID: AQAAf8Ax+73fGfNjFvk2AA--.34690S4 X-CM-SenderInfo: p2kd03xldq233l6o00pqjv00gofq/ X-Coremail-Antispam: 1Uk129KBjvJXoWxXFWfWFW7Wry8Ary5WF1Dtrb_yoW5GFykpa 47urn5Jr48Jwn7X3ZIy3Wqvry5WrWkKF1I9a42va4Yy3srtr1q9w4kJr9FvFyxZ3ykJF4F vas5XFsxWF1DX3DanT9S1TB71UUUUjJqnTZGkaVYY2UrUUUUj1kv1TuYvTs0mT0YCTnIWj qI5I8CrVACY4xI64kE6c02F40Ex7xfYxn0WfASr-VFAUDa7-sFnT9fnUUIcSsGvfJTRUUU bckFc2x0x2IEx4CE42xK8VAvwI8IcIk0rVWrJVCq3wA2ocxC64kIII0Yj41l84x0c7CEw4 AK67xGY2AK021l84ACjcxK6xIIjxv20xvE14v26ryj6F1UM28EF7xvwVC0I7IYx2IY6xkF 7I0E14v26r4j6F4UM28EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7 CjxVAFwI0_Gr1j6F4UJwAaw2AFwI0_JF0_Jw1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAq jxCEc2xF0cIa020Ex4CE44I27wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E74AGY7Cv6c x26rWlOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JMxkF7I0En4kS14v26r12 6r1DMxAIw28IcxkI7VAKI48JMxAIw28IcVCjz48v1sIEY20_WwCFx2IqxVCFs4IE7xkEbV WUJVW8JwCFI7km07C267AKxVWUAVWUtwC20s026c02F40E14v26r1j6r18MI8I3I0E7480 Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7 IYx2IY67AKxVW8JVW5JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04k2 6cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4UMIIF0xvEx4A2jsIEc7CjxV AFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x0zR9iSdUUUUU= X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_PASS, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1758332310905439154?= X-GMAIL-MSGID: =?utf-8?q?1758332310905439154?= |
Series |
Add KVM LoongArch support
|
|
Commit Message
zhaotianrui
Feb. 20, 2023, 6:57 a.m. UTC
Implement loongarch kvm module init, module exit interface,
using kvm context to save the vpid info and vcpu world switch
interface pointer.
Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn>
---
arch/loongarch/kvm/main.c | 81 +++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100644 arch/loongarch/kvm/main.c
Comments
On 2/20/23 07:57, Tianrui Zhao wrote: > + order = get_order(kvm_vector_size + kvm_enter_guest_size); > + addr = (void *)__get_free_pages(GFP_KERNEL, order); > + if (!addr) { > + free_percpu(vmcs); > + return -ENOMEM; > + } > + > + memcpy(addr, kvm_vector_entry, kvm_vector_size); > + memcpy(addr + kvm_vector_size, kvm_enter_guest, kvm_enter_guest_size); > + flush_icache_range((unsigned long)addr, (unsigned long)addr + > + kvm_vector_size + kvm_enter_guest_size); > + > + vpid_mask = read_csr_gstat(); > + vpid_mask = (vpid_mask & CSR_GSTAT_GIDBIT) >> CSR_GSTAT_GIDBIT_SHIFT; > + if (vpid_mask) > + vpid_mask = GENMASK(vpid_mask - 1, 0); > + > + for_each_possible_cpu(cpu) { > + context = per_cpu_ptr(vmcs, cpu); > + context->vpid_mask = vpid_mask; > + context->vpid_cache = context->vpid_mask + 1; > + context->last_vcpu = NULL; > + context->kvm_eentry = addr; > + context->kvm_enter_guest = addr + kvm_vector_size; > + context->page_order = order; > + } A lot of these variables are constant across all pCPUs, any reason to have them in a per-CPU variable? Likewise, since they are all the same as the constant global vmcs variable, why make them part of struct kvm_context instead of just making them globals? Also, why does the world switch code need a copy? Paolo
在 2023年02月21日 01:46, Paolo Bonzini 写道: > On 2/20/23 07:57, Tianrui Zhao wrote: >> + order = get_order(kvm_vector_size + kvm_enter_guest_size); >> + addr = (void *)__get_free_pages(GFP_KERNEL, order); >> + if (!addr) { >> + free_percpu(vmcs); >> + return -ENOMEM; >> + } >> + >> + memcpy(addr, kvm_vector_entry, kvm_vector_size); >> + memcpy(addr + kvm_vector_size, kvm_enter_guest, >> kvm_enter_guest_size); >> + flush_icache_range((unsigned long)addr, (unsigned long)addr + >> + kvm_vector_size + kvm_enter_guest_size); >> + >> + vpid_mask = read_csr_gstat(); >> + vpid_mask = (vpid_mask & CSR_GSTAT_GIDBIT) >> >> CSR_GSTAT_GIDBIT_SHIFT; >> + if (vpid_mask) >> + vpid_mask = GENMASK(vpid_mask - 1, 0); >> + >> + for_each_possible_cpu(cpu) { >> + context = per_cpu_ptr(vmcs, cpu); >> + context->vpid_mask = vpid_mask; >> + context->vpid_cache = context->vpid_mask + 1; >> + context->last_vcpu = NULL; >> + context->kvm_eentry = addr; >> + context->kvm_enter_guest = addr + kvm_vector_size; >> + context->page_order = order; >> + } > > A lot of these variables are constant across all pCPUs, any reason to > have them in a per-CPU variable? Likewise, since they are all the > same as the constant global vmcs variable, why make them part of > struct kvm_context instead of just making them globals? Ok thanks, it is more appropriate to use global variables to save those information. Thanks Tianrui Zhao > > Also, why does the world switch code need a copy? > > Paolo
在 2023/2/21 01:46, Paolo Bonzini 写道: > On 2/20/23 07:57, Tianrui Zhao wrote: >> + order = get_order(kvm_vector_size + kvm_enter_guest_size); >> + addr = (void *)__get_free_pages(GFP_KERNEL, order); >> + if (!addr) { >> + free_percpu(vmcs); >> + return -ENOMEM; >> + } >> + >> + memcpy(addr, kvm_vector_entry, kvm_vector_size); >> + memcpy(addr + kvm_vector_size, kvm_enter_guest, kvm_enter_guest_size); >> + flush_icache_range((unsigned long)addr, (unsigned long)addr + >> + kvm_vector_size + kvm_enter_guest_size); >> + >> + vpid_mask = read_csr_gstat(); >> + vpid_mask = (vpid_mask & CSR_GSTAT_GIDBIT) >> CSR_GSTAT_GIDBIT_SHIFT; >> + if (vpid_mask) >> + vpid_mask = GENMASK(vpid_mask - 1, 0); >> + >> + for_each_possible_cpu(cpu) { >> + context = per_cpu_ptr(vmcs, cpu); >> + context->vpid_mask = vpid_mask; >> + context->vpid_cache = context->vpid_mask + 1; >> + context->last_vcpu = NULL; >> + context->kvm_eentry = addr; >> + context->kvm_enter_guest = addr + kvm_vector_size; >> + context->page_order = order; >> + } > > A lot of these variables are constant across all pCPUs, any reason to have them in a per-CPU variable? Likewise, since they are all the same as the constant global vmcs variable, why make them part of struct kvm_context instead of just making them globals? > Paolo, Thanks for reviewing these patches. Originally we think that global variables make c files depending with each other, and global variables is not faster than percpu, so that we removes global variables. we are ok to make them globals. > Also, why does the world switch code need a copy? There will be problem in world switch code if there is page fault reenter, since pgd register is shared between root kernel and kvm hypervisor. World switch entry need be unmapped area, cannot be tlb mapped area. In future if hw pagetable walking is supported, or there is separate pgd registers between root kernel and kvm hypervisor, copying about world switch code will not be used. Regards Bibo, Mao > > Paolo
On 2/21/23 07:59, maobibo wrote: >> Also, why does the world switch code need a copy? > There will be problem in world switch code if there is page fault reenter, > since pgd register is shared between root kernel and kvm hypervisor. > World switch entry need be unmapped area, cannot be tlb mapped area. So if I understand correctly the processor is in direct address translation mode until the "csrwr t0, LOONGARCH_CSR_CRMD" instruction. Where does it leave paged mode? Can you please also add comments to kvm_vector_entry explaining the processor state after a VZ exception entry (interrupts, paging, ...)? Paolo
在 2023/2/21 16:14, Paolo Bonzini 写道: > On 2/21/23 07:59, maobibo wrote: >>> Also, why does the world switch code need a copy? >> There will be problem in world switch code if there is page fault reenter, >> since pgd register is shared between root kernel and kvm hypervisor. >> World switch entry need be unmapped area, cannot be tlb mapped area. > > So if I understand correctly the processor is in direct address translation mode until the "csrwr t0, LOONGARCH_CSR_CRMD" instruction. Where does it leave paged mode? The processor still in paged mode during world switch context. For example when vm exits from guest mode to root mode, it executes world switch code from kvm_vector_entry, PC register points to HVA address, however vmid from LOONGARCH_CSR_GTLBC is not clear to root mode. If there is page fault exception, hardware treats it exception from GPA-->HPA rather than that from HVA --> HPA, since vmid info in CSR_GTLBC is not zero. In page mode, there are two kinds of address: unmapped address and tlb mapped address. For unmapped address there is only cachable/uncachable attribution, but not RWX attr; and there is no tlb handling for it. For simplicity, unmapped address can be treated as window filtered address. It will be fully root mode only after this piece of code is executed during world switch context; vmid is zero and PC points to HVA. ori t0, zero, CSR_GSTAT_PVM csrxchg zero, t0, LOONGARCH_CSR_GSTAT /* Clear GTLBC.TGID field */ csrrd t0, LOONGARCH_CSR_GTLBC bstrins.w t0, zero, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT csrwr t0, LOONGARCH_CSR_GTLBC > > Can you please also add comments to kvm_vector_entry explaining the processor state after a VZ exception entry (interrupts, paging, ...)? Yeap, we will add more comments about these critical exception entry. Regards Bibo, Mao > > Paolo
On 2023/2/21 18:18, maobibo wrote: > > > 在 2023/2/21 16:14, Paolo Bonzini 写道: >> On 2/21/23 07:59, maobibo wrote: >>>> Also, why does the world switch code need a copy? >>> There will be problem in world switch code if there is page fault reenter, >>> since pgd register is shared between root kernel and kvm hypervisor. >>> World switch entry need be unmapped area, cannot be tlb mapped area. >> >> So if I understand correctly the processor is in direct address translation mode until the "csrwr t0, LOONGARCH_CSR_CRMD" instruction. Where does it leave paged mode? > The processor still in paged mode during world switch context. For example > when vm exits from guest mode to root mode, it executes world switch code > from kvm_vector_entry, PC register points to HVA address, however vmid from > LOONGARCH_CSR_GTLBC is not clear to root mode. If there is page fault > exception, hardware treats it exception from GPA-->HPA rather than that > from HVA --> HPA, since vmid info in CSR_GTLBC is not zero. > > In page mode, there are two kinds of address: unmapped address and > tlb mapped address. For unmapped address there is only cachable/uncachable > attribution, but not RWX attr; and there is no tlb handling for it. > For simplicity, unmapped address can be treated as window filtered address. > > It will be fully root mode only after this piece of code is executed > during world switch context; vmid is zero and PC points to HVA. > ori t0, zero, CSR_GSTAT_PVM > csrxchg zero, t0, LOONGARCH_CSR_GSTAT > /* Clear GTLBC.TGID field */ > csrrd t0, LOONGARCH_CSR_GTLBC > bstrins.w t0, zero, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT > csrwr t0, LOONGARCH_CSR_GTLBC AFAIK all of these is probably coming from Volume 3 of LoongArch ISA Manual, which is unfortunately not publicly available at the moment. For sake of meaningful reviews, when can we expect to get our hands on the manuals?
在 2023/2/21 18:37, WANG Xuerui 写道: > On 2023/2/21 18:18, maobibo wrote: >> >> >> 在 2023/2/21 16:14, Paolo Bonzini 写道: >>> On 2/21/23 07:59, maobibo wrote: >>>>> Also, why does the world switch code need a copy? >>>> There will be problem in world switch code if there is page fault reenter, >>>> since pgd register is shared between root kernel and kvm hypervisor. >>>> World switch entry need be unmapped area, cannot be tlb mapped area. >>> >>> So if I understand correctly the processor is in direct address translation mode until the "csrwr t0, LOONGARCH_CSR_CRMD" instruction. Where does it leave paged mode? >> The processor still in paged mode during world switch context. For example >> when vm exits from guest mode to root mode, it executes world switch code >> from kvm_vector_entry, PC register points to HVA address, however vmid from >> LOONGARCH_CSR_GTLBC is not clear to root mode. If there is page fault >> exception, hardware treats it exception from GPA-->HPA rather than that >> from HVA --> HPA, since vmid info in CSR_GTLBC is not zero. >> >> In page mode, there are two kinds of address: unmapped address and >> tlb mapped address. For unmapped address there is only cachable/uncachable >> attribution, but not RWX attr; and there is no tlb handling for it. >> For simplicity, unmapped address can be treated as window filtered address. >> >> It will be fully root mode only after this piece of code is executed >> during world switch context; vmid is zero and PC points to HVA. >> ori t0, zero, CSR_GSTAT_PVM >> csrxchg zero, t0, LOONGARCH_CSR_GSTAT >> /* Clear GTLBC.TGID field */ >> csrrd t0, LOONGARCH_CSR_GTLBC >> bstrins.w t0, zero, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT >> csrwr t0, LOONGARCH_CSR_GTLBC > > AFAIK all of these is probably coming from Volume 3 of LoongArch ISA Manual, which is unfortunately not publicly available at the moment. For sake of meaningful reviews, when can we expect to get our hands on the manuals? We are pushing to public the virtualization manual inside, it is convenient to sw developer to review the code. However I am not sure about the date :( Regards Bibo, Mao >
On 2023/2/21 19:39, maobibo wrote: > > > 在 2023/2/21 18:37, WANG Xuerui 写道: >> On 2023/2/21 18:18, maobibo wrote: >>> >>> >>> 在 2023/2/21 16:14, Paolo Bonzini 写道: >>>> On 2/21/23 07:59, maobibo wrote: >>>>>> Also, why does the world switch code need a copy? >>>>> There will be problem in world switch code if there is page fault reenter, >>>>> since pgd register is shared between root kernel and kvm hypervisor. >>>>> World switch entry need be unmapped area, cannot be tlb mapped area. >>>> >>>> So if I understand correctly the processor is in direct address translation mode until the "csrwr t0, LOONGARCH_CSR_CRMD" instruction. Where does it leave paged mode? >>> The processor still in paged mode during world switch context. For example >>> when vm exits from guest mode to root mode, it executes world switch code >>> from kvm_vector_entry, PC register points to HVA address, however vmid from >>> LOONGARCH_CSR_GTLBC is not clear to root mode. If there is page fault >>> exception, hardware treats it exception from GPA-->HPA rather than that >>> from HVA --> HPA, since vmid info in CSR_GTLBC is not zero. >>> >>> In page mode, there are two kinds of address: unmapped address and >>> tlb mapped address. For unmapped address there is only cachable/uncachable >>> attribution, but not RWX attr; and there is no tlb handling for it. >>> For simplicity, unmapped address can be treated as window filtered address. >>> >>> It will be fully root mode only after this piece of code is executed >>> during world switch context; vmid is zero and PC points to HVA. >>> ori t0, zero, CSR_GSTAT_PVM >>> csrxchg zero, t0, LOONGARCH_CSR_GSTAT >>> /* Clear GTLBC.TGID field */ >>> csrrd t0, LOONGARCH_CSR_GTLBC >>> bstrins.w t0, zero, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT >>> csrwr t0, LOONGARCH_CSR_GTLBC >> >> AFAIK all of these is probably coming from Volume 3 of LoongArch ISA Manual, which is unfortunately not publicly available at the moment. For sake of meaningful reviews, when can we expect to get our hands on the manuals? > We are pushing to public the virtualization manual inside, it is convenient > to sw developer to review the code. However I am not sure about the date :( Well, that's kinda expected, but it's nice to see some progress and certainly your open attitude to this matter is constructive. Thanks for sharing this and looking forward to the eventual docs release then!
diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c new file mode 100644 index 000000000..d7969d02a --- /dev/null +++ b/arch/loongarch/kvm/main.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited + */ + +#include <linux/err.h> +#include <linux/module.h> +#include <linux/kvm_host.h> +#include <asm/kvm_host.h> +#include <asm/cacheflush.h> + +static struct kvm_context __percpu *vmcs; + +int kvm_arch_init(void *opaque) +{ + struct kvm_context *context; + unsigned long vpid_mask; + int cpu, order; + void *addr; + + vmcs = alloc_percpu(struct kvm_context); + if (!vmcs) { + pr_err("kvm: failed to allocate percpu kvm_context\n"); + return -ENOMEM; + } + + order = get_order(kvm_vector_size + kvm_enter_guest_size); + addr = (void *)__get_free_pages(GFP_KERNEL, order); + if (!addr) { + free_percpu(vmcs); + return -ENOMEM; + } + + memcpy(addr, kvm_vector_entry, kvm_vector_size); + memcpy(addr + kvm_vector_size, kvm_enter_guest, kvm_enter_guest_size); + flush_icache_range((unsigned long)addr, (unsigned long)addr + + kvm_vector_size + kvm_enter_guest_size); + + vpid_mask = read_csr_gstat(); + vpid_mask = (vpid_mask & CSR_GSTAT_GIDBIT) >> CSR_GSTAT_GIDBIT_SHIFT; + if (vpid_mask) + vpid_mask = GENMASK(vpid_mask - 1, 0); + + for_each_possible_cpu(cpu) { + context = per_cpu_ptr(vmcs, cpu); + context->vpid_mask = vpid_mask; + context->vpid_cache = context->vpid_mask + 1; + context->last_vcpu = NULL; + context->kvm_eentry = addr; + context->kvm_enter_guest = addr + kvm_vector_size; + context->page_order = order; + } + + _kvm_init_fault(); + + return 0; +} + +void kvm_arch_exit(void) +{ + struct kvm_context *context = per_cpu_ptr(vmcs, 0); + + free_pages((unsigned long)context->kvm_eentry, context->page_order); + free_percpu(vmcs); +} + +static int kvm_loongarch_init(void) +{ + if (!cpu_has_lvz) + return 0; + + return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); +} + +static void kvm_loongarch_exit(void) +{ + kvm_exit(); +} + +module_init(kvm_loongarch_init); +module_exit(kvm_loongarch_exit);