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

Re: [Xen-devel] [PATCH v8 07/11] arm: smccc: handle SMCs according to SMCCC



On Tue, 10 Oct 2017, Volodymyr Babchuk wrote:
> SMCCC (SMC Call Convention) describes how to handle both HVCs and SMCs.
> SMCCC states that both HVC and SMC are valid conduits to call to different
> firmware functions. Thus, for example, PSCI calls can be made both by
> SMC or HVC. Also SMCCC defines function number coding for such calls.
> Besides functional calls there are query calls, which allows underling
> OS determine version, UUID and number of functions provided by service
> provider.
> 
> This patch adds new file `vsmc.c`, which handles both generic SMCs
> and HVC according to SMCCC. At this moment it implements only one
> service: Standard Hypervisor Service.
> 
> At this time Standard Hypervisor Service only supports query calls,
> so caller can ask about hypervisor UID and determine that it is XEN running.
> 
> This change allows more generic handling for SMCs and HVCs and it can
> be easily extended to support new services and functions.
> 
> But, before SMC is forwarded to standard SMCCC handler, it can be routed
> to a domain monitor, if one is installed.
> 
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
> Reviewed-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
> Reviewed-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
> Acked-by: Julien Grall <julien.grall@xxxxxxx>
> ---
>  xen/arch/arm/Makefile               |   1 +
>  xen/arch/arm/traps.c                |  17 ----
>  xen/arch/arm/vsmc.c                 | 191 
> ++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/traps.h         |   3 +
>  xen/include/public/arch-arm/smccc.h |  58 +++++++++++
>  5 files changed, 253 insertions(+), 17 deletions(-)
>  create mode 100644 xen/arch/arm/vsmc.c
>  create mode 100644 xen/include/public/arch-arm/smccc.h
> 
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 424580b..30a2a65 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -53,6 +53,7 @@ obj-$(CONFIG_HAS_ITS) += vgic-v3-its.o
>  obj-y += vm_event.o
>  obj-y += vtimer.o
>  obj-$(CONFIG_SBSA_VUART_CONSOLE) += vpl011.o
> +obj-y += vsmc.o
>  obj-y += vpsci.o
>  obj-y += vuart.o
>  
> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> index 5b91e6c..6ea0090 100644
> --- a/xen/arch/arm/traps.c
> +++ b/xen/arch/arm/traps.c
> @@ -2195,23 +2195,6 @@ static void do_trap_data_abort_guest(struct 
> cpu_user_regs *regs,
>      inject_dabt_exception(regs, info.gva, hsr.len);
>  }
>  
> -static void do_trap_smc(struct cpu_user_regs *regs, const union hsr hsr)
> -{
> -    int rc = 0;
> -
> -    if ( !check_conditional_instr(regs, hsr) )
> -    {
> -        advance_pc(regs, hsr);
> -        return;
> -    }
> -
> -    if ( current->domain->arch.monitor.privileged_call_enabled )
> -        rc = monitor_smc();
> -
> -    if ( rc != 1 )
> -        inject_undef_exception(regs, hsr);
> -}
> -
>  static void enter_hypervisor_head(struct cpu_user_regs *regs)
>  {
>      if ( guest_mode(regs) )
> diff --git a/xen/arch/arm/vsmc.c b/xen/arch/arm/vsmc.c
> new file mode 100644
> index 0000000..38df821
> --- /dev/null
> +++ b/xen/arch/arm/vsmc.c
> @@ -0,0 +1,191 @@
> +/*
> + * xen/arch/arm/vsmc.c
> + *
> + * Generic handler for SMC and HVC calls according to
> + * ARM SMC calling convention
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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 General Public License for more details.
> + */
> +
> +
> +#include <xen/lib.h>
> +#include <xen/types.h>
> +#include <public/arch-arm/smccc.h>
> +#include <asm/monitor.h>
> +#include <asm/regs.h>
> +#include <asm/smccc.h>
> +#include <asm/traps.h>
> +
> +/* Number of functions currently supported by Hypervisor Service. */
> +#define XEN_SMCCC_FUNCTION_COUNT 3
> +
> +static bool fill_uid(struct cpu_user_regs *regs, xen_uuid_t uuid)
> +{
> +    int n;
> +
> +    /*
> +     * UID is returned in registers r0..r3, four bytes per register,
> +     * first byte is stored in low-order bits of a register.
> +     * (ARM DEN 0028B page 14)
> +     */
> +    for (n = 0; n < 4; n++)
> +    {
> +        const uint8_t *bytes = uuid.a + n * 4;
> +        uint32_t r;
> +
> +        r = bytes[0];
> +        r |= bytes[1] << 8;
> +        r |= bytes[2] << 16;
> +        r |= bytes[3] << 24;
> +
> +        set_user_reg(regs, n, r);
> +    }
> +
> +    return true;
> +}
> +
> +static bool fill_revision(struct cpu_user_regs *regs, uint32_t major,
> +                         uint32_t minor)
> +{
> +    /*
> +     * Revision is returned in registers r0 and r1.
> +     * r0 stores major part of the version
> +     * r1 stores minor part of the version
> +     * (ARM DEN 0028B page 15)
> +     */
> +    set_user_reg(regs, 0, major);
> +    set_user_reg(regs, 1, minor);
> +
> +    return true;
> +}
> +
> +static bool fill_function_call_count(struct cpu_user_regs *regs, uint32_t 
> cnt)
> +{
> +    /*
> +     * Function call count is retuned as any other return value in register 
> r0
> +     * (ARM DEN 0028B page 17)
> +     */
> +    set_user_reg(regs, 0, cnt);
> +
> +    return true;
> +}
> +
> +/* SMCCC interface for hypervisor. Tell about itself. */
> +static bool handle_hypervisor(struct cpu_user_regs *regs)
> +{
> +    switch ( smccc_get_fn(get_user_reg(regs, 0)) )
> +    {
> +    case ARM_SMCCC_FUNC_CALL_COUNT:
> +        return fill_function_call_count(regs, XEN_SMCCC_FUNCTION_COUNT);
> +    case ARM_SMCCC_FUNC_CALL_UID:
> +        return fill_uid(regs, XEN_SMCCC_UID);
> +    case ARM_SMCCC_FUNC_CALL_REVISION:
> +        return fill_revision(regs, XEN_SMCCC_MAJOR_REVISION,
> +                             XEN_SMCCC_MINOR_REVISION);
> +    default:
> +        return false;
> +    }
> +}
> +
> +/*
> + * vsmccc_handle_call() - handle SMC/HVC call according to ARM SMCCC.
> + * returns true if that was valid SMCCC call (even if function number
> + * was unknown).
> + */
> +static bool vsmccc_handle_call(struct cpu_user_regs *regs)
> +{
> +    bool handled = false;
> +    const union hsr hsr = { .bits = regs->hsr };
> +    register_t funcid = get_user_reg(regs, 0);
> +
> +    /*
> +     * Check immediate value for HVC32, HVC64 and SMC64.
> +     * It is not so easy to check immediate value for SMC32,
> +     * because it is not stored in HSR.ISS field. To get immediate
> +     * value we need to disassemble instruction at current pc, which
> +     * is expensive. So we will assume that it is 0x0.
> +     */
> +    switch ( hsr.ec )
> +    {
> +    case HSR_EC_HVC32:
> +    case HSR_EC_HVC64:
> +    case HSR_EC_SMC64:

HSR_EC_HVC64 and HSR_EC_SMC64 are only defined on ARM64. I added an
#ifdef here while committing.


> +        if ( (hsr.iss & HSR_XXC_IMM_MASK) != 0)
> +            return false;
> +        break;
> +    case HSR_EC_SMC32:
> +        break;
> +    default:
> +        return false;
> +    }
> +
> +    /* 64 bit calls are allowed only from 64 bit domains. */
> +    if ( smccc_is_conv_64(funcid) && is_32bit_domain(current->domain) )
> +    {
> +        set_user_reg(regs, 0, ARM_SMCCC_ERR_UNKNOWN_FUNCTION);
> +        return true;
> +    }
> +
> +    switch ( smccc_get_owner(funcid) )
> +    {
> +    case ARM_SMCCC_OWNER_HYPERVISOR:
> +        handled = handle_hypervisor(regs);
> +        break;
> +    }
> +
> +    if ( !handled )
> +    {
> +        gprintk(XENLOG_INFO, "Unhandled SMC/HVC: %08"PRIregister"\n", 
> funcid);
> +
> +        /* Inform caller that function is not supported. */
> +        set_user_reg(regs, 0, ARM_SMCCC_ERR_UNKNOWN_FUNCTION);
> +    }
> +
> +    return true;
> +}
> +
> +void do_trap_smc(struct cpu_user_regs *regs, const union hsr hsr)
> +{
> +    int rc = 0;
> +
> +    if ( !check_conditional_instr(regs, hsr) )
> +    {
> +        advance_pc(regs, hsr);
> +        return;
> +    }
> +
> +    /* If monitor is enabled, let it handle the call. */
> +    if ( current->domain->arch.monitor.privileged_call_enabled )
> +        rc = monitor_smc();
> +
> +    if ( rc == 1 )
> +        return;
> +
> +    /*
> +     * Use standard routines to handle the call.
> +     * vsmccc_handle_call() will return false if this call is not
> +     * SMCCC compatible (e.g. immediate value != 0). As it is not
> +     * compatible, we can't be sure that guest will understand
> +     * ARM_SMCCC_ERR_UNKNOWN_FUNCTION.
> +     */
> +    if ( vsmccc_handle_call(regs) )
> +        advance_pc(regs, hsr);
> +    else
> +        inject_undef_exception(regs, hsr);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/asm-arm/traps.h b/xen/include/asm-arm/traps.h
> index 7508af8..325c15f 100644
> --- a/xen/include/asm-arm/traps.h
> +++ b/xen/include/asm-arm/traps.h
> @@ -35,6 +35,9 @@ void do_cp14_64(struct cpu_user_regs *regs, const union hsr 
> hsr);
>  void do_cp14_dbg(struct cpu_user_regs *regs, const union hsr hsr);
>  void do_cp(struct cpu_user_regs *regs, const union hsr hsr);
>  
> +/* SMCCC handling */
> +void do_trap_smc(struct cpu_user_regs *regs, const union hsr hsr);
> +
>  #endif /* __ASM_ARM_TRAPS__ */
>  /*
>   * Local variables:
> diff --git a/xen/include/public/arch-arm/smccc.h 
> b/xen/include/public/arch-arm/smccc.h
> new file mode 100644
> index 0000000..2bee5b3
> --- /dev/null
> +++ b/xen/include/public/arch-arm/smccc.h
> @@ -0,0 +1,58 @@
> +/*
> + * smccc.h
> + *
> + * SMC/HVC interface in accordance with SMC Calling Convention.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a 
> copy
> + * of this software and associated documentation files (the "Software"), to
> + * deal in the Software without restriction, including without limitation the
> + * rights to use, copy, modify, merge, publish, distribute, sublicense, 
> and/or
> + * sell copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
> THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + * Copyright 2017 (C) EPAM Systems
> + */
> +
> +#ifndef __XEN_PUBLIC_ARCH_ARM_SMCCC_H__
> +#define __XEN_PUBLIC_ARCH_ARM_SMCCC_H__
> +
> +#include "public/xen.h"
> +
> +/*
> + * Hypervisor Service version.
> + *
> + * We can't use XEN version here, because of SMCCC requirements:
> + * Major revision should change every time SMC/HVC function is removed.
> + * Minor revision should change every time SMC/HVC function is added.
> + * So, it is SMCCC protocol revision code, not XEN version.
> + *
> + * Those values are subjected to change, when interface will be extended.
> + */
> +#define XEN_SMCCC_MAJOR_REVISION 0
> +#define XEN_SMCCC_MINOR_REVISION 1
> +
> +/* Hypervisor Service UID. Randomly generated with uuidgen. */
> +#define XEN_SMCCC_UID XEN_DEFINE_UUID(0xa71812dc, 0xc698, 0x4369, 0x9acf, \
> +                                      0x79, 0xd1, 0x8d, 0xde, 0xe6, 0x67)
> +
> +#endif /* __XEN_PUBLIC_ARCH_ARM_SMCCC_H__ */
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:b
> + */
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxx
> https://lists.xen.org/xen-devel
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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