/* 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 #include #include #include #include #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);