1 /*
2 * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stddef.h>
8
9 #include "array.h"
10 #include "config_tfm.h"
11 #include "internal_status_code.h"
12 #include "ns_mailbox_client_id.h"
13 #include "tfm_plat_defs.h"
14 #include "tfm_multi_core.h"
15
tfm_multi_core_register_client_id_range(void * owner,uint32_t irq_source)16 int32_t tfm_multi_core_register_client_id_range(void *owner,
17 uint32_t irq_source)
18 {
19 size_t i;
20
21 if (owner == NULL) {
22 return SPM_ERROR_BAD_PARAMETERS;
23 }
24
25 for (i = 0; i < ARRAY_SIZE(ns_mailbox_client_id_info); i++) {
26 if (ns_mailbox_client_id_info[i].source == irq_source) {
27 if (ns_mailbox_client_id_range_owner[i] != NULL) {
28 return SPM_ERROR_GENERIC;
29 }
30
31 ns_mailbox_client_id_range_owner[i] = owner;
32 return SPM_SUCCESS;
33 }
34 }
35
36 return SPM_ERROR_GENERIC;
37 }
38
39 /* Map a negative client ID in the range of the owner's defined client ID. */
tfm_multi_core_hal_client_id_translate(void * owner,int32_t client_id_in,int32_t * client_id_out)40 int32_t tfm_multi_core_hal_client_id_translate(void *owner,
41 int32_t client_id_in,
42 int32_t *client_id_out)
43 {
44 size_t i;
45 int32_t base = 0, limit = 0;
46 int32_t min_client_id, client_id = 0;
47 const size_t nr_ranges = ARRAY_SIZE(ns_mailbox_client_id_range_owner);
48
49 if ((owner == NULL) || (client_id_out == NULL)) {
50 return SPM_ERROR_BAD_PARAMETERS;
51 }
52
53 #if MAILBOX_SUPPORT_NS_CLIENT_ID_ZERO
54 /* Accept client_id_in == 0 as a valid offset */
55 if (client_id_in > 0) {
56 return SPM_ERROR_BAD_PARAMETERS;
57 }
58 #else
59 if (client_id_in >= 0) {
60 return SPM_ERROR_BAD_PARAMETERS;
61 }
62 #endif
63
64 for (i = 0; i < nr_ranges; i++) {
65 if (ns_mailbox_client_id_range_owner[i] == owner) {
66 base = ns_mailbox_client_id_info[i].client_id_base;
67 limit = ns_mailbox_client_id_info[i].client_id_limit;
68 break;
69 }
70 }
71 if (i == nr_ranges) {
72 return SPM_ERROR_GENERIC;
73 }
74
75 /*
76 * client_id_range = limit - base + 1
77 * min_client_id = -client_id_range
78 *
79 * However client_id_range cannot be calculated directly, because if
80 * base = INT32_MIN and limit = -1 then
81 * client_id_range becomes INT32_MAX + 1 because
82 * abs(INT32_MIN) = abs(INT32_MAX) + 1 and that causes overflow. So
83 * min_client_id is calculated directly, with a reordered expression:
84 * min_client_id = -(limit - base + 1) ==
85 * -limit + base -1 ==
86 * -(limit - base) -1
87 */
88 min_client_id = -1 * (limit - base) - 1;
89
90 if (client_id_in < min_client_id) {
91 return SPM_ERROR_GENERIC;
92 }
93
94 /*
95 * 1 is added before client_id_in, so that no underflow happens even if
96 * limit + client_id_in == INT32_MIN - 1
97 */
98 client_id = (limit + 1) + client_id_in;
99
100 /*
101 * A final check.
102 * No further validation after this translation function returns.
103 * It is harmless to check the final output again, in case any corner case
104 * is not spotted in earlier checks.
105 */
106 if (client_id >= 0) {
107 return SPM_ERROR_GENERIC;
108 }
109
110 *client_id_out = client_id;
111 return SPM_SUCCESS;
112 }
113