1 /*
2 * Copyright (c) 2023-2026, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdint.h>
8 #include <errno.h>
9
10 #include <arch_features.h>
11 #include <common/debug.h>
12 #include <common/runtime_svc.h>
13
14 #include <plat/arm/common/arm_sip_svc.h>
15 #include <plat/common/platform.h>
16
17 #if SPMD_SPM_AT_SEL2
18 #include <lib/gpt_rme/gpt_rme.h>
19 #endif
20
21 #if ENABLE_SPMD_LP
22 #include <services/el3_spmd_logical_sp.h>
23 #endif
24
25 #if (defined(SPD_spmd) && SPMD_SPM_AT_SEL2 == 1)
plat_protect_memory(bool protect,bool secure_origin,const uint64_t base,const size_t size,void * handle)26 static uint64_t plat_protect_memory(bool protect,
27 bool secure_origin,
28 const uint64_t base,
29 const size_t size,
30 void *handle)
31 {
32 uint64_t ret = SMC_INVALID_PARAM;
33 uint64_t last_updated = 0;
34 uint64_t granule_count;
35
36 if (!is_feat_rme_supported()) {
37 SMC_RET1(handle, SMC_UNK);
38 }
39
40 if (!secure_origin) {
41 SMC_RET1(handle, SMC_UNK);
42 /* Shall not be reached. */
43 }
44
45 if ((base % PAGE_SIZE_4KB) != 0U &&
46 (size % PAGE_SIZE_4KB) != 0U) {
47 VERBOSE("Base address must be aligned to 4k.\n");
48 SMC_RET1(handle, SMC_INVALID_PARAM);
49 /* Shall not be reached. */
50 }
51
52 if ((ULONG_MAX - base) < size) {
53 VERBOSE("Base + Size results in overflow.\n");
54 SMC_RET1(handle, SMC_INVALID_PARAM);
55 /* Shall not be reached. */
56 }
57
58 for (uint64_t it = base; it < (base + size); it += PAGE_SIZE_4KB) {
59 /*
60 * If protect is true, add memory to secure PAS.
61 * Else unprotect it, making part of non-secure PAS.
62 */
63 granule_count = 1;
64
65 if (protect) {
66 ret = gpt_transition_pas(it, &granule_count,
67 GPT_GPI_SECURE,
68 SMC_FROM_SECURE);
69 } else {
70 ret = gpt_transition_pas(it, &granule_count, GPT_GPI_NS,
71 SMC_FROM_SECURE);
72 }
73
74 switch (ret) {
75 case 0:
76 last_updated = it;
77 break;
78 case -EINVAL:
79 SMC_RET2(handle, SMC_INVALID_PARAM, last_updated);
80 break; /* Shall not be reached. */
81 case -EPERM:
82 SMC_RET2(handle, SMC_DENIED, last_updated);
83 break; /* Shall not be reached. */
84 default:
85 ERROR("Unexpected return\n");
86 panic();
87 }
88 }
89
90 SMC_RET1(handle, SMC_OK);
91 }
92 #endif /* SPMD_SPM_AT_SEL2 */
93
plat_arm_sip_handler(uint32_t smc_fid,u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * cookie,void * handle,u_register_t flags)94 uintptr_t plat_arm_sip_handler(uint32_t smc_fid,
95 u_register_t x1,
96 u_register_t x2,
97 u_register_t x3,
98 u_register_t x4,
99 void *cookie,
100 void *handle,
101 u_register_t flags)
102 {
103 bool secure_origin;
104
105 /* Determine which security state this SMC originated from */
106 secure_origin = is_caller_secure(flags);
107 (void) secure_origin;
108
109 switch (smc_fid) {
110 #if PLAT_TEST_SPM
111 case ARM_SIP_SET_INTERRUPT_PENDING:
112 if (!secure_origin) {
113 SMC_RET1(handle, SMC_UNK);
114 }
115
116 VERBOSE("SiP Call- Set interrupt pending %d\n", (uint32_t)x1);
117 plat_ic_set_interrupt_pending(x1);
118
119 SMC_RET1(handle, SMC_OK);
120 break; /* Not reached */
121 #endif
122
123 #if (defined(SPD_spmd) && SPMD_SPM_AT_SEL2 == 1)
124 case PLAT_PROTECT_MEM_SMC64:
125 VERBOSE("Sip Call - Protect memory\n");
126 return plat_protect_memory(true, secure_origin, x1, x2, handle);
127 break;
128 case PLAT_UNPROTECT_MEM_SMC64:
129 VERBOSE("Sip Call - Unprotect memory\n");
130 return plat_protect_memory(false, secure_origin, x1, x2, handle);
131 break;
132 #endif
133 }
134
135 #if ENABLE_SPMD_LP
136 return plat_spmd_logical_sp_smc_handler(smc_fid, x1, x2, x3, x4,
137 cookie, handle, flags);
138 #else
139 WARN("Unimplemented ARM SiP Service Call: 0x%x\n", smc_fid);
140 SMC_RET1(handle, SMC_UNK);
141 #endif
142 }
143