[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 01/19] xen/arm: Implement PSCI system suspend


  • To: Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>
  • From: Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Date: Sat, 8 Oct 2022 22:00:02 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • 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-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=lSYKyVF/vWxyqV3U+G5s1EFVb7pGe7lKPFsx4VlLqaA=; b=fcuuE59ekPznNFU67WMC1uIrOp5I5VBuBrkwyVmlFLb/F2SIHGorMghJ/Yso5KYtj864VVxgXmmSn4PnWkM0QGVtrMgfYNT7MhG9bqNUprwKgJ/fhZ3C8Gw0iwyK0K5NwzXE86QCp9u/hv6KgJTpWiN+t0bRhJW63M3AUUa3BPN++Qe6hrjcNlrKp1IsRCWpJS4kOsNcmgcQ+2OvDjnJqn0ENE0MhK0GJZbpQosPf9lYMgZM/1t4beoc27633Nol3dmiWp4ixHKvk9sumNxWhiT8l8t260F3iq5ZciJH9HRliVPPjR4yaCVHoEttJ9OA32OTKj5L25hx3MuLPQdfGw==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=VtQMz5ENceg8SeMlXgJbW6k33B3yyq6dCRfNjca4/QJfeQAxxQ1oq1wxbR6m8nXE3PVVNCvccixZ7LzxhiqWqOhmoj1HMK2j9760zZc9iYFT2hWsdU7JkPXwLXBuQ56aMuJgZOlEA+h5tt8C7jPlWLdld+B6eQB1enkIGEDNHj0xTt3ZwKGKFMTUXw6Ty5HxbwTFo+LfY8ApOwCoODZhcq+itgR0HOWLbGQ7D1CIpN9z1A6CMuCm7EJdiZ2xXHVyYLkDlXmDSoP9v9IsS3zFGORTFhEssX3CVrkBwBSzmI+HIUfeECOVLSMOSuRkgzZDgYNXzerVrgFLVPdHd/j7sA==
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, George Dunlap <george.dunlap@xxxxxxxxxx>, Ian Jackson <iwj@xxxxxxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Wei Liu <wl@xxxxxxx>, Dario Faggioli <dfaggioli@xxxxxxxx>, Saeed Nowshadi <saeed.nowshadi@xxxxxxxxxx>, Mykyta Poturai <mykyta.poturai@xxxxxxxx>
  • Delivery-date: Sat, 08 Oct 2022 22:00:46 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHY2jgjWfMPRPlYK0auWtHF0HPLyK4E74yA
  • Thread-topic: [PATCH 01/19] xen/arm: Implement PSCI system suspend

Hi Mykyta,

Mykyta Poturai <Mykyta_Poturai@xxxxxxxx> writes:

> From: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
>
> The implementation consists of:
> -Adding PSCI system suspend call as new PSCI function
> -Trapping PSCI system_suspend HVC

AFAIK, this can be SMC as well.

> -Implementing PSCI system suspend call (virtual interface that allows
>  guests to suspend themselves)
>
> The PSCI system suspend should be called by a guest from its boot
> VCPU.

Why such limititation? PSCI standart does not limit choise of a CPU.


