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