summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/hvc.c
blob: d837cbf09442ee811a741c7f1943b8705386c13e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/* 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);