| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2021 MediaTek Inc. |
| */ |
| |
| #include "mkp_hvc.h" |
| #include "debug.h" |
| |
| DEBUG_SET_LEVEL(DEBUG_LEVEL_ERR); |
| |
| static void mkp_smccc_hvc(unsigned long a0, unsigned long a1, |
| unsigned long a2, unsigned long a3, |
| unsigned long a4, unsigned long a5, |
| unsigned long a6, unsigned long a7, |
| struct arm_smccc_res *res) |
| { |
| arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res); |
| } |
| |
| int mkp_set_mapping_ro_hvc_call(uint32_t policy, uint32_t handle) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_SET_MAPPING_RO); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| |
| return res.a0 ? -1 : 0; |
| } |
| |
| int mkp_set_mapping_rw_hvc_call(uint32_t policy, uint32_t handle) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_SET_MAPPING_RW); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| |
| return res.a0 ? -1 : 0; |
| } |
| |
| int mkp_set_mapping_nx_hvc_call(uint32_t policy, uint32_t handle) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_SET_MAPPING_NX); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| |
| return res.a0 ? -1 : 0; |
| } |
| |
| int mkp_set_mapping_x_hvc_call(uint32_t policy, uint32_t handle) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_SET_MAPPING_X); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| |
| return res.a0 ? -1 : 0; |
| } |
| |
| int mkp_clear_mapping_hvc_call(uint32_t policy, uint32_t handle) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_CLEAR_MAPPING); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| |
| return res.a0 ? -1 : 0; |
| } |
| |
| int mkp_lookup_mapping_entry_hvc_call(uint32_t policy, uint32_t handle, |
| unsigned long *entry_size, unsigned long *permission) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_LOOKUP_MAPPING_ENTRY); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| if (res.a0) |
| return -1; |
| |
| *entry_size = res.a1; |
| *permission = res.a2; |
| return 0; |
| |
| } |
| int mkp_req_new_policy_hvc_call(unsigned long policy_char) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| uint32_t policy = 0; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_NEW_POLICY); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, policy_char, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| policy = (uint32_t)res.a0; |
| |
| if (res.a0 == 0) |
| return -1; |
| |
| return (int)policy; |
| } |
| |
| int mkp_change_policy_action_hvc_call(uint32_t policy, unsigned long policy_char_action) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| int ret = -1; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_POLICY_ACTION); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, policy_char_action, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| ret = (int)res.a0; |
| |
| /* Success: 0, Fail: other */ |
| return ret; |
| } |
| |
| int mkp_req_new_specified_policy_hvc_call(unsigned long policy_char, uint32_t specified_policy) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| uint32_t policy = 0; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_NEW_SPECIFIED_POLICY); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, policy_char, specified_policy, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, specified_policy, res.a0, res.a1, res.a2, res.a3); |
| policy = (uint32_t)res.a0; |
| |
| if (res.a0 == 0) |
| return -1; |
| |
| /* Expect "policy == specified_policy" */ |
| if (policy != specified_policy) |
| return -1; |
| |
| return (int)policy; |
| } |
| |
| uint32_t mkp_create_handle_hvc_call(uint32_t policy, |
| unsigned long ipa, unsigned long size) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| uint32_t handle = 0; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_CREATE_HANDLE); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, ipa, size, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| handle = (uint32_t)(res.a0); |
| |
| // if fail return 0 |
| // success return >0 |
| |
| return handle; |
| } |
| int mkp_destroy_handle_hvc_call(uint32_t policy, uint32_t handle) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_DESTROY_HANDLE); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, 0, 0, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| |
| return res.a0 ? -1 : 0; |
| } |
| |
| int mkp_configure_sharebuf_hvc_call(uint32_t policy, uint32_t handle, uint32_t type, |
| unsigned long nr_entries, unsigned long size) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_CONFIGURE_SHAREBUF); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, type, nr_entries, size, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| return res.a0 ? -1 : 0; |
| } |
| |
| int mkp_update_sharebuf_1_argu_hvc_call(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_UPDATE_SHAREBUF_1_ARGU); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, index, a1, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| return res.a0 ? -1 : (int)res.a1; |
| } |
| |
| int mkp_update_sharebuf_2_argu_hvc_call(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_UPDATE_SHAREBUF_2_ARGU); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, index, a1, a2, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| return res.a0 ? -1 : (int)res.a1; |
| } |
| |
| int mkp_update_sharebuf_3_argu_hvc_call(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2, unsigned long a3) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_UPDATE_SHAREBUF_3_ARGU); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, index, a1, a2, a3, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| return res.a0 ? -1 : (int)res.a1; |
| } |
| |
| int mkp_update_sharebuf_4_argu_hvc_call(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_UPDATE_SHAREBUF_4_ARGU); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, index, a1, a2, a3, a4, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| return res.a0 ? -1 : (int)res.a1; |
| } |
| |
| int mkp_update_sharebuf_5_argu_hvc_call(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_UPDATE_SHAREBUF_5_ARGU); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, index, a1, a2, a3, a4, a5, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| return res.a0 ? -1 : (int)res.a1; |
| } |
| |
| int mkp_update_sharebuf_hvc_call(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long ipa) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(policy, HVC_FUNC_UPDATE_SHAREBUF); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, handle, index, ipa, 0, 0, 0, 0, &res); |
| MKP_DEBUG("%s:%d hvc_id:0x%x, policy:%d res:0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, __LINE__, |
| mkp_hvc_fast_call_id, policy, res.a0, res.a1, res.a2, res.a3); |
| return res.a0 ? -1 : 0; |
| } |
| |
| /* Pass some essential information to MKP service, return 0 if success. */ |
| int __init mkp_setup_essential_hvc_call(unsigned long phys_offset, |
| unsigned long fixaddr_top, unsigned long fixaddr_real_start) |
| { |
| uint64_t phys_addr; |
| static int is_executed; |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| int ret = -1; |
| |
| /* Get subscribe's IPA */ |
| phys_addr = (uint64_t)(vmalloc_to_pfn((void *)&subscribe) << PAGE_SHIFT) + |
| ((uint64_t)&subscribe & ~PAGE_MASK); |
| |
| if (is_executed == 0) { |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(0, HVC_FUNC_ESS_0); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, phys_offset, fixaddr_top, |
| fixaddr_real_start, phys_addr, 0, 0, 0, &res); |
| is_executed = 1; |
| |
| /* Success */ |
| if (res.a0 == 0) |
| ret = 0; |
| } |
| |
| return ret; |
| } |
| |
| /* Tell MKP service it should start granting */ |
| int __init mkp_start_granting_hvc_call(void) |
| { |
| struct arm_smccc_res res; |
| int mkp_hvc_fast_call_id; |
| int ret = -1; |
| |
| mkp_hvc_fast_call_id = MKP_HVC_CALL_ID(0, HVC_FUNC_ESS_1); |
| mkp_smccc_hvc(mkp_hvc_fast_call_id, 0, 0, 0, 0, 0, 0, 0, &res); |
| |
| /* Success */ |
| if (res.a0 == 0) |
| ret = 0; |
| |
| return ret; |
| } |