|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |