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