| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2021 MediaTek Inc. |
| */ |
| |
| #include "mkp_api.h" |
| |
| const uint64_t subscribe = 0x6d6b7021; /* mkp! */ |
| uint64_t *grant_ticket __ro_after_init; |
| |
| /* Preparation for grant ticket */ |
| bool __init prepare_grant_ticket(void) |
| { |
| struct page *tpage; |
| void *taddr; |
| |
| tpage = vmalloc_to_page((void *)&subscribe); |
| taddr = vmap(&tpage, 1, VM_MAP, PAGE_KERNEL); |
| if (!taddr) |
| return false; |
| |
| grant_ticket = (uint64_t *)((uint64_t)taddr + ((uint64_t)&subscribe & ~PAGE_MASK)); |
| |
| return true; |
| } |
| |
| void __init mkp_set_policy(u32 policy) |
| { |
| // set policy control |
| set_policy(policy); |
| } |
| |
| int __init mkp_set_ext_policy(uint32_t policy) |
| { |
| // set extended policy |
| return set_ext_policy(policy); |
| } |
| |
| int mkp_lookup_mapping_entry(uint32_t policy, uint32_t handle, |
| unsigned long *entry_size, unsigned long *permission) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_lookup_mapping_entry_hvc_call(policy, |
| handle, entry_size, permission); |
| return ret; |
| } |
| |
| int mkp_request_new_policy(unsigned long policy_char) |
| { |
| int ret = 0; |
| |
| ret = mkp_req_new_policy_hvc_call(policy_char); |
| |
| return ret; |
| } |
| |
| int mkp_change_policy_action(uint32_t policy, unsigned long policy_char_action) |
| { |
| int ret = 0; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return -1; |
| if (policy_char_action & (~ACTION_BITS)) |
| return -1; |
| |
| mkp_policy_action[policy] &= (~ACTION_BITS); |
| mkp_policy_action[policy] |= policy_char_action; |
| |
| ret = mkp_change_policy_action_hvc_call(policy, policy_char_action); |
| |
| if (ret == 0) |
| return 0; |
| else |
| return -1; |
| } |
| |
| int mkp_request_new_specified_policy(unsigned long policy_char, uint32_t specified_policy) |
| { |
| int ret = 0; |
| |
| ret = mkp_req_new_specified_policy_hvc_call(policy_char, specified_policy); |
| |
| return ret; |
| } |
| |
| uint32_t mkp_create_handle(uint32_t policy, unsigned long ipa, unsigned long size) |
| { |
| uint32_t handle = 0; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return 0; |
| |
| // hvc call to get handle |
| handle = mkp_create_handle_hvc_call(policy, ipa, size); |
| |
| return handle; |
| } |
| int mkp_destroy_handle(uint32_t policy, uint32_t handle) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_destroy_handle_hvc_call(policy, handle); |
| return ret; |
| } |
| |
| uint32_t mkp_create_ro_sharebuf(uint32_t policy, unsigned long size, struct page **pages) |
| { |
| uint32_t handle = 0; |
| phys_addr_t ipa; |
| int ret = -1; |
| struct page *l_pages = NULL; |
| unsigned int order = get_order(size); |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return 0; |
| |
| l_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); |
| if (l_pages == NULL) |
| return 0; |
| ipa = page_to_phys(l_pages); |
| *pages = l_pages; |
| handle = mkp_create_handle(policy, ipa, size); |
| if (handle == 0) { |
| __free_pages(l_pages, order); |
| return 0; |
| } |
| |
| ret = do_secure_ops(policy, handle, mkp_set_mapping_ro_hvc_call); |
| if (ret == -1) { |
| ret = mkp_destroy_handle(policy, handle); |
| __free_pages(l_pages, order); |
| return 0; |
| } |
| *pages = l_pages; |
| return handle; |
| } |
| |
| uint32_t mkp_create_wo_sharebuf(uint32_t policy, unsigned long size, struct page **pages) |
| { |
| uint32_t handle = 0; |
| phys_addr_t ipa; |
| int ret = -1; |
| struct page *l_pages = NULL; |
| unsigned int order = get_order(size); |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return 0; |
| |
| l_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); |
| if (l_pages == NULL) |
| return 0; |
| ipa = page_to_phys(l_pages); |
| *pages = l_pages; |
| handle = mkp_create_handle(policy, ipa, size); |
| if (handle == 0) { |
| __free_pages(l_pages, order); |
| return 0; |
| } |
| |
| ret = do_secure_ops(policy, handle, mkp_set_mapping_rw_hvc_call); |
| if (ret == -1) { |
| ret = mkp_destroy_handle(policy, handle); |
| __free_pages(l_pages, order); |
| return 0; |
| } |
| *pages = l_pages; |
| return handle; |
| } |
| |
| int mkp_configure_sharebuf(uint32_t policy, uint32_t handle, uint32_t type, |
| unsigned long nr_entries, unsigned long size) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_configure_sharebuf_hvc_call(policy, handle, |
| type, nr_entries, size); |
| return ret; |
| } |
| int mkp_update_sharebuf_1_argu(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_update_sharebuf_1_argu_hvc_call(policy, handle, index, a1); |
| return ret; |
| } |
| int mkp_update_sharebuf_2_argu(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_update_sharebuf_2_argu_hvc_call(policy, handle, index, a1, a2); |
| return ret; |
| } |
| int mkp_update_sharebuf_3_argu(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2, unsigned long a3) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_update_sharebuf_3_argu_hvc_call(policy, handle, index, a1, a2, a3); |
| return ret; |
| } |
| int mkp_update_sharebuf_4_argu(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_update_sharebuf_4_argu_hvc_call(policy, handle, index, a1, a2, a3, a4); |
| return ret; |
| } |
| int mkp_update_sharebuf_5_argu(uint32_t policy, uint32_t handle, unsigned long index, |
| unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_update_sharebuf_5_argu_hvc_call(policy, handle, index, a1, a2, a3, a4, a5); |
| return ret; |
| } |
| int mkp_update_sharebuf(uint32_t policy, uint32_t handle, unsigned long index/*tag*/, |
| unsigned long ipa) |
| { |
| int ret = -1; |
| |
| if (policy >= MKP_POLICY_NR || policy_ctrl[policy] == 0) |
| return ret; |
| |
| ret = mkp_update_sharebuf_hvc_call(policy, handle, index, ipa); |
| return ret; |
| } |