> Non-boot VCPUs of the guest should be hot-unplugged using PSCI
> CPU_OFF call prior to issuing PSCI system suspend. Interrupts that
> are left enabled by the guest are assumed to be its wake-up interrupts.
> Therefore, a wake-up interrupt triggers the resume of the guest. Guest
> should resume regardless of the state of Xen (suspended or not).
>
> When a guest calls PSCI system suspend the respective domain will be
> suspended if the following conditions are met:
> 1) Given resume entry point is not invalid
> 2) Other (if any) VCPUs of the calling guest are hot-unplugged
>
> If the conditions above are met the calling domain is labeled as
> suspended and the calling VCPU is blocked. If nothing else wouldn't
> be done the suspended domain would resume from the place where it
> called PSCI system suspend. This is expected if processing of the PSCI
> system suspend call fails. However, in the case of success the calling
> guest should resume (continue execution after the wake-up) from the entry
> point which is given as the first argument of the PSCI system suspend
> call. In addition to the entry point, the guest expects to start within
> the environment whose state matches the state after reset. This means
> that the guest should find reset register values, MMU disabled, etc.
> Thereby, the context of VCPU should be 'reset' (as if the system is
> comming out of reset), the program counter should contain entry point,
> which is 1st argument, and r0/x0 should contain context ID which is 2nd
> argument of PSCI system suspend call. The context of VCPU is set during
> resume path, to prevent it being overwritten by ctxt_switch_from after
> vcpu is blocked and scheduled out.
>
> VCPU is marked as suspended with _VPF_suspended flag. A suspended domain
> will resume after the Xen receives an interrupt which is targeted to the
> domain, unblocks the domain's VCPU, and schedules it in. During the
> vcpu_unblock execution the VCPU is checked for VPF_suspended flag. If
> the flag is present, the context of that VCPU gets cleared and entry
> point/cid are set.
>
> Signed-off-by: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
> Signed-off-by: Saeed Nowshadi <saeed.nowshadi@xxxxxxxxxx>
> Signed-off-by: Mykyta Poturai <mykyta.poturai@xxxxxxxx>
> ---
>  xen/arch/arm/Makefile            |   1 +
>  xen/arch/arm/domain.c            |   4 +
>  xen/arch/arm/suspend.c           | 182 +++++++++++++++++++++++++++++++
>  xen/arch/arm/vpsci.c             |  28 +++++
>  xen/common/sched/core.c          |   8 ++
>  xen/include/asm-arm/domain.h     |   3 +
>  xen/include/asm-arm/perfc_defn.h |   1 +
>  xen/include/asm-arm/psci.h       |   2 +
>  xen/include/asm-arm/suspend.h    |  17 +++
>  xen/include/xen/sched.h          |   3 +
>  10 files changed, 249 insertions(+)
>  create mode 100644 xen/arch/arm/suspend.c
>  create mode 100644 xen/include/asm-arm/suspend.h
>
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index b5913c9d39..07dbbd99a3 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -49,6 +49,7 @@ obj-y += setup.o
>  obj-y += shutdown.o
>  obj-y += smp.o
>  obj-y += smpboot.o
> +obj-y += suspend.o
>  obj-y += sysctl.o
>  obj-y += time.o
>  obj-y += traps.o
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 23c8b345d4..4110154bda 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -40,6 +40,8 @@
>  #include <asm/vtimer.h>
>  #include <asm/vscmi.h>
>  
> +#include <public/sched.h>
> +

Do you really need this include?

>  #include "vpci.h"
>  #include "vuart.h"
>  
> @@ -101,6 +103,8 @@ static void ctxt_switch_from(struct vcpu *p)
>      if ( is_idle_vcpu(p) )
>          return;
>  
> +    /* VCPU's context should not be saved if its domain is suspended */
> +

Is this a some leftover?

>      p2m_save_state(p);
>  
>      /* CP 15 */
> diff --git a/xen/arch/arm/suspend.c b/xen/arch/arm/suspend.c
> new file mode 100644
> index 0000000000..987ba6ac11
> --- /dev/null
> +++ b/xen/arch/arm/suspend.c
> @@ -0,0 +1,182 @@
> +/*
> + * Copyright (C) 2022 EPAM Systems Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#include <xen/sched.h>
> +#include <asm/cpufeature.h>
> +#include <asm/event.h>
> +#include <asm/psci.h>
> +#include <asm/suspend.h>
> +#include <public/sched.h>
> +
> +struct cpu_context cpu_context;
> +
> +/* Reset values of VCPU architecture specific registers */
> +static void vcpu_arch_reset(struct vcpu *v)
> +{
> +    v->arch.ttbr0 = 0;
> +    v->arch.ttbr1 = 0;
> +    v->arch.ttbcr = 0;
> +
> +    v->arch.csselr = 0;
> +    v->arch.cpacr = 0;
> +    v->arch.contextidr = 0;
> +    v->arch.tpidr_el0 = 0;
> +    v->arch.tpidrro_el0 = 0;
> +    v->arch.tpidr_el1 = 0;
> +    v->arch.vbar = 0;
> +    v->arch.dacr = 0;
> +    v->arch.par = 0;
> +#if defined(CONFIG_ARM_32)
> +    v->arch.mair0 = 0;
> +    v->arch.mair1 = 0;
> +    v->arch.amair0 = 0;
> +    v->arch.amair1 = 0;
> +#else
> +    v->arch.mair = 0;
> +    v->arch.amair = 0;
> +#endif
> +    /* Fault Status */
> +#if defined(CONFIG_ARM_32)
> +    v->arch.dfar = 0;
> +    v->arch.ifar = 0;
> +    v->arch.dfsr = 0;
> +#elif defined(CONFIG_ARM_64)
> +    v->arch.far = 0;
> +    v->arch.esr = 0;
> +#endif
> +
> +    v->arch.ifsr  = 0;
> +    v->arch.afsr0 = 0;
> +    v->arch.afsr1 = 0;
> +
> +#ifdef CONFIG_ARM_32
> +    v->arch.joscr = 0;
> +    v->arch.jmcr = 0;
> +#endif
> +
> +    if ( is_32bit_domain(v->domain) && cpu_has_thumbee )
> +    {
> +        v->arch.teecr = 0;
> +        v->arch.teehbr = 0;
> +    }
> +}
> +
> +
> +static void vcpu_suspend(register_t epoint, register_t cid)
> +{
> +    struct vcpu *v = current;
> +
> +    v->arch.suspend_ep = epoint;
> +    v->arch.suspend_cid = cid;
> +    set_bit(_VPF_suspended, &v->pause_flags);
> +    return;
> +}
> +
> +/*
> + * This function sets the context of current VCPU to the state which is 
> expected
> + * by the guest on resume. The expected VCPU state is:
> + * 1) pc to contain resume entry point (1st argument of PSCI SYSTEM_SUSPEND)
> + * 2) r0/x0 to contain context ID (2nd argument of PSCI SYSTEM_SUSPEND)
> + * 3) All other general purpose and system registers should have reset values
> + */
> +void vcpu_resume(struct vcpu *v)
> +{
> +
> +    struct vcpu_guest_context ctxt;
> +
> +    /* Make sure that VCPU guest regs are zeroed */
> +    memset(&ctxt, 0, sizeof(ctxt));
> +
> +    /* Set non-zero values to the registers prior to copying */
> +    ctxt.user_regs.pc64 = (u64)v->arch.suspend_ep;
> +
> +    if ( is_32bit_domain(v->domain) )
> +    {
> +        ctxt.user_regs.r0_usr = v->arch.suspend_cid;
> +        ctxt.user_regs.cpsr = PSR_GUEST32_INIT;
> +
> +        /* Thumb set is allowed only for 32-bit domain */
> +        if ( v->arch.suspend_ep & 1 )
> +        {
> +            ctxt.user_regs.cpsr |= PSR_THUMB;
> +            ctxt.user_regs.pc64 &= ~(u64)1;
> +        }
> +    }
> +#ifdef CONFIG_ARM_64
> +    else
> +    {
> +        ctxt.user_regs.x0 = v->arch.suspend_cid;
> +        ctxt.user_regs.cpsr = PSR_GUEST64_INIT;
> +    }
> +#endif
> +    ctxt.sctlr = SCTLR_GUEST_INIT;
> +    ctxt.flags = VGCF_online;
> +
> +    /* Reset architecture specific registers */
> +    vcpu_arch_reset(v);
> +
> +    /* Initialize VCPU registers */
> +    arch_set_info_guest(v, &ctxt);
> +    clear_bit(_VPF_suspended, &v->pause_flags);
> +}
> +
> +int32_t domain_suspend(register_t epoint, register_t cid)
> +{
> +    struct vcpu *v;
> +    struct domain *d = current->domain;
> +    bool is_thumb = epoint & 1;
> +
> +    dprintk(XENLOG_DEBUG,
> +            "Dom%d suspend: epoint=0x%"PRIregister", cid=0x%"PRIregister"\n",
> +            d->domain_id, epoint, cid);
> +
> +    /* THUMB set is not allowed with 64-bit domain */
> +    if ( is_64bit_domain(d) && is_thumb )
> +        return PSCI_INVALID_ADDRESS;
> +
> +    /* Ensure that all CPUs other than the calling one are offline */
> +    for_each_vcpu ( d, v )
> +    {
> +        if ( v != current && is_vcpu_online(v) )
> +            return PSCI_DENIED;
> +    }
> +
> +    //TODO: add support for suspending from any VCPU

How hard it would be to implement?

> +    if (current->vcpu_id != 0)
> +        return PSCI_DENIED;
> +
> +    /*
> +     * Prepare the calling VCPU for suspend (reset its context, save entry 
> point
> +     * into pc and context ID into r0/x0 as specified by PSCI SYSTEM_SUSPEND)
> +     */
> +    vcpu_suspend(epoint, cid);
> +
> +    /*
> +     * The calling domain is suspended by blocking its last running VCPU. If 
> an
> +     * event is pending the domain will resume right away (VCPU will not 
> block,
> +     * but when scheduled in it will resume from the given entry point).
> +     */
> +    vcpu_block_unless_event_pending(current);
> +
> +    return PSCI_SUCCESS;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/vpsci.c b/xen/arch/arm/vpsci.c
> index c1e250be59..f4e6e92873 100644
> --- a/xen/arch/arm/vpsci.c
> +++ b/xen/arch/arm/vpsci.c
> @@ -18,6 +18,7 @@
>  #include <asm/vgic.h>
>  #include <asm/vpsci.h>
>  #include <asm/event.h>
> +#include <asm/suspend.h>
>  
>  #include <public/sched.h>
>  
> @@ -208,6 +209,11 @@ static void do_psci_0_2_system_reset(void)
>      domain_shutdown(d,SHUTDOWN_reboot);
>  }
>  
> +static int32_t do_psci_1_0_system_suspend(register_t epoint, register_t cid)
> +{
> +    return domain_suspend(epoint, cid);
> +}
> +
>  static int32_t do_psci_1_0_features(uint32_t psci_func_id)
>  {
>      /* /!\ Ordered by function ID and not name */
> @@ -225,6 +231,8 @@ static int32_t do_psci_1_0_features(uint32_t psci_func_id)
>      case PSCI_0_2_FN32_SYSTEM_OFF:
>      case PSCI_0_2_FN32_SYSTEM_RESET:
>      case PSCI_1_0_FN32_PSCI_FEATURES:
> +    case PSCI_1_0_FN32_SYSTEM_SUSPEND:
> +    case PSCI_1_0_FN64_SYSTEM_SUSPEND:
>      case ARM_SMCCC_VERSION_FID:
>          return 0;
>      default:
> @@ -355,6 +363,26 @@ bool do_vpsci_0_2_call(struct cpu_user_regs *regs, 
> uint32_t fid)
>          return true;
>      }
>  
> +    case PSCI_1_0_FN32_SYSTEM_SUSPEND:
> +    case PSCI_1_0_FN64_SYSTEM_SUSPEND:
> +    {
> +        register_t epoint = PSCI_ARG(regs,1);
> +        register_t cid = PSCI_ARG(regs,2);
> +        register_t ret;
> +
> +        perfc_incr(vpsci_system_suspend);
> +        /* Set the result to PSCI_SUCCESS if the call fails.
> +         * Otherwise preserve the context_id in x0. For now 

Looks like there is a trailing space                          ^

> +         * we don't support the case where the system is suspended
> +         * to a shallower level and PSCI_SUCCESS is returned to the 

And in this line also

> +         * caller.
> +         */
> +        ret = do_psci_1_0_system_suspend(epoint, cid);
> +        if ( ret != PSCI_SUCCESS )
> +            PSCI_SET_RESULT(regs, ret);
> +        return true;
> +    }
> +
>      default:
>          return false;
>      }
> diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
> index 8f4b1ca10d..4e1ea62c44 100644
> --- a/xen/common/sched/core.c
> +++ b/xen/common/sched/core.c
> @@ -38,6 +38,10 @@
>  #include <xsm/xsm.h>
>  #include <xen/err.h>
>  
> +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
> +#include <asm/suspend.h>
> +#endif
> +
>  #include "private.h"
>  
>  #ifdef CONFIG_XEN_GUEST
> @@ -957,6 +961,10 @@ void vcpu_unblock(struct vcpu *v)
>  {
>      if ( !test_and_clear_bit(_VPF_blocked, &v->pause_flags) )
>          return;
> +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
> +    if ( test_bit(_VPF_suspended, &v->pause_flags) )
> +        vcpu_resume(v);
> +#endif

This does not look good. I do understant that that was I, who suggested
to add this flag, but I didn't expected that it will get into common code.

Also, this is not justified in the commit message. I remeber that there was
some discussion about why vcpu_block()/vcpu_unblock() could not be used, and
I'd love to see its summary in the commit message.

>  
>      /* Polling period ends when a VCPU is unblocked. */
>      if ( unlikely(v->poll_evtchn != 0) )
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 413e5a2a18..715841e0b5 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -203,6 +203,9 @@ struct arch_vcpu
>      struct vtimer virt_timer;
>      bool   vtimer_initialized;
>  
> +    register_t suspend_ep;
> +    register_t suspend_cid;
> +
>      /*
>       * The full P2M may require some cleaning (e.g when emulation
>       * set/way). As the action can take a long time, it requires
> diff --git a/xen/include/asm-arm/perfc_defn.h 
> b/xen/include/asm-arm/perfc_defn.h
> index 31f071222b..d71e91a5e4 100644
> --- a/xen/include/asm-arm/perfc_defn.h
> +++ b/xen/include/asm-arm/perfc_defn.h
> @@ -33,6 +33,7 @@ PERFCOUNTER(vpsci_system_reset,        "vpsci: 
> system_reset")
>  PERFCOUNTER(vpsci_cpu_suspend,         "vpsci: cpu_suspend")
>  PERFCOUNTER(vpsci_cpu_affinity_info,   "vpsci: cpu_affinity_info")
>  PERFCOUNTER(vpsci_features,            "vpsci: features")
> +PERFCOUNTER(vpsci_system_suspend,      "vpsci: system_suspend")
>  
>  PERFCOUNTER(vcpu_kick,                 "vcpu: notify other vcpu")
>  
> diff --git a/xen/include/asm-arm/psci.h b/xen/include/asm-arm/psci.h
> index 832f77afff..26462d0c47 100644
> --- a/xen/include/asm-arm/psci.h
> +++ b/xen/include/asm-arm/psci.h
> @@ -43,10 +43,12 @@ void call_psci_system_reset(void);
>  #define PSCI_0_2_FN32_SYSTEM_OFF          PSCI_0_2_FN32(8)
>  #define PSCI_0_2_FN32_SYSTEM_RESET        PSCI_0_2_FN32(9)
>  #define PSCI_1_0_FN32_PSCI_FEATURES       PSCI_0_2_FN32(10)
> +#define PSCI_1_0_FN32_SYSTEM_SUSPEND      PSCI_0_2_FN32(14)
>  
>  #define PSCI_0_2_FN64_CPU_SUSPEND         PSCI_0_2_FN64(1)
>  #define PSCI_0_2_FN64_CPU_ON              PSCI_0_2_FN64(3)
>  #define PSCI_0_2_FN64_AFFINITY_INFO       PSCI_0_2_FN64(4)
> +#define PSCI_1_0_FN64_SYSTEM_SUSPEND      PSCI_0_2_FN64(14)
>  
>  /* PSCI v0.2 affinity level state returned by AFFINITY_INFO */
>  #define PSCI_0_2_AFFINITY_LEVEL_ON      0
> diff --git a/xen/include/asm-arm/suspend.h b/xen/include/asm-arm/suspend.h
> new file mode 100644
> index 0000000000..fbaa414f0c
> --- /dev/null
> +++ b/xen/include/asm-arm/suspend.h
> @@ -0,0 +1,17 @@
> +#ifndef __ASM_ARM_SUSPEND_H__
> +#define __ASM_ARM_SUSPEND_H__
> +
> +int32_t domain_suspend(register_t epoint, register_t cid);
> +void vcpu_resume(struct vcpu *v);
> +
> +#endif
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
> index 3b4ed3a2ab..b2f6d1af28 100644
> --- a/xen/include/xen/sched.h
> +++ b/xen/include/xen/sched.h
> @@ -903,6 +903,9 @@ static inline struct domain *next_domain_in_cpupool(
>  /* VCPU is parked. */
>  #define _VPF_parked          8
>  #define VPF_parked           (1UL<<_VPF_parked)
> +/* VCPU is suspended */
> +#define _VPF_suspended       9
> +#define VPF_suspended        (1UL<<_VPF_suspended)
>  
>  static inline bool vcpu_runnable(const struct vcpu *v)
>  {


-- 
Volodymyr Babchuk at EPAM


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.