From patchwork Mon Jul 20 11:02:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nastya Vicodin X-Patchwork-Id: 1332196 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=Bcsoe3Cv; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4B9JkG3FyQz9sRN for ; Mon, 20 Jul 2020 21:03:34 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id D58E481EF5; Mon, 20 Jul 2020 13:02:59 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Bcsoe3Cv"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 16F9081EBE; Mon, 20 Jul 2020 13:02:46 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,SPF_HELO_NONE, T_PDS_OTHER_BAD_TLD,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-lj1-x241.google.com (mail-lj1-x241.google.com [IPv6:2a00:1450:4864:20::241]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 0B90481C34 for ; Mon, 20 Jul 2020 13:02:37 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=vicooodin@gmail.com Received: by mail-lj1-x241.google.com with SMTP id r19so19667088ljn.12 for ; Mon, 20 Jul 2020 04:02:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=fZkNNrCgpUhVaG8ZC77svzJnMYlIOqC3LLYTwYgX62k=; b=Bcsoe3CvPLDoCRqIqy2RwAlQSpxekWpXrumgalBUbcDXSJ6a+k4gEYCE8M9Iy17svN S25MEy7hUibeQrlq9FcXe3PiaBFlbGbU2YJUkJ6ZNP7Zglmis4+rUDghqYWbI4SRPW1M xuw/bY10RkJ2gXMPEaJtcPaRjFyMqfguZoxWv0iTqRaYUs37cJ7HDHl+15M2tBoK3nZu fLQrvQVAMWVaIFX4fcQvjEOupmJMXmPwxeZnVTsVfkYLfSArdUFNzBAepdvjCPIWy6Hf 8uK022dw+EcJJ6WhskXeDpNdBhzOxDad8I7J/3dV+lIJTZgIf5MdUlryKxCfL6ieWL3+ inNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=fZkNNrCgpUhVaG8ZC77svzJnMYlIOqC3LLYTwYgX62k=; b=rVbVC3wWsSRkqE33SKh8LfuExyLqQrQU2rjYEfpqZWNPQwjge5uIbHXZN4zHXCcPkc ZUjElPU6Imo+lsLbVuyheOPkjAESxPCai4XwI8rptp8ofaL7ebl0FoyAljc1FChsagL7 tFzuiNcQJ2s+MZiUOTrxwlVLlhtm8H5HWgYm3Ifs2uVGWvTedZf/AUUI+J0r0+65inA7 UpXNN3VNQbUsKWB+soPwzpKd3bsUvx7Cx0aW8xhZlTfXWEGBwo1lTzLpOSip1WiV75Zc XiylYH88r29B0z8i32wC9wL2nBJKyMihztuctkA2+qRRJXJasoSXJ8iINVsGY97nAqjf TK3Q== X-Gm-Message-State: AOAM533Y26mxOKmLJsxC68Zjld7xyqZas57Ap6STMQpUU7Ru3+Gy8z4i pYP+/+IaWkm4R3s4tjzN9lg/+2au32Infg== X-Google-Smtp-Source: ABdhPJxInpIkUyq3XK9Y6rxulZIpa/xT6w4yJvEZ53KgbmDzpO5x9oghvevKzOAttW5298/cLBQmmA== X-Received: by 2002:a2e:958f:: with SMTP id w15mr9572881ljh.190.1595242954924; Mon, 20 Jul 2020 04:02:34 -0700 (PDT) Received: from localhost.localdomain (host-176-36-213-80.la.net.ua. [176.36.213.80]) by smtp.gmail.com with ESMTPSA id l1sm3169130ljc.65.2020.07.20.04.02.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 Jul 2020 04:02:34 -0700 (PDT) From: Anastasiia Lukianenko To: u-boot@lists.denx.de, sjg@chromium.org, ye.li@nxp.com, bmeng.cn@gmail.com, xypron.glpk@gmx.de Cc: julien@xen.org, sstabellini@kernel.org, peng.fan@nxp.com, roman@zededa.com, volodymyr_babchuk@epam.com, vicooodin@gmail.com, Oleksandr Andrushchenko , Anastasiia Lukianenko Subject: [PATCH v2 05/18] xen: Port Xen hypervizor related code from mini-os Date: Mon, 20 Jul 2020 14:02:11 +0300 Message-Id: <20200720110224.28851-6-vicooodin@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200720110224.28851-1-vicooodin@gmail.com> References: <20200720110224.28851-1-vicooodin@gmail.com> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Oleksandr Andrushchenko Port hypervizor related code from mini-os. Update essential arch code to support required bit operations, memory barriers etc. Copyright for the bits ported belong to at least the following authors, please see related files for details: Copyright (c) 2002-2003, K A Fraser Copyright (c) 2005, Grzegorz Milos, gm281@cam.ac.uk,Intel Research Cambridge Copyright (c) 2014, Karim Allah Ahmed Signed-off-by: Oleksandr Andrushchenko Signed-off-by: Anastasiia Lukianenko --- arch/arm/include/asm/io.h | 4 + arch/arm/include/asm/xen/system.h | 88 +++++++++++ common/board_r.c | 13 ++ drivers/Makefile | 1 + drivers/xen/Makefile | 5 + drivers/xen/hypervisor.c | 240 ++++++++++++++++++++++++++++++ include/xen.h | 15 ++ include/xen/hvm.h | 27 ++++ 8 files changed, 393 insertions(+) create mode 100644 arch/arm/include/asm/xen/system.h create mode 100644 drivers/xen/Makefile create mode 100644 drivers/xen/hypervisor.c create mode 100644 include/xen.h create mode 100644 include/xen/hvm.h diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 8959749ad6..ade1401f3b 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -110,9 +110,13 @@ static inline void __raw_readsl(unsigned long addr, void *data, int longlen) * have some advantages to use them instead of the simple one here. */ #define mb() dsb() +#define rmb() dsb() +#define wmb() dsb() #define __iormb() dmb() #define __iowmb() dmb() +#define smp_processor_id() 0 + #define writeb(v,c) ({ u8 __v = v; __iowmb(); __arch_putb(__v,c); __v; }) #define writew(v,c) ({ u16 __v = v; __iowmb(); __arch_putw(__v,c); __v; }) #define writel(v,c) ({ u32 __v = v; __iowmb(); __arch_putl(__v,c); __v; }) diff --git a/arch/arm/include/asm/xen/system.h b/arch/arm/include/asm/xen/system.h new file mode 100644 index 0000000000..0fc8a7995c --- /dev/null +++ b/arch/arm/include/asm/xen/system.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * (C) 2014 Karim Allah Ahmed + * (C) 2020, EPAM Systems Inc. + */ +#ifndef _ASM_ARM_XEN_SYSTEM_H +#define _ASM_ARM_XEN_SYSTEM_H + +#include +#include + +/* If *ptr == old, then store new there (and return new). + * Otherwise, return the old value. + * Atomic. + */ +#define synch_cmpxchg(ptr, old, new) \ +({ __typeof__(*ptr) stored = old; \ + __atomic_compare_exchange_n(ptr, &stored, new, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? new : old; \ +}) + +/* As test_and_clear_bit, but using __ATOMIC_SEQ_CST */ +static inline int synch_test_and_clear_bit(int nr, volatile void *addr) +{ + u8 *byte = ((u8 *)addr) + (nr >> 3); + u8 bit = 1 << (nr & 7); + u8 orig; + + orig = __atomic_fetch_and(byte, ~bit, __ATOMIC_SEQ_CST); + + return (orig & bit) != 0; +} + +/* As test_and_set_bit, but using __ATOMIC_SEQ_CST */ +static inline int synch_test_and_set_bit(int nr, volatile void *base) +{ + u8 *byte = ((u8 *)base) + (nr >> 3); + u8 bit = 1 << (nr & 7); + u8 orig; + + orig = __atomic_fetch_or(byte, bit, __ATOMIC_SEQ_CST); + + return (orig & bit) != 0; +} + +/* As set_bit, but using __ATOMIC_SEQ_CST */ +static inline void synch_set_bit(int nr, volatile void *addr) +{ + synch_test_and_set_bit(nr, addr); +} + +/* As clear_bit, but using __ATOMIC_SEQ_CST */ +static inline void synch_clear_bit(int nr, volatile void *addr) +{ + synch_test_and_clear_bit(nr, addr); +} + +/* As test_bit, but with a following memory barrier. */ +//static inline int synch_test_bit(int nr, volatile void *addr) +static inline int synch_test_bit(int nr, const void *addr) +{ + int result; + + result = test_bit(nr, addr); + barrier(); + return result; +} + +#define xchg(ptr, v) __atomic_exchange_n(ptr, v, __ATOMIC_SEQ_CST) +#define xchg(ptr, v) __atomic_exchange_n(ptr, v, __ATOMIC_SEQ_CST) + +#define xen_mb() mb() +#define xen_rmb() rmb() +#define xen_wmb() wmb() + +#define to_phys(x) ((unsigned long)(x)) +#define to_virt(x) ((void *)(x)) + +#define PFN_UP(x) (unsigned long)(((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) (unsigned long)((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((unsigned long)(x) << PAGE_SHIFT) +#define PHYS_PFN(x) (unsigned long)((x) >> PAGE_SHIFT) + +#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt))) +#define virt_to_mfn(_virt) (PFN_DOWN(to_phys(_virt))) +#define mfn_to_virt(_mfn) (to_virt(PFN_PHYS(_mfn))) +#define pfn_to_virt(_pfn) (to_virt(PFN_PHYS(_pfn))) + +#endif diff --git a/common/board_r.c b/common/board_r.c index 5e924322b2..c8a3a8665c 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -56,6 +56,9 @@ #include #include #include +#ifdef CONFIG_XEN +#include +#endif #ifdef CONFIG_ADDR_MAP #include #endif @@ -462,6 +465,13 @@ static int initr_mmc(void) } #endif +#ifdef CONFIG_XEN +static int initr_xen(void) +{ + xen_init(); + return 0; +} +#endif /* * Tell if it's OK to load the environment early in boot. * @@ -755,6 +765,9 @@ static init_fnc_t init_sequence_r[] = { #endif #ifdef CONFIG_MMC initr_mmc, +#endif +#ifdef CONFIG_XEN + initr_xen, #endif initr_env, #ifdef CONFIG_SYS_BOOTPARAMS_LEN diff --git a/drivers/Makefile b/drivers/Makefile index afd159e903..14ac35e907 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/ obj-$(CONFIG_$(SPL_)BOARD) += board/ +obj-$(CONFIG_XEN) += xen/ ifndef CONFIG_TPL_BUILD ifdef CONFIG_SPL_BUILD diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile new file mode 100644 index 0000000000..1211bf2386 --- /dev/null +++ b/drivers/xen/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2020 EPAM Systems Inc. + +obj-y += hypervisor.o diff --git a/drivers/xen/hypervisor.c b/drivers/xen/hypervisor.c new file mode 100644 index 0000000000..108e9701d6 --- /dev/null +++ b/drivers/xen/hypervisor.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: MIT License +/* + * hypervisor.c + * + * Communication to/from hypervisor. + * + * Copyright (c) 2002-2003, K A Fraser + * Copyright (c) 2005, Grzegorz Milos, gm281@cam.ac.uk,Intel Research Cambridge + * Copyright (c) 2020, EPAM Systems Inc. + */ +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#define active_evtchns(cpu, sh, idx) \ + ((sh)->evtchn_pending[idx] & \ + ~(sh)->evtchn_mask[idx]) + +int in_callback; + +/* + * Shared page for communicating with the hypervisor. + * Events flags go here, for example. + */ +struct shared_info *HYPERVISOR_shared_info; + +static const char *param_name(int op) +{ +#define PARAM(x)[HVM_PARAM_##x] = #x + static const char *const names[] = { + PARAM(CALLBACK_IRQ), + PARAM(STORE_PFN), + PARAM(STORE_EVTCHN), + PARAM(PAE_ENABLED), + PARAM(IOREQ_PFN), + PARAM(VPT_ALIGN), + PARAM(CONSOLE_PFN), + PARAM(CONSOLE_EVTCHN), + }; +#undef PARAM + + if (op >= ARRAY_SIZE(names)) + return "unknown"; + + if (!names[op]) + return "reserved"; + + return names[op]; +} + +/** + * hvm_get_parameter_maintain_dcache - function to obtain a HVM + * parameter value. + * @idx: HVM parameter index + * @value: Value to fill in + * + * According to Xen on ARM ABI (xen/include/public/arch-arm.h): + * all memory which is shared with other entities in the system + * (including the hypervisor and other guests) must reside in memory + * which is mapped as Normal Inner Write-Back Outer Write-Back + * Inner-Shareable. + * + * Thus, page attributes must be equally set for all the entities + * working with that page. + * + * Before MMU setup the data cache is turned off, so it means that + * manual data cache maintenance is required, because of the + * difference of page attributes. + */ +int hvm_get_parameter_maintain_dcache(int idx, uint64_t *value) +{ + struct xen_hvm_param xhv; + int ret; + + invalidate_dcache_range((unsigned long)&xhv, + (unsigned long)&xhv + sizeof(xhv)); + xhv.domid = DOMID_SELF; + xhv.index = idx; + invalidate_dcache_range((unsigned long)&xhv, + (unsigned long)&xhv + sizeof(xhv)); + + ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); + if (ret < 0) { + pr_err("Cannot get hvm parameter %s (%d): %d!\n", + param_name(idx), idx, ret); + BUG(); + } + invalidate_dcache_range((unsigned long)&xhv, + (unsigned long)&xhv + sizeof(xhv)); + + *value = xhv.value; + + return ret; +} + +int hvm_get_parameter(int idx, uint64_t *value) +{ + struct xen_hvm_param xhv; + int ret; + + xhv.domid = DOMID_SELF; + xhv.index = idx; + ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); + if (ret < 0) { + pr_err("Cannot get hvm parameter %s (%d): %d!\n", + param_name(idx), idx, ret); + BUG(); + } + + *value = xhv.value; + + return ret; +} + +struct shared_info *map_shared_info(void *p) +{ + struct xen_add_to_physmap xatp; + + HYPERVISOR_shared_info = (struct shared_info *)memalign(PAGE_SIZE, + PAGE_SIZE); + if (!HYPERVISOR_shared_info) + BUG(); + + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = virt_to_pfn(HYPERVISOR_shared_info); + if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0) + BUG(); + + return HYPERVISOR_shared_info; +} + +void do_hypervisor_callback(struct pt_regs *regs) +{ + unsigned long l1, l2, l1i, l2i; + unsigned int port; + int cpu = 0; + struct shared_info *s = HYPERVISOR_shared_info; + struct vcpu_info *vcpu_info = &s->vcpu_info[cpu]; + + in_callback = 1; + + vcpu_info->evtchn_upcall_pending = 0; + l1 = xchg(&vcpu_info->evtchn_pending_sel, 0); + + while (l1 != 0) { + l1i = __ffs(l1); + l1 &= ~(1UL << l1i); + + while ((l2 = active_evtchns(cpu, s, l1i)) != 0) { + l2i = __ffs(l2); + l2 &= ~(1UL << l2i); + + port = (l1i * (sizeof(unsigned long) * 8)) + l2i; + /* TODO: handle new event: do_event(port, regs); */ + /* Suppress -Wunused-but-set-variable */ + (void)(port); + } + } + + in_callback = 0; +} + +void force_evtchn_callback(void) +{ +#ifdef XEN_HAVE_PV_UPCALL_MASK + int save; +#endif + struct vcpu_info *vcpu; + + vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; +#ifdef XEN_HAVE_PV_UPCALL_MASK + save = vcpu->evtchn_upcall_mask; +#endif + + while (vcpu->evtchn_upcall_pending) { +#ifdef XEN_HAVE_PV_UPCALL_MASK + vcpu->evtchn_upcall_mask = 1; +#endif + do_hypervisor_callback(NULL); +#ifdef XEN_HAVE_PV_UPCALL_MASK + vcpu->evtchn_upcall_mask = save; +#endif + }; +} + +void mask_evtchn(uint32_t port) +{ + struct shared_info *s = HYPERVISOR_shared_info; + + synch_set_bit(port, &s->evtchn_mask[0]); +} + +void unmask_evtchn(uint32_t port) +{ + struct shared_info *s = HYPERVISOR_shared_info; + struct vcpu_info *vcpu_info = &s->vcpu_info[smp_processor_id()]; + + synch_clear_bit(port, &s->evtchn_mask[0]); + + /* + * Just like a real IO-APIC we 'lose the interrupt edge' if the + * channel is masked. + */ + if (synch_test_bit(port, &s->evtchn_pending[0]) && + !synch_test_and_set_bit(port / (sizeof(unsigned long) * 8), + &vcpu_info->evtchn_pending_sel)) { + vcpu_info->evtchn_upcall_pending = 1; +#ifdef XEN_HAVE_PV_UPCALL_MASK + if (!vcpu_info->evtchn_upcall_mask) +#endif + force_evtchn_callback(); + } +} + +void clear_evtchn(uint32_t port) +{ + struct shared_info *s = HYPERVISOR_shared_info; + + synch_clear_bit(port, &s->evtchn_pending[0]); +} + +void xen_init(void) +{ + debug("%s\n", __func__); + + map_shared_info(NULL); +} + diff --git a/include/xen.h b/include/xen.h new file mode 100644 index 0000000000..abc3546dd2 --- /dev/null +++ b/include/xen.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * (C) 2020, EPAM Systems Inc. + */ +#ifndef __XEN_H__ +#define __XEN_H__ + +/** + * xen_init() - Xen initialization + * + * Map Xen memory pages. + */ +void xen_init(void); + +#endif /* __XEN_H__ */ diff --git a/include/xen/hvm.h b/include/xen/hvm.h new file mode 100644 index 0000000000..f02c0798a6 --- /dev/null +++ b/include/xen/hvm.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Simple wrappers around HVM functions + * + * Copyright (c) 2002-2003, K A Fraser + * Copyright (c) 2005, Grzegorz Milos, gm281@cam.ac.uk,Intel Research Cambridge + * Copyright (c) 2020, EPAM Systems Inc. + */ +#ifndef XEN_HVM_H__ +#define XEN_HVM_H__ + +#include +#include +#include + +extern struct shared_info *HYPERVISOR_shared_info; + +int hvm_get_parameter(int idx, uint64_t *value); +int hvm_get_parameter_maintain_dcache(int idx, uint64_t *value); + +struct shared_info *map_shared_info(void *p); +void do_hypervisor_callback(struct pt_regs *regs); +void mask_evtchn(uint32_t port); +void unmask_evtchn(uint32_t port); +void clear_evtchn(uint32_t port); + +#endif /* XEN_HVM_H__ */