102 lines
2.4 KiB
C
102 lines
2.4 KiB
C
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only 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 <linux/io.h>
|
|
#include <linux/export.h>
|
|
#include <linux/err.h>
|
|
|
|
#include <asm/compiler.h>
|
|
|
|
#include <soc/qcom/hvc.h>
|
|
|
|
#define HVC_RET_SUCCESS 0
|
|
#define HVC_RET_ERROR -1
|
|
#define HVC_RET_EFUNCNOSUPPORT -2
|
|
#define HVC_RET_EINVALARCH -3
|
|
#define HVC_RET_EMEMMAP -4
|
|
#define HVC_RET_EMEMUNMAP -5
|
|
#define HVC_RET_EMEMPERM -6
|
|
|
|
static int hvc_to_linux_errno(int errno)
|
|
{
|
|
switch (errno) {
|
|
case HVC_RET_SUCCESS:
|
|
return 0;
|
|
case HVC_RET_ERROR:
|
|
return -EIO;
|
|
case HVC_RET_EFUNCNOSUPPORT:
|
|
return -EOPNOTSUPP;
|
|
case HVC_RET_EINVALARCH:
|
|
case HVC_RET_EMEMMAP:
|
|
case HVC_RET_EMEMUNMAP:
|
|
return -EINVAL;
|
|
case HVC_RET_EMEMPERM:
|
|
return -EPERM;
|
|
};
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_ARM64
|
|
static int __hvc(u64 x0, u64 x1, u64 x2, u64 x3, u64 x4, u64 x5,
|
|
u64 x6, u64 x7, u64 *ret1, u64 *ret2, u64 *ret3)
|
|
{
|
|
register u64 r0 asm("x0") = x0;
|
|
register u64 r1 asm("x1") = x1;
|
|
register u64 r2 asm("x2") = x2;
|
|
register u64 r3 asm("x3") = x3;
|
|
register u64 r4 asm("x4") = x4;
|
|
register u64 r5 asm("x5") = x5;
|
|
register u64 r6 asm("x6") = x6;
|
|
register u64 r7 asm("x7") = x7;
|
|
|
|
asm volatile(
|
|
__asmeq("%0", "x0")
|
|
__asmeq("%1", "x1")
|
|
__asmeq("%2", "x2")
|
|
__asmeq("%3", "x3")
|
|
__asmeq("%4", "x4")
|
|
__asmeq("%5", "x5")
|
|
__asmeq("%6", "x6")
|
|
__asmeq("%7", "x7")
|
|
"hvc #0\n"
|
|
: "+r" (r0), "+r" (r1), "+r" (r2), "+r" (r3)
|
|
: "r" (r4), "r" (r5), "r" (r6), "r" (r7));
|
|
|
|
*ret1 = r1;
|
|
*ret2 = r2;
|
|
*ret3 = r3;
|
|
|
|
return r0;
|
|
}
|
|
#else
|
|
static int __hvc(u64 x0, u64 x1, u64 x2, u64 x3, u64 x4, u64 x5,
|
|
u64 x6, u64 x7, u64 *ret1, u64 *ret2, u64 *ret3)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int hvc(u64 func_id, struct hvc_desc *desc)
|
|
{
|
|
int ret;
|
|
|
|
if (!desc)
|
|
return -EINVAL;
|
|
|
|
ret = __hvc(func_id, desc->arg[0], desc->arg[1], desc->arg[2],
|
|
desc->arg[3], desc->arg[4], desc->arg[5], 0,
|
|
&desc->ret[0], &desc->ret[1], &desc->ret[2]);
|
|
|
|
return hvc_to_linux_errno(ret);
|
|
}
|
|
EXPORT_SYMBOL(hvc);
|