1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     System Control and Management Interface (SCMI) support
9  *      resource management support.
10  */
11 
12 #include <mod_resource_perms.h>
13 #include <mod_scmi_std.h>
14 
15 #include <fwk_assert.h>
16 #include <fwk_log.h>
17 #include <fwk_mm.h>
18 #include <fwk_module.h>
19 #include <fwk_module_idx.h>
20 #include <fwk_status.h>
21 #include <fwk_string.h>
22 
23 #include <inttypes.h>
24 
25 struct res_perms_ctx {
26     /*! platform config data */
27     struct mod_res_resource_perms_config *config;
28 
29     /*! Number of agents for the platform. */
30     uint32_t agent_count;
31 
32     /*! Number of protocols for the platform. */
33     uint32_t protocol_count;
34 
35     /*! Number of clock resources for the platform. */
36     uint32_t clock_count;
37 
38     /*! Number of sensor resources for the platform. */
39     uint32_t sensor_count;
40 
41     /*! Number of power domain resources for the platform. */
42     uint32_t pd_count;
43 
44     /*! Number of performance domain resources for the platform. */
45     uint32_t perf_count;
46 
47     /*! Number of devices for the platform. */
48     uint32_t device_count;
49 
50 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
51     /*! Number of reset domain resources for the platform. */
52     uint32_t reset_domain_count;
53 #endif
54 
55     /*! Number of voltage domain resources for the platform. */
56     uint32_t voltd_count;
57 
58     /*!
59      * The  default is for an agent to have permission to access any
60      * resource. In order to deny permissions to an agent the table
61      * must be created and the relevant bit SET. If the table is not
62      * created then all agents have access to all resources.
63      *
64      * The agent_permissions table can be created in the SCMI config
65      * file.
66      *
67      * If the agent_permissions table was not set up in the config,
68      * the agent will not be able to allocate permissions at run-time.
69      *
70      * Note that if the agent wants to set permissions at run-time
71      * the agent_permissions[] tables must be allocated in writable
72      * memory.
73      */
74     struct mod_res_agent_permission *agent_permissions;
75 
76     /*!
77      * The list of domain devices in the system. If this is not set then setting
78      * device permissions for an agent is not supported.
79      */
80     struct mod_res_device *domain_devices;
81 };
82 
83 struct res_perms_backup {
84     /*! \brief Power Domain:Resource permissions. */
85     mod_res_perms_t *scmi_pd_perms;
86 
87     /*! Performance:Resource permissions. */
88     mod_res_perms_t *scmi_perf_perms;
89 
90     /*! \brief Clock:Resource permissions. */
91     mod_res_perms_t *scmi_clock_perms;
92 
93     /*! \brief Sensor:Resource permissions. */
94     mod_res_perms_t *scmi_sensor_perms;
95 
96 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
97     /*! \brief Reset Domain:Resource permissions. */
98     mod_res_perms_t *scmi_reset_domain_perms;
99 #endif
100 
101     /*! \brief Voltage Domain:Resource permissions. */
102     mod_res_perms_t *scmi_voltd_perms;
103 };
104 
105 static struct res_perms_ctx resources_perms_ctx;
106 static struct res_perms_backup resources_perms_backup;
107 
108 /*
109  * Map the agent-id to the corresponding index in the table.
110  *
111  * Returns FWK_SUCCESS if the agent_id is valid for the platform.
112  * Returns FWK_E_PARAM if the agent_is id not valid for the platform.
113  *
114  * This is a weak definition to allow the platform override the function
115  * to deal with platform-specific agent mappings, eg, for non-sequential
116  * agent IDs or for sharing a single set of permissions between multiple
117  * agents, etc.
118  */
mod_res_agent_id_to_index(uint32_t agent_id,uint32_t * agent_idx)119 __attribute((weak)) int mod_res_agent_id_to_index(
120     uint32_t agent_id,
121     uint32_t *agent_idx)
122 {
123     uint32_t idx = agent_id - 1;
124 
125     if (idx < resources_perms_ctx.agent_count) {
126         *agent_idx = idx;
127         return FWK_SUCCESS;
128     }
129 
130     return FWK_E_PARAM;
131 }
132 
133 /*
134  * Map the protocol-id to the corresponding index in the table.
135  *
136  * Returns true if the protocol_id is valid for the platform.
137  * Returns false if the protocol_is id not valid for the platform.
138  *
139  * This is a weak definition to allow the platform override the function
140  * to deal with platform-specific protocol mappings, eg, for non-contiguous
141  * protocol IDs.
142  */
mod_res_plat_protocol_id_to_index(uint32_t protocol_id,uint32_t * protocol_idx)143 __attribute((weak)) int mod_res_plat_protocol_id_to_index(
144     uint32_t protocol_id,
145     uint32_t *protocol_idx)
146 {
147     return FWK_E_PARAM;
148 }
149 
mod_res_protocol_id_to_index(uint32_t protocol_id,uint32_t * protocol_idx)150 static int mod_res_protocol_id_to_index(
151     uint32_t protocol_id,
152     uint32_t *protocol_idx)
153 {
154     if ((protocol_id >= MOD_SCMI_PLATFORM_PROTOCOL_ID_MIN) &&
155         (protocol_id <= MOD_SCMI_PLATFORM_PROTOCOL_ID_MAX)) {
156         return mod_res_plat_protocol_id_to_index(protocol_id, protocol_idx);
157     }
158 
159     switch (protocol_id) {
160     case MOD_SCMI_PROTOCOL_ID_BASE:
161     case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN:
162     case MOD_SCMI_PROTOCOL_ID_SYS_POWER:
163     case MOD_SCMI_PROTOCOL_ID_PERF:
164     case MOD_SCMI_PROTOCOL_ID_CLOCK:
165     case MOD_SCMI_PROTOCOL_ID_SENSOR:
166     case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN:
167     case MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
168         *protocol_idx = protocol_id - MOD_SCMI_PROTOCOL_ID_BASE;
169         return FWK_SUCCESS;
170     default:
171         return FWK_E_PARAM;
172     }
173 }
174 
175 /*
176  * Map the message-id to the corresponding index in the resources
177  * table.
178  *
179  * Returns FWK_SUCCESS if the message_id is valid for the protocol.
180  * Returns FWK_E_PARAM if the message_id not valid for the protocol.
181  *
182  * Contents of idx are only valid if >= 0.
183  *
184  * This is a weak definition to allow the platform override the function
185  * to deal with platform-specific message ID mappings, eg, for non-contiguous
186  * message IDs.
187  */
mod_res_plat_message_id_to_index(uint32_t protocol_id,uint32_t message_id,int32_t * message_idx)188 __attribute((weak)) int mod_res_plat_message_id_to_index(
189     uint32_t protocol_id,
190     uint32_t message_id,
191     int32_t *message_idx)
192 {
193     return FWK_E_PARAM;
194 }
195 
mod_res_message_id_to_index(uint32_t protocol_id,uint32_t message_id,int32_t * message_idx)196 static int mod_res_message_id_to_index(
197     uint32_t protocol_id,
198     uint32_t message_id,
199     int32_t *message_idx)
200 {
201     /*
202      * All protocols have
203      *
204      *  0: VERSION
205      *  1: ATTRIBUTES
206      *  2: MSG_ATTRIBUTES
207      *
208      * messages which are available to all agents.
209      *
210      * If the message is not managed in the permissions
211      * we return false and idx == -1.
212      */
213     *message_idx = -1;
214 
215     if ((protocol_id >= MOD_SCMI_PLATFORM_PROTOCOL_ID_MIN) &&
216         (protocol_id <= MOD_SCMI_PLATFORM_PROTOCOL_ID_MAX)) {
217         return mod_res_plat_message_id_to_index(
218             protocol_id, message_id, message_idx);
219     }
220 
221     if (message_id < 3) {
222         return FWK_SUCCESS;
223     }
224 
225     switch (protocol_id) {
226     case MOD_SCMI_PROTOCOL_ID_BASE:
227         if (message_id >= MOD_SCMI_BASE_COMMAND_COUNT) {
228             return FWK_E_PARAM;
229         }
230         if (message_id == MOD_SCMI_BASE_NOTIFY_ERRORS) {
231             *message_idx = 0;
232         }
233         return FWK_SUCCESS;
234 
235     case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN:
236         if (message_id >= MOD_SCMI_PD_POWER_COMMAND_COUNT) {
237             return FWK_E_PARAM;
238         }
239         if ((message_id >= MOD_SCMI_PD_POWER_DOMAIN_ATTRIBUTES) &&
240             (message_id <= MOD_SCMI_PD_POWER_STATE_NOTIFY)) {
241             *message_idx = (int32_t)(
242                 message_id - (uint32_t)MOD_SCMI_PD_POWER_DOMAIN_ATTRIBUTES);
243         }
244         return FWK_SUCCESS;
245 
246     case MOD_SCMI_PROTOCOL_ID_SYS_POWER:
247         if (message_id >= MOD_SCMI_SYS_POWER_COMMAND_COUNT) {
248             return FWK_E_PARAM;
249         }
250         if ((message_id >= MOD_SCMI_SYS_POWER_STATE_SET) &&
251             (message_id <= MOD_SCMI_SYS_POWER_STATE_NOTIFY)) {
252             *message_idx =
253                 (int32_t)(message_id - (uint32_t)MOD_SCMI_SYS_POWER_STATE_SET);
254         }
255         return FWK_SUCCESS;
256 
257     case MOD_SCMI_PROTOCOL_ID_PERF:
258         if (message_id >= MOD_SCMI_PERF_COMMAND_COUNT) {
259             return FWK_E_PARAM;
260         }
261         if ((message_id >= MOD_SCMI_PERF_DOMAIN_ATTRIBUTES) &&
262             (message_id <= MOD_SCMI_PERF_DESCRIBE_FAST_CHANNEL)) {
263             *message_idx = (int32_t)(
264                 message_id - (uint32_t)MOD_SCMI_PERF_DOMAIN_ATTRIBUTES);
265         }
266         return FWK_SUCCESS;
267 
268     case MOD_SCMI_PROTOCOL_ID_CLOCK:
269         if (message_id >= MOD_SCMI_CLOCK_COMMAND_COUNT) {
270             return FWK_E_PARAM;
271         }
272         if ((message_id >= MOD_SCMI_CLOCK_ATTRIBUTES) &&
273             (message_id <= MOD_SCMI_CLOCK_CONFIG_SET)) {
274             *message_idx =
275                 (int32_t)(message_id - (uint32_t)MOD_SCMI_CLOCK_ATTRIBUTES);
276         }
277         return FWK_SUCCESS;
278 
279     case MOD_SCMI_PROTOCOL_ID_SENSOR:
280         if (message_id >= MOD_SCMI_SENSOR_COMMAND_COUNT) {
281             return FWK_E_PARAM;
282         }
283         if ((message_id >= MOD_SCMI_SENSOR_DESCRIPTION_GET) &&
284             (message_id <= MOD_SCMI_SENSOR_READING_GET)) {
285             *message_idx = (int32_t)(
286                 message_id - (uint32_t)MOD_SCMI_SENSOR_DESCRIPTION_GET);
287         }
288         return FWK_SUCCESS;
289 
290     case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN:
291         if (message_id >= MOD_SCMI_RESET_COMMAND_COUNT) {
292             return FWK_E_PARAM;
293         }
294         if ((message_id >= MOD_SCMI_RESET_DOMAIN_ATTRIBUTES) &&
295             (message_id <= MOD_SCMI_RESET_NOTIFY)) {
296             *message_idx = (int32_t)(
297                 message_id - (uint32_t)MOD_SCMI_RESET_DOMAIN_ATTRIBUTES);
298         }
299         return FWK_SUCCESS;
300 
301     case MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
302         if (message_id >= MOD_SCMI_VOLTD_COMMAND_COUNT) {
303             return FWK_E_PARAM;
304         }
305         if ((message_id >= MOD_SCMI_VOLTD_DOMAIN_ATTRIBUTES) &&
306             (message_id <= MOD_SCMI_VOLTD_LEVEL_GET)) {
307             *message_idx = (int32_t)(
308                 message_id - (uint32_t)MOD_SCMI_VOLTD_DOMAIN_ATTRIBUTES);
309         }
310         return FWK_SUCCESS;
311 
312     default:
313         return FWK_E_PARAM;
314     }
315 }
316 
317 /*
318  * Map the resource-id to the corresponding element index in the resources
319  * table.
320  *
321  * Returns FWK_SUCCESS if the resource_id is valid for the protocol.
322  * Returns FWK_E_PARAM if the resource_id not valid for the protocol.
323  *
324  * Contents of resource_idx are only valid if >= 0.
325  *
326  * This is a weak definition to allow the platform override the function
327  * to deal with platform-specific ID mappings, eg, for non-contiguous
328  * IDs.
329  */
mod_res_plat_resource_id_to_index(uint32_t agent_id,uint32_t protocol_id,uint32_t message_id,uint32_t resource_id,int32_t * resource_idx)330 __attribute((weak)) int mod_res_plat_resource_id_to_index(
331     uint32_t agent_id,
332     uint32_t protocol_id,
333     uint32_t message_id,
334     uint32_t resource_id,
335     int32_t *resource_idx)
336 {
337     return FWK_E_PARAM;
338 }
339 
mod_res_resource_id_to_index(uint32_t agent_id,uint32_t protocol_id,uint32_t message_id,uint32_t resource_id,int32_t * resource_idx)340 static int mod_res_resource_id_to_index(
341     uint32_t agent_id,
342     uint32_t protocol_id,
343     uint32_t message_id,
344     uint32_t resource_id,
345     int32_t *resource_idx)
346 {
347     uint32_t agent_idx;
348     int message_count;
349     int message_offset;
350     int resource_size;
351     int status;
352 
353     /*
354      * All protocols have
355      *
356      *  0: VERSION
357      *  1: ATTRIBUTES
358      *  2: MSG_ATTRIBUTES
359      *
360      * messages which are available to all agents.
361      *
362      * If the message is not managed in the permissions
363      * we return false and idx == -1.
364      */
365     *resource_idx = -1;
366 
367     if ((protocol_id >= MOD_SCMI_PLATFORM_PROTOCOL_ID_MIN) &&
368         (protocol_id <= MOD_SCMI_PLATFORM_PROTOCOL_ID_MAX)) {
369         return mod_res_plat_resource_id_to_index(
370             agent_id, protocol_id, message_id, resource_id, resource_idx);
371     }
372 
373     if (message_id < 3) {
374         return FWK_SUCCESS;
375     }
376 
377     /*
378      * Each table is organised as
379      *
380      *      agent[number_of_agents].commands[number_of_commands_for_protocol]
381      */
382 
383     switch (protocol_id) {
384     case MOD_SCMI_PROTOCOL_ID_BASE:
385         /* No per-resource managemment for SCMI Base Protocol */
386         return FWK_E_PARAM;
387 
388     case MOD_SCMI_PROTOCOL_ID_SYS_POWER:
389         /* No per-resource managemment for SCMI System Power Protocol */
390         return FWK_E_PARAM;
391 
392     case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN:
393         if ((message_id >= MOD_SCMI_PD_POWER_DOMAIN_ATTRIBUTES) &&
394             (message_id <= MOD_SCMI_PD_POWER_STATE_NOTIFY)) {
395             message_count = (int)MOD_SCMI_PD_POWER_STATE_NOTIFY -
396                 (int)MOD_SCMI_PD_POWER_DOMAIN_ATTRIBUTES + 1;
397             message_offset =
398                 (int)(message_id - (uint32_t)MOD_SCMI_PD_POWER_DOMAIN_ATTRIBUTES);
399             resource_size = (int)resources_perms_ctx.pd_count;
400             break;
401         }
402         return FWK_E_PARAM;
403 
404     case MOD_SCMI_PROTOCOL_ID_PERF:
405         if ((message_id >= MOD_SCMI_PERF_DOMAIN_ATTRIBUTES) &&
406             (message_id <= MOD_SCMI_PERF_DESCRIBE_FAST_CHANNEL)) {
407             message_count = (int)MOD_SCMI_PERF_DESCRIBE_FAST_CHANNEL -
408                 (int)MOD_SCMI_PERF_DOMAIN_ATTRIBUTES + 1;
409             message_offset =
410                 (int)(message_id - (uint32_t)MOD_SCMI_PERF_DOMAIN_ATTRIBUTES);
411             resource_size = (int)resources_perms_ctx.perf_count;
412             break;
413         }
414         return FWK_E_PARAM;
415 
416     case MOD_SCMI_PROTOCOL_ID_CLOCK:
417         if ((message_id >= MOD_SCMI_CLOCK_ATTRIBUTES) &&
418             (message_id <= MOD_SCMI_CLOCK_CONFIG_SET)) {
419             message_count = (int)MOD_SCMI_CLOCK_CONFIG_SET -
420                 (int)MOD_SCMI_CLOCK_ATTRIBUTES + 1;
421             message_offset =
422                 (int)(message_id - (uint32_t)MOD_SCMI_CLOCK_ATTRIBUTES);
423             resource_size = (int)resources_perms_ctx.clock_count;
424             break;
425         }
426         return FWK_E_PARAM;
427 
428     case MOD_SCMI_PROTOCOL_ID_SENSOR:
429         if ((message_id >= MOD_SCMI_SENSOR_DESCRIPTION_GET) &&
430             (message_id <= MOD_SCMI_SENSOR_READING_GET)) {
431             message_count = (int)MOD_SCMI_SENSOR_READING_GET -
432                 (int)MOD_SCMI_SENSOR_DESCRIPTION_GET + 1;
433             message_offset =
434                 (int)(message_id - (uint32_t)MOD_SCMI_SENSOR_DESCRIPTION_GET);
435             resource_size = (int)resources_perms_ctx.sensor_count;
436             break;
437         }
438         return FWK_E_PARAM;
439 
440 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
441     case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN:
442         if ((message_id >= MOD_SCMI_RESET_DOMAIN_ATTRIBUTES) &&
443             (message_id <= MOD_SCMI_RESET_NOTIFY)) {
444             message_count = (int)MOD_SCMI_RESET_NOTIFY -
445                 (int)MOD_SCMI_RESET_DOMAIN_ATTRIBUTES + 1;
446             message_offset =
447                 (int)(message_id - (uint32_t)MOD_SCMI_RESET_DOMAIN_ATTRIBUTES);
448             resource_size = (int)resources_perms_ctx.reset_domain_count;
449             break;
450         }
451         return FWK_E_PARAM;
452 #endif
453 
454     case MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
455         if ((message_id >= MOD_SCMI_VOLTD_DOMAIN_ATTRIBUTES) &&
456             (message_id <= MOD_SCMI_VOLTD_LEVEL_GET)) {
457             message_count = (int)MOD_SCMI_VOLTD_LEVEL_GET -
458                 (int)MOD_SCMI_VOLTD_DOMAIN_ATTRIBUTES + 1;
459             message_offset =
460                 (int)(message_id - (uint32_t)MOD_SCMI_VOLTD_DOMAIN_ATTRIBUTES);
461             resource_size = (int)resources_perms_ctx.voltd_count;
462             break;
463         }
464         return FWK_E_PARAM;
465 
466     default:
467         return FWK_E_PARAM;
468     }
469 
470     status = mod_res_agent_id_to_index(agent_id, &agent_idx);
471     if ((status != FWK_SUCCESS) ||
472         (agent_idx >= resources_perms_ctx.agent_count)) {
473         return FWK_E_PARAM;
474     }
475 
476     resource_size =
477         (int)MOD_RES_PERMS_RESOURCE_ELEMENT((unsigned int)resource_size) + 1;
478 
479     /*
480      * message_count: the number of messages for the agent.
481      * resource_size: the number of resource elements per message type.
482      * message_offset: the offset of this message from message 0.
483      *
484      * [1]: &agent[agent_idx].message[0]
485      * [2]: &agent[agent_idx].message[message_id]
486      * [3]: &agent[agent_idx].message[message_id].resource[resource_id]
487      */
488     *resource_idx = (int32_t)(
489         (agent_idx * message_count * resource_size) + /* [1] */
490         (message_offset * resource_size) + /* [2] */
491         MOD_RES_PERMS_RESOURCE_ELEMENT(resource_id)); /* [3] */
492 
493     return FWK_SUCCESS;
494 }
495 
496 /*
497  * Check whether an agent has access to a protocol.
498  *
499  * Note that we will always check the higher permissions levels
500  * when called, so
501  *
502  *      protocol -> message -> resource
503  */
504 
505 /*
506  * Check whether an agent has access to a protocol.
507  *
508  * Note that we will always check the higher permissions levels
509  * when called, so
510  *
511  *      protocol -> message -> resource
512  */
513 __attribute((weak)) enum mod_res_perms_permissions
mod_res_plat_agent_protocol_permissions(uint32_t agent_id,uint32_t protocol_id)514     mod_res_plat_agent_protocol_permissions(
515         uint32_t agent_id,
516         uint32_t protocol_id)
517 {
518     return MOD_RES_PERMS_ACCESS_DENIED;
519 }
520 
agent_protocol_permissions(uint32_t agent_id,uint32_t protocol_id)521 static enum mod_res_perms_permissions agent_protocol_permissions(
522     uint32_t agent_id,
523     uint32_t protocol_id)
524 {
525     uint32_t agent_idx;
526     uint32_t protocol_idx;
527     mod_res_perms_t perms;
528     int status;
529 
530     /* No Agent:Protocol permissions management */
531     if ((agent_id == 0) || (resources_perms_ctx.agent_permissions == NULL) ||
532         (resources_perms_ctx.agent_permissions->agent_protocol_permissions ==
533          NULL)) {
534         return MOD_RES_PERMS_ACCESS_ALLOWED;
535     }
536 
537     if ((protocol_id >= MOD_SCMI_PLATFORM_PROTOCOL_ID_MIN) &&
538         (protocol_id <= MOD_SCMI_PLATFORM_PROTOCOL_ID_MAX)) {
539         return mod_res_plat_agent_protocol_permissions(agent_id, protocol_id);
540     }
541 
542     status = mod_res_agent_id_to_index(agent_id, &agent_idx);
543     if ((status != FWK_SUCCESS) ||
544         (agent_idx >= resources_perms_ctx.agent_count)) {
545         return MOD_RES_PERMS_ACCESS_DENIED;
546     }
547 
548     status = mod_res_protocol_id_to_index(protocol_id, &protocol_idx);
549     if ((status != FWK_SUCCESS) ||
550         (protocol_idx >= resources_perms_ctx.protocol_count)) {
551         return MOD_RES_PERMS_ACCESS_DENIED;
552     }
553 
554     perms = resources_perms_ctx.agent_permissions
555                 ->agent_protocol_permissions[agent_idx]
556                 .protocols;
557 
558     /* Agent:Protocol access denied */
559     if (perms & (1U << protocol_idx)) {
560         return MOD_RES_PERMS_ACCESS_DENIED;
561     }
562 
563     return MOD_RES_PERMS_ACCESS_ALLOWED;
564 }
565 
566 /*
567  * Check whether an agent can access a protocol:message.
568  */
569 __attribute((weak)) enum mod_res_perms_permissions
mod_res_plat_agent_message_permissions(uint32_t agent_id,uint32_t protocol_id,uint32_t message_id)570     mod_res_plat_agent_message_permissions(
571         uint32_t agent_id,
572         uint32_t protocol_id,
573         uint32_t message_id)
574 {
575     return MOD_RES_PERMS_ACCESS_DENIED;
576 }
577 
agent_message_permissions(uint32_t agent_id,uint32_t protocol_id,uint32_t message_id)578 static enum mod_res_perms_permissions agent_message_permissions(
579     uint32_t agent_id,
580     uint32_t protocol_id,
581     uint32_t message_id)
582 {
583     enum mod_res_perms_permissions protocol_perms;
584     uint32_t agent_idx;
585     uint32_t protocol_idx;
586     int32_t message_idx;
587     mod_res_perms_t perms;
588     int status;
589 
590     /* No permissions management */
591     if ((agent_id == 0) || (resources_perms_ctx.agent_permissions == NULL)) {
592         return MOD_RES_PERMS_ACCESS_ALLOWED;
593     }
594 
595     if ((protocol_id >= MOD_SCMI_PLATFORM_PROTOCOL_ID_MIN) &&
596         (protocol_id <= MOD_SCMI_PLATFORM_PROTOCOL_ID_MAX)) {
597         return mod_res_plat_agent_message_permissions(
598             agent_id, protocol_id, message_id);
599     }
600 
601     /* Agent:Protocol access denied */
602     protocol_perms = agent_protocol_permissions(agent_id, protocol_id);
603     if (protocol_perms == MOD_RES_PERMS_ACCESS_DENIED) {
604         return MOD_RES_PERMS_ACCESS_DENIED;
605     }
606 
607     /* No Agent:Protocol:command permissions management */
608     if (resources_perms_ctx.agent_permissions->agent_msg_permissions == NULL) {
609         return MOD_RES_PERMS_ACCESS_ALLOWED;
610     }
611 
612     status = mod_res_message_id_to_index(protocol_id, message_id, &message_idx);
613     if (status != FWK_SUCCESS) {
614         return MOD_RES_PERMS_ACCESS_DENIED;
615     }
616 
617     if (message_idx < 0) {
618         return MOD_RES_PERMS_ACCESS_ALLOWED;
619     }
620 
621     status = mod_res_agent_id_to_index(agent_id, &agent_idx);
622     if (status != FWK_SUCCESS) {
623         return MOD_RES_PERMS_ACCESS_DENIED;
624     }
625 
626     status = mod_res_protocol_id_to_index(protocol_id, &protocol_idx);
627     if (status != FWK_SUCCESS) {
628         return MOD_RES_PERMS_ACCESS_DENIED;
629     }
630 
631     perms =
632         resources_perms_ctx.agent_permissions->agent_msg_permissions[agent_idx]
633             .messages[protocol_idx];
634 
635     /* Agent:Protocol:message access denied */
636     if (perms & (1U << (uint32_t)message_idx)) {
637         return MOD_RES_PERMS_ACCESS_DENIED;
638     }
639 
640     return MOD_RES_PERMS_ACCESS_ALLOWED;
641 }
642 
643 /*
644  * Check the permissions for agent:protocol:message:resource.
645  *
646  * Note that BASE and SYSTEM_POWER protocols do not support
647  * resource-level permissions checking, these protocols are
648  * managed at the  agent:protocol:message level.
649  */
650 __attribute((weak)) enum mod_res_perms_permissions
mod_res_plat_agent_resource_permissions(uint32_t agent_id,uint32_t protocol_id,uint32_t message_id,uint32_t resource_id)651     mod_res_plat_agent_resource_permissions(
652         uint32_t agent_id,
653         uint32_t protocol_id,
654         uint32_t message_id,
655         uint32_t resource_id)
656 {
657     return MOD_RES_PERMS_ACCESS_DENIED;
658 }
659 
agent_resource_permissions(uint32_t agent_id,uint32_t protocol_id,uint32_t message_id,uint32_t resource_id)660 static enum mod_res_perms_permissions agent_resource_permissions(
661     uint32_t agent_id,
662     uint32_t protocol_id,
663     uint32_t message_id,
664     uint32_t resource_id)
665 {
666     enum mod_res_perms_permissions message_perms;
667     uint32_t agent_idx;
668     int32_t message_idx;
669     int32_t resource_idx;
670     mod_res_perms_t perms;
671     int status;
672 
673     /* No permissions management */
674     if ((agent_id == 0) || (resources_perms_ctx.agent_permissions == NULL)) {
675         return MOD_RES_PERMS_ACCESS_ALLOWED;
676     }
677 
678     if ((protocol_id >= MOD_SCMI_PLATFORM_PROTOCOL_ID_MIN) &&
679         (protocol_id <= MOD_SCMI_PLATFORM_PROTOCOL_ID_MAX)) {
680         return mod_res_plat_agent_resource_permissions(
681             agent_id, protocol_id, message_id, resource_id);
682     }
683 
684     /* Agent:Protocol:command access denied */
685     message_perms =
686         agent_message_permissions(agent_id, protocol_id, message_id);
687     if (message_perms == MOD_RES_PERMS_ACCESS_DENIED) {
688         return MOD_RES_PERMS_ACCESS_DENIED;
689     }
690 
691     status = mod_res_message_id_to_index(protocol_id, message_id, &message_idx);
692     if (status != FWK_SUCCESS) {
693         return MOD_RES_PERMS_ACCESS_DENIED;
694     }
695     if (message_idx < 0) {
696         return MOD_RES_PERMS_ACCESS_ALLOWED;
697     }
698 
699     status = mod_res_agent_id_to_index(agent_id, &agent_idx);
700     if (status != FWK_SUCCESS) {
701         return MOD_RES_PERMS_ACCESS_DENIED;
702     }
703 
704     status = mod_res_resource_id_to_index(
705         agent_id, protocol_id, message_id, resource_id, &resource_idx);
706     if (status != FWK_SUCCESS) {
707         return MOD_RES_PERMS_ACCESS_DENIED;
708     }
709     if (resource_idx < 0) {
710         return MOD_RES_PERMS_ACCESS_ALLOWED;
711     }
712 
713     switch (protocol_id) {
714     case MOD_SCMI_PROTOCOL_ID_BASE:
715         return MOD_RES_PERMS_ACCESS_DENIED;
716 
717     case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN:
718         if (resources_perms_ctx.agent_permissions->scmi_pd_perms == NULL) {
719             return MOD_RES_PERMS_ACCESS_ALLOWED;
720         }
721         if (resource_id >= resources_perms_ctx.pd_count) {
722             return MOD_RES_PERMS_ACCESS_DENIED;
723         }
724         perms =
725             resources_perms_ctx.agent_permissions->scmi_pd_perms[resource_idx];
726         break;
727 
728     case MOD_SCMI_PROTOCOL_ID_SYS_POWER:
729         return MOD_RES_PERMS_ACCESS_DENIED;
730 
731     case MOD_SCMI_PROTOCOL_ID_PERF:
732         if (resources_perms_ctx.agent_permissions->scmi_perf_perms == NULL) {
733             return MOD_RES_PERMS_ACCESS_ALLOWED;
734         }
735         if (resource_id >= resources_perms_ctx.perf_count) {
736             return MOD_RES_PERMS_ACCESS_DENIED;
737         }
738         perms = resources_perms_ctx.agent_permissions
739                     ->scmi_perf_perms[resource_idx];
740         break;
741 
742     case MOD_SCMI_PROTOCOL_ID_CLOCK:
743         if (resources_perms_ctx.agent_permissions->scmi_clock_perms == NULL) {
744             return MOD_RES_PERMS_ACCESS_ALLOWED;
745         }
746         if (resource_id >= resources_perms_ctx.clock_count) {
747             return MOD_RES_PERMS_ACCESS_DENIED;
748         }
749         perms = resources_perms_ctx.agent_permissions
750                     ->scmi_clock_perms[resource_idx];
751         break;
752 
753     case MOD_SCMI_PROTOCOL_ID_SENSOR:
754         if (resources_perms_ctx.agent_permissions->scmi_sensor_perms == NULL) {
755             return MOD_RES_PERMS_ACCESS_ALLOWED;
756         }
757         if (resource_id >= resources_perms_ctx.sensor_count) {
758             return MOD_RES_PERMS_ACCESS_DENIED;
759         }
760         perms = resources_perms_ctx.agent_permissions
761                     ->scmi_sensor_perms[resource_idx];
762         break;
763 
764 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
765     case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN:
766         if (resources_perms_ctx.agent_permissions->scmi_reset_domain_perms ==
767             NULL) {
768             return MOD_RES_PERMS_ACCESS_ALLOWED;
769         }
770         if (resource_id >= resources_perms_ctx.reset_domain_count) {
771             return MOD_RES_PERMS_ACCESS_DENIED;
772         }
773         perms = resources_perms_ctx.agent_permissions
774                     ->scmi_reset_domain_perms[resource_idx];
775         break;
776 #endif
777 
778     case MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
779         if (resources_perms_ctx.agent_permissions->scmi_voltd_perms == NULL) {
780             return MOD_RES_PERMS_ACCESS_ALLOWED;
781         }
782         if (resource_id >= resources_perms_ctx.voltd_count) {
783             return MOD_RES_PERMS_ACCESS_DENIED;
784         }
785         perms = resources_perms_ctx.agent_permissions
786                     ->scmi_voltd_perms[resource_idx];
787         break;
788 
789     default:
790         return MOD_RES_PERMS_ACCESS_DENIED;
791     }
792 
793     /* Agent:Protocol:message:resource access denied */
794     if ((perms & (1U << (MOD_RES_PERMS_RESOURCE_BIT(resource_id))))) {
795         return MOD_RES_PERMS_ACCESS_DENIED;
796     }
797 
798     return MOD_RES_PERMS_ACCESS_ALLOWED;
799 }
800 
801 /*
802  * Set the permissions for an agent:device.
803  */
set_agent_resource_message_perms(uint32_t agent_id,uint32_t protocol_id,uint32_t message_idx,uint32_t resource_id,mod_res_perms_t * perms,enum mod_res_perms_permissions flags)804 static int set_agent_resource_message_perms(
805     uint32_t agent_id,
806     uint32_t protocol_id,
807     uint32_t message_idx,
808     uint32_t resource_id,
809     mod_res_perms_t *perms,
810     enum mod_res_perms_permissions flags)
811 {
812     int status;
813     int32_t resource_idx;
814     mod_res_perms_t permissions;
815 
816     status = mod_res_resource_id_to_index(
817         agent_id, protocol_id, message_idx, resource_id, &resource_idx);
818     if (status != FWK_SUCCESS) {
819         return status;
820     }
821 
822     permissions = perms[resource_idx];
823 
824     flags =
825         ((flags == 0) ? MOD_RES_PERMS_ACCESS_DENIED :
826                         MOD_RES_PERMS_ACCESS_ALLOWED);
827 
828     if (flags == MOD_RES_PERMS_ACCESS_ALLOWED) {
829         permissions &= ~(1U << (MOD_RES_PERMS_RESOURCE_BIT(resource_id)));
830     } else {
831         permissions |= (1U << (MOD_RES_PERMS_RESOURCE_BIT(resource_id)));
832     }
833 
834     perms[resource_idx] = permissions;
835 
836     return FWK_SUCCESS;
837 }
838 
set_agent_resource_pd_permissions(uint32_t agent_id,uint32_t resource_id,enum mod_res_perms_permissions flags)839 static int set_agent_resource_pd_permissions(
840     uint32_t agent_id,
841     uint32_t resource_id,
842     enum mod_res_perms_permissions flags)
843 {
844     int status;
845     int32_t message_idx;
846 
847     if (resources_perms_ctx.agent_permissions->scmi_pd_perms == NULL) {
848         return FWK_SUCCESS;
849     }
850     if (resource_id >= resources_perms_ctx.pd_count) {
851         return FWK_E_ACCESS;
852     }
853 
854     /* Do a backup before making the changes if required */
855     if ((resources_perms_ctx.config->pd_cmd_count != 0) &&
856         (resources_perms_ctx.config->pd_resource_count != 0) &&
857         (resources_perms_backup.scmi_pd_perms == NULL)) {
858         resources_perms_backup.scmi_pd_perms = (mod_res_perms_t *)fwk_mm_alloc(
859             resources_perms_ctx.agent_count *
860                 resources_perms_ctx.config->pd_cmd_count *
861                 resources_perms_ctx.config->pd_resource_count,
862             sizeof(mod_res_perms_t));
863         fwk_str_memcpy(
864             resources_perms_backup.scmi_pd_perms,
865             resources_perms_ctx.agent_permissions->scmi_pd_perms,
866             resources_perms_ctx.agent_count *
867                 resources_perms_ctx.config->pd_cmd_count *
868                 resources_perms_ctx.config->pd_resource_count *
869                 sizeof(mod_res_perms_t));
870     }
871 
872     for (message_idx = (int32_t)MOD_SCMI_PD_POWER_DOMAIN_ATTRIBUTES;
873          message_idx <= MOD_SCMI_PD_POWER_STATE_NOTIFY;
874          message_idx++) {
875         status = set_agent_resource_message_perms(
876             agent_id,
877             MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN,
878             (uint32_t)message_idx,
879             resource_id,
880             resources_perms_ctx.agent_permissions->scmi_pd_perms,
881             flags);
882 
883         if (status != FWK_SUCCESS) {
884             return status;
885         }
886     }
887 
888     return FWK_SUCCESS;
889 }
890 
set_agent_resource_perf_permissions(uint32_t agent_id,uint32_t resource_id,enum mod_res_perms_permissions flags)891 static int set_agent_resource_perf_permissions(
892     uint32_t agent_id,
893     uint32_t resource_id,
894     enum mod_res_perms_permissions flags)
895 {
896     int status;
897     int32_t message_idx;
898 
899     if (resources_perms_ctx.agent_permissions->scmi_perf_perms == NULL) {
900         return FWK_SUCCESS;
901     }
902     if (resource_id >= resources_perms_ctx.perf_count) {
903         return FWK_E_ACCESS;
904     }
905 
906     /* Do a backup before making the changes if required */
907     if ((resources_perms_ctx.config->perf_cmd_count != 0) &&
908         (resources_perms_ctx.config->perf_resource_count != 0) &&
909         (resources_perms_backup.scmi_perf_perms == NULL)) {
910         resources_perms_backup.scmi_perf_perms =
911             (mod_res_perms_t *)fwk_mm_alloc(
912                 resources_perms_ctx.agent_count *
913                     resources_perms_ctx.config->perf_cmd_count *
914                     resources_perms_ctx.config->perf_resource_count,
915                 sizeof(mod_res_perms_t));
916         fwk_str_memcpy(
917             resources_perms_backup.scmi_perf_perms,
918             resources_perms_ctx.agent_permissions->scmi_perf_perms,
919             resources_perms_ctx.agent_count *
920                 resources_perms_ctx.config->perf_cmd_count *
921                 resources_perms_ctx.config->perf_resource_count *
922                 sizeof(mod_res_perms_t));
923     }
924 
925     for (message_idx = (int32_t)MOD_SCMI_PERF_DOMAIN_ATTRIBUTES;
926          message_idx <= MOD_SCMI_PERF_DESCRIBE_FAST_CHANNEL;
927          message_idx++) {
928         status = set_agent_resource_message_perms(
929             agent_id,
930             MOD_SCMI_PROTOCOL_ID_PERF,
931             (uint32_t)message_idx,
932             resource_id,
933             resources_perms_ctx.agent_permissions->scmi_perf_perms,
934             flags);
935 
936         if (status != FWK_SUCCESS) {
937             return status;
938         }
939     }
940 
941     return FWK_SUCCESS;
942 }
943 
set_agent_resource_clock_permissions(uint32_t agent_id,uint32_t resource_id,enum mod_res_perms_permissions flags)944 static int set_agent_resource_clock_permissions(
945     uint32_t agent_id,
946     uint32_t resource_id,
947     enum mod_res_perms_permissions flags)
948 {
949     int status;
950     int32_t message_idx;
951 
952     if (resources_perms_ctx.agent_permissions->scmi_clock_perms == NULL) {
953         return FWK_SUCCESS;
954     }
955     if (resource_id >= resources_perms_ctx.clock_count) {
956         return FWK_E_ACCESS;
957     }
958 
959     /* Do a backup before making the changes if required */
960     if ((resources_perms_ctx.config->clock_cmd_count != 0) &&
961         (resources_perms_ctx.config->clock_resource_count != 0) &&
962         (resources_perms_backup.scmi_clock_perms == NULL)) {
963         resources_perms_backup.scmi_clock_perms =
964             (mod_res_perms_t *)fwk_mm_alloc(
965                 resources_perms_ctx.agent_count *
966                     resources_perms_ctx.config->clock_cmd_count *
967                     resources_perms_ctx.config->clock_resource_count,
968                 sizeof(mod_res_perms_t));
969         fwk_str_memcpy(
970             resources_perms_backup.scmi_clock_perms,
971             resources_perms_ctx.agent_permissions->scmi_clock_perms,
972             resources_perms_ctx.agent_count *
973                 resources_perms_ctx.config->clock_cmd_count *
974                 resources_perms_ctx.config->clock_resource_count *
975                 sizeof(mod_res_perms_t));
976     }
977 
978     for (message_idx = (int32_t)MOD_SCMI_CLOCK_ATTRIBUTES;
979          message_idx <= MOD_SCMI_CLOCK_CONFIG_SET;
980          message_idx++) {
981         status = set_agent_resource_message_perms(
982             agent_id,
983             MOD_SCMI_PROTOCOL_ID_CLOCK,
984             (uint32_t)message_idx,
985             resource_id,
986             resources_perms_ctx.agent_permissions->scmi_clock_perms,
987             flags);
988 
989         if (status != FWK_SUCCESS) {
990             return status;
991         }
992     }
993 
994     return FWK_SUCCESS;
995 }
996 
997 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
998 
set_agent_resource_reset_permissions(uint32_t agent_id,uint32_t resource_id,enum mod_res_perms_permissions flags)999 static int set_agent_resource_reset_permissions(
1000     uint32_t agent_id,
1001     uint32_t resource_id,
1002     enum mod_res_perms_permissions flags)
1003 {
1004     int status;
1005     int32_t message_idx;
1006 
1007     if (resources_perms_ctx.agent_permissions->scmi_reset_domain_perms ==
1008         NULL) {
1009         return FWK_SUCCESS;
1010     }
1011     if (resource_id >= resources_perms_ctx.reset_domain_count) {
1012         return FWK_E_ACCESS;
1013     }
1014 
1015     /* Do a backup before making the changes if required */
1016     if ((resources_perms_ctx.config->reset_domain_cmd_count != 0) &&
1017         (resources_perms_ctx.config->reset_domain_resource_count != 0) &&
1018         (resources_perms_backup.scmi_reset_domain_perms == NULL)) {
1019         resources_perms_backup.scmi_reset_domain_perms =
1020             (mod_res_perms_t *)fwk_mm_alloc(
1021                 resources_perms_ctx.agent_count *
1022                     resources_perms_ctx.config->reset_domain_cmd_count *
1023                     resources_perms_ctx.config->reset_domain_resource_count,
1024                 sizeof(mod_res_perms_t));
1025         fwk_str_memcpy(
1026             resources_perms_backup.scmi_reset_domain_perms,
1027             resources_perms_ctx.agent_permissions->scmi_reset_domain_perms,
1028             resources_perms_ctx.agent_count *
1029                 resources_perms_ctx.config->reset_domain_cmd_count *
1030                 resources_perms_ctx.config->reset_domain_cmd_count *
1031                 sizeof(mod_res_perms_t));
1032     }
1033 
1034     for (message_idx = MOD_SCMI_RESET_DOMAIN_ATTRIBUTES;
1035          message_idx <= MOD_SCMI_RESET_NOTIFY;
1036          message_idx++) {
1037         status = set_agent_resource_message_perms(
1038             agent_id,
1039             MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
1040             message_idx,
1041             resource_id,
1042             resources_perms_ctx.agent_permissions->scmi_reset_domain_perms,
1043             flags);
1044 
1045         if (status != FWK_SUCCESS) {
1046             return status;
1047         }
1048     }
1049 
1050     return FWK_SUCCESS;
1051 }
1052 
1053 #endif
1054 
set_agent_resource_voltd_permissions(uint32_t agent_id,uint32_t resource_id,enum mod_res_perms_permissions flags)1055 static int set_agent_resource_voltd_permissions(
1056     uint32_t agent_id,
1057     uint32_t resource_id,
1058     enum mod_res_perms_permissions flags)
1059 {
1060     int status;
1061     int32_t message_idx;
1062 
1063     if (resources_perms_ctx.agent_permissions->scmi_voltd_perms == NULL) {
1064         return FWK_SUCCESS;
1065     }
1066     if (resource_id >= resources_perms_ctx.voltd_count) {
1067         return FWK_E_ACCESS;
1068     }
1069 
1070     /* Do a backup before making the changes if required */
1071     if ((resources_perms_ctx.config->voltd_cmd_count != 0) &&
1072         (resources_perms_ctx.config->voltd_resource_count != 0) &&
1073         (resources_perms_backup.scmi_voltd_perms == NULL)) {
1074         resources_perms_backup.scmi_voltd_perms =
1075             (mod_res_perms_t *)fwk_mm_alloc(
1076                 resources_perms_ctx.agent_count *
1077                     resources_perms_ctx.config->voltd_cmd_count *
1078                     resources_perms_ctx.config->voltd_resource_count,
1079                 sizeof(mod_res_perms_t));
1080         fwk_str_memcpy(
1081             resources_perms_backup.scmi_voltd_perms,
1082             resources_perms_ctx.agent_permissions->scmi_voltd_perms,
1083             resources_perms_ctx.agent_count *
1084                 resources_perms_ctx.config->voltd_cmd_count *
1085                 resources_perms_ctx.config->voltd_resource_count *
1086                 sizeof(mod_res_perms_t));
1087     }
1088 
1089     for (message_idx = (int32_t)MOD_SCMI_VOLTD_DOMAIN_ATTRIBUTES;
1090          message_idx <= MOD_SCMI_VOLTD_LEVEL_GET;
1091          message_idx++) {
1092         status = set_agent_resource_message_perms(
1093             agent_id,
1094             MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
1095             (uint32_t)message_idx,
1096             resource_id,
1097             resources_perms_ctx.agent_permissions->scmi_voltd_perms,
1098             flags);
1099 
1100         if (status != FWK_SUCCESS) {
1101             return status;
1102         }
1103     }
1104 
1105     return FWK_SUCCESS;
1106 }
1107 
set_agent_resource_sensor_permissions(uint32_t agent_id,uint32_t resource_id,enum mod_res_perms_permissions flags)1108 static int set_agent_resource_sensor_permissions(
1109     uint32_t agent_id,
1110     uint32_t resource_id,
1111     enum mod_res_perms_permissions flags)
1112 {
1113     int status;
1114     int32_t message_idx;
1115 
1116     if (resources_perms_ctx.agent_permissions->scmi_sensor_perms == NULL) {
1117         return FWK_SUCCESS;
1118     }
1119     if (resource_id >= resources_perms_ctx.sensor_count) {
1120         return FWK_E_ACCESS;
1121     }
1122 
1123     /* Do a backup before making the changes if required */
1124     if ((resources_perms_ctx.config->sensor_cmd_count != 0) &&
1125         (resources_perms_ctx.config->sensor_resource_count != 0) &&
1126         (resources_perms_backup.scmi_sensor_perms == NULL)) {
1127         resources_perms_backup.scmi_sensor_perms =
1128             (mod_res_perms_t *)fwk_mm_alloc(
1129                 resources_perms_ctx.agent_count *
1130                     resources_perms_ctx.config->sensor_cmd_count *
1131                     resources_perms_ctx.config->sensor_resource_count,
1132                 sizeof(mod_res_perms_t));
1133         fwk_str_memcpy(
1134             resources_perms_backup.scmi_sensor_perms,
1135             resources_perms_ctx.agent_permissions->scmi_sensor_perms,
1136             resources_perms_ctx.agent_count *
1137                 resources_perms_ctx.config->sensor_cmd_count *
1138                 resources_perms_ctx.config->sensor_resource_count *
1139                 sizeof(mod_res_perms_t));
1140     }
1141 
1142     for (message_idx = (int32_t)MOD_SCMI_SENSOR_DESCRIPTION_GET;
1143          message_idx <= MOD_SCMI_SENSOR_READING_GET;
1144          message_idx++) {
1145         status = set_agent_resource_message_perms(
1146             agent_id,
1147             MOD_SCMI_PROTOCOL_ID_SENSOR,
1148             (uint32_t)message_idx,
1149             resource_id,
1150             resources_perms_ctx.agent_permissions->scmi_sensor_perms,
1151             flags);
1152 
1153         if (status != FWK_SUCCESS) {
1154             return status;
1155         }
1156     }
1157 
1158     return FWK_SUCCESS;
1159 }
1160 
mod_res_agent_set_permissions(enum mod_res_domain_device_types type,uint32_t agent_id,uint32_t resource_id,enum mod_res_perms_permissions flags)1161 static int mod_res_agent_set_permissions(
1162     enum mod_res_domain_device_types type,
1163     uint32_t agent_id,
1164     uint32_t resource_id,
1165     enum mod_res_perms_permissions flags)
1166 {
1167     int status;
1168 
1169     switch (type) {
1170     case MOD_RES_POWER_DOMAIN_DEVICE:
1171         status =
1172             set_agent_resource_pd_permissions(agent_id, resource_id, flags);
1173         break;
1174 
1175     case MOD_RES_PERF_DOMAIN_DEVICE:
1176         status =
1177             set_agent_resource_perf_permissions(agent_id, resource_id, flags);
1178         break;
1179 
1180     case MOD_RES_CLOCK_DOMAIN_DEVICE:
1181         status =
1182             set_agent_resource_clock_permissions(agent_id, resource_id, flags);
1183         break;
1184 
1185     case MOD_RES_SENSOR_DOMAIN_DEVICE:
1186         status =
1187             set_agent_resource_sensor_permissions(agent_id, resource_id, flags);
1188         break;
1189 
1190 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
1191     case MOD_RES_RESET_DOMAIN_DEVICE:
1192         status =
1193             set_agent_resource_reset_permissions(agent_id, resource_id, flags);
1194         break;
1195 #endif
1196 
1197     case MOD_RES_VOLTAGE_DOMAIN_DEVICE:
1198         status =
1199             set_agent_resource_voltd_permissions(agent_id, resource_id, flags);
1200         break;
1201 
1202     default:
1203         status = FWK_E_ACCESS;
1204         break;
1205     }
1206 
1207     if (status != FWK_SUCCESS) {
1208         FWK_LOG_WARN(
1209             "[perms] set_permissions for agent %d type %d device %d failed\n",
1210             (int)agent_id,
1211             (int)type,
1212             (int)resource_id);
1213     }
1214 
1215     return status;
1216 }
1217 
mod_res_agent_set_device_permission(uint32_t agent_id,uint32_t device_id,uint32_t flags)1218 static int mod_res_agent_set_device_permission(
1219     uint32_t agent_id,
1220     uint32_t device_id,
1221     uint32_t flags)
1222 {
1223     struct mod_res_domain_device *dev;
1224     uint32_t resource_id;
1225     int status;
1226     uint32_t i;
1227 
1228     /* No device permissons */
1229     if ((resources_perms_ctx.device_count == 0) ||
1230         (resources_perms_ctx.domain_devices == NULL)) {
1231         return FWK_E_ACCESS;
1232     }
1233 
1234     if (device_id >= resources_perms_ctx.device_count) {
1235         return FWK_E_PARAM;
1236     }
1237 
1238     if ((flags != 0) && (flags != 1)) {
1239         return FWK_E_PARAM;
1240     }
1241 
1242     /* Find device */
1243     for (i = 0; i < resources_perms_ctx.device_count; i++) {
1244         if (resources_perms_ctx.domain_devices[i].device_id == device_id) {
1245             break;
1246         }
1247     }
1248 
1249     if (i == resources_perms_ctx.device_count) {
1250         return FWK_E_ACCESS;
1251     }
1252 
1253     dev = resources_perms_ctx.domain_devices[i].domain_devices;
1254     while (dev->type != MOD_RES_DOMAIN_DEVICE_INVALID) {
1255         if (fwk_id_is_equal(dev->device_id, FWK_ID_NONE)) {
1256             return FWK_SUCCESS;
1257         }
1258 
1259         resource_id = fwk_id_get_element_idx(dev->device_id);
1260 
1261         status = mod_res_agent_set_permissions(
1262             dev->type,
1263             agent_id,
1264             resource_id,
1265             (enum mod_res_perms_permissions)flags);
1266 
1267         if (status != FWK_SUCCESS) {
1268             FWK_LOG_WARN(
1269                 "[perms] set_permissions for agent %d device %d failed\n",
1270                 (int)agent_id,
1271                 (int)i);
1272         }
1273 
1274         /* next domain device */
1275         dev++;
1276     };
1277 
1278     return FWK_SUCCESS;
1279 }
1280 
1281 /*
1282  * Set the permissions for an agent:device:protocol.
1283  */
mod_res_agent_set_device_protocol_permission(uint32_t agent_id,uint32_t device_id,uint32_t protocol_id,uint32_t flags)1284 static int mod_res_agent_set_device_protocol_permission(
1285     uint32_t agent_id,
1286     uint32_t device_id,
1287     uint32_t protocol_id,
1288     uint32_t flags)
1289 {
1290     enum mod_res_domain_device_types dev_type;
1291     struct mod_res_domain_device *dev;
1292     uint32_t resource_id;
1293     int status;
1294     uint32_t i;
1295 
1296     /* No device permissons */
1297     if ((resources_perms_ctx.device_count == 0) ||
1298         (resources_perms_ctx.domain_devices == NULL)) {
1299         return FWK_E_ACCESS;
1300     }
1301 
1302     if (device_id >= resources_perms_ctx.device_count) {
1303         return FWK_E_PARAM;
1304     }
1305 
1306     if ((flags != 0) && (flags != 1)) {
1307         return FWK_E_PARAM;
1308     }
1309 
1310     /* Find device */
1311     for (i = 0; i < resources_perms_ctx.device_count; i++) {
1312         if (resources_perms_ctx.domain_devices[i].device_id == device_id) {
1313             break;
1314         }
1315     }
1316 
1317     if (i == resources_perms_ctx.device_count) {
1318         return FWK_E_ACCESS;
1319     }
1320 
1321     switch (protocol_id) {
1322     case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN:
1323         dev_type = MOD_RES_POWER_DOMAIN_DEVICE;
1324         break;
1325     case MOD_SCMI_PROTOCOL_ID_PERF:
1326         dev_type = MOD_RES_PERF_DOMAIN_DEVICE;
1327         break;
1328     case MOD_SCMI_PROTOCOL_ID_CLOCK:
1329         dev_type = MOD_RES_CLOCK_DOMAIN_DEVICE;
1330         break;
1331     case MOD_SCMI_PROTOCOL_ID_SENSOR:
1332         dev_type = MOD_RES_SENSOR_DOMAIN_DEVICE;
1333         break;
1334     case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN:
1335         dev_type = MOD_RES_RESET_DOMAIN_DEVICE;
1336         break;
1337     case MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
1338         dev_type = MOD_RES_VOLTAGE_DOMAIN_DEVICE;
1339         break;
1340     case MOD_SCMI_PROTOCOL_ID_BASE:
1341     case MOD_SCMI_PROTOCOL_ID_SYS_POWER:
1342     default:
1343         return FWK_E_ACCESS;
1344     }
1345 
1346     dev = resources_perms_ctx.domain_devices[i].domain_devices;
1347     while (dev->type != MOD_RES_DOMAIN_DEVICE_INVALID) {
1348         if (fwk_id_is_equal(dev->device_id, FWK_ID_NONE)) {
1349             return FWK_SUCCESS;
1350         }
1351 
1352         if (dev->type != dev_type) {
1353             dev++;
1354             continue;
1355         }
1356 
1357         resource_id = fwk_id_get_element_idx(dev->device_id);
1358 
1359         status = mod_res_agent_set_permissions(
1360             dev->type,
1361             agent_id,
1362             resource_id,
1363             (enum mod_res_perms_permissions)flags);
1364 
1365         if (status != FWK_SUCCESS) {
1366             FWK_LOG_WARN(
1367                 "[perms] set_permissions for agent %d device %d failed\n",
1368                 (int)agent_id,
1369                 (int)i);
1370         }
1371 
1372         /* next domain device */
1373         dev++;
1374     };
1375 
1376     return FWK_SUCCESS;
1377 }
1378 
1379 /*
1380  * Reset the permissions for an agent to the default configuration.
1381  * Note that we only save and restore the permissions for protocols
1382  * which have set <protocol>_cmd_count and <protocol>_resource_count
1383  * in the platform config data. Also, the backup copies of the
1384  * permissions are not cleared after they are restored, the backup may
1385  * be re-used for any future reset requests.
1386  */
mod_res_agent_copy_config(uint32_t agent_id,mod_res_perms_t * perms,mod_res_perms_t * backup_perms,uint32_t protocol_id)1387 static void mod_res_agent_copy_config(
1388     uint32_t agent_id,
1389     mod_res_perms_t *perms,
1390     mod_res_perms_t *backup_perms,
1391     uint32_t protocol_id)
1392 {
1393     int cmd_count;
1394     int resource_count;
1395     int32_t resource_idx;
1396     int i, j;
1397     int status;
1398 
1399     switch (protocol_id) {
1400     case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN:
1401         cmd_count = (int)MOD_SCMI_PD_POWER_COMMAND_COUNT;
1402         resource_count = (int)resources_perms_ctx.config->pd_resource_count;
1403         break;
1404     case MOD_SCMI_PROTOCOL_ID_PERF:
1405         cmd_count = (int)MOD_SCMI_PERF_COMMAND_COUNT;
1406         resource_count = (int)resources_perms_ctx.config->perf_resource_count;
1407         break;
1408     case MOD_SCMI_PROTOCOL_ID_CLOCK:
1409         cmd_count = (int)MOD_SCMI_CLOCK_COMMAND_COUNT;
1410         resource_count = (int)resources_perms_ctx.config->clock_resource_count;
1411         break;
1412     case MOD_SCMI_PROTOCOL_ID_SENSOR:
1413         cmd_count = (int)MOD_SCMI_SENSOR_COMMAND_COUNT;
1414         resource_count = (int)resources_perms_ctx.config->sensor_resource_count;
1415         break;
1416 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
1417     case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN:
1418         cmd_count = (int)MOD_SCMI_RESET_COMMAND_COUNT;
1419         resource_count =
1420             (int)resources_perms_ctx.config->reset_domain_resource_count;
1421         break;
1422 #endif
1423     case MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
1424         cmd_count = (int)MOD_SCMI_VOLTD_COMMAND_COUNT;
1425         resource_count = (int)resources_perms_ctx.config->voltd_resource_count;
1426         break;
1427     default:
1428         return;
1429     }
1430 
1431     for (i = 3; i < cmd_count; i++) { /* commands < 3 are excluded */
1432         for (j = 0; j < resource_count; j++) {
1433             status = mod_res_resource_id_to_index(
1434                 agent_id,
1435                 protocol_id,
1436                 (uint32_t)i, /* message id */
1437                 (uint32_t)j, /* resource id */
1438                 &resource_idx);
1439             if ((status != FWK_SUCCESS) || (resource_idx < 0)) {
1440                 continue;
1441             }
1442             perms[resource_idx] = backup_perms[resource_idx];
1443         }
1444     }
1445 }
1446 
mod_res_agent_reset_config(uint32_t agent_id,uint32_t flags)1447 static int mod_res_agent_reset_config(uint32_t agent_id, uint32_t flags)
1448 {
1449     /* No device permissons */
1450     if ((resources_perms_ctx.device_count == 0) ||
1451         (resources_perms_ctx.domain_devices == NULL)) {
1452         return FWK_E_ACCESS;
1453     }
1454 
1455     if (flags == 0) {
1456         return FWK_SUCCESS;
1457     }
1458 
1459     if (agent_id >= resources_perms_ctx.agent_count) {
1460         return FWK_E_ACCESS;
1461     }
1462 
1463     if (resources_perms_backup.scmi_pd_perms != NULL) {
1464         mod_res_agent_copy_config(
1465             agent_id,
1466             resources_perms_ctx.agent_permissions->scmi_pd_perms,
1467             resources_perms_backup.scmi_pd_perms,
1468             MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN);
1469     }
1470 
1471     if (resources_perms_backup.scmi_perf_perms != NULL) {
1472         mod_res_agent_copy_config(
1473             agent_id,
1474             resources_perms_ctx.agent_permissions->scmi_perf_perms,
1475             resources_perms_backup.scmi_perf_perms,
1476             MOD_SCMI_PROTOCOL_ID_PERF);
1477     }
1478 
1479     if (resources_perms_backup.scmi_clock_perms != NULL) {
1480         mod_res_agent_copy_config(
1481             agent_id,
1482             resources_perms_ctx.agent_permissions->scmi_clock_perms,
1483             resources_perms_backup.scmi_clock_perms,
1484             MOD_SCMI_PROTOCOL_ID_CLOCK);
1485     }
1486 
1487     if (resources_perms_backup.scmi_sensor_perms != NULL) {
1488         mod_res_agent_copy_config(
1489             agent_id,
1490             resources_perms_ctx.agent_permissions->scmi_sensor_perms,
1491             resources_perms_backup.scmi_sensor_perms,
1492             MOD_SCMI_PROTOCOL_ID_SENSOR);
1493     }
1494 
1495 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
1496     if (resources_perms_backup.scmi_reset_domain_perms != NULL) {
1497         mod_res_agent_copy_config(
1498             agent_id,
1499             resources_perms_ctx.agent_permissions->scmi_reset_domain_perms,
1500             resources_perms_backup.scmi_reset_domain_perms,
1501             MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN);
1502     }
1503 #endif
1504 
1505     if (resources_perms_backup.scmi_voltd_perms != NULL) {
1506         mod_res_agent_copy_config(
1507             agent_id,
1508             resources_perms_ctx.agent_permissions->scmi_voltd_perms,
1509             resources_perms_backup.scmi_voltd_perms,
1510             MOD_SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN);
1511     }
1512 
1513     return FWK_SUCCESS;
1514 }
1515 
1516 static const struct mod_res_permissions_api res_perms_api = {
1517     .agent_has_protocol_permission = agent_protocol_permissions,
1518     .agent_has_message_permission = agent_message_permissions,
1519     .agent_has_resource_permission = agent_resource_permissions,
1520     .agent_set_device_permission = mod_res_agent_set_device_permission,
1521     .agent_set_device_protocol_permission =
1522         mod_res_agent_set_device_protocol_permission,
1523     .agent_reset_config = mod_res_agent_reset_config,
1524 };
1525 
1526 /*
1527  * Module Framework support
1528  */
mod_res_perms_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)1529 static int mod_res_perms_process_bind_request(
1530     fwk_id_t source_id,
1531     fwk_id_t target_id,
1532     fwk_id_t api_id,
1533     const void **api)
1534 {
1535     /* Only allow binding to the module */
1536     if (!fwk_id_is_equal(target_id, fwk_module_id_resource_perms)) {
1537         return FWK_E_PARAM;
1538     }
1539 
1540     /* We don't do any permissions management */
1541     *api = &res_perms_api;
1542 
1543     return FWK_SUCCESS;
1544 }
1545 
mod_res_perms_resources_init(fwk_id_t module_id,unsigned int element_count,const void * data)1546 static int mod_res_perms_resources_init(
1547     fwk_id_t module_id,
1548     unsigned int element_count,
1549     const void *data)
1550 {
1551     struct mod_res_resource_perms_config *config;
1552 
1553     config = (struct mod_res_resource_perms_config *)data;
1554     if (config->agent_permissions != 0x0) {
1555         resources_perms_ctx.agent_permissions =
1556             (struct mod_res_agent_permission *)config->agent_permissions;
1557         resources_perms_ctx.agent_count = config->agent_count;
1558         resources_perms_ctx.protocol_count = config->protocol_count;
1559         resources_perms_ctx.clock_count = config->clock_count;
1560         resources_perms_ctx.sensor_count = config->sensor_count;
1561         resources_perms_ctx.pd_count = config->pd_count;
1562         resources_perms_ctx.perf_count = config->perf_count;
1563         resources_perms_ctx.device_count = config->device_count;
1564 #ifdef BUILD_HAS_MOD_SCMI_RESET_DOMAIN
1565         resources_perms_ctx.reset_domain_count = config->reset_domain_count;
1566 #endif
1567         resources_perms_ctx.voltd_count = config->voltd_count;
1568         resources_perms_ctx.domain_devices =
1569             (struct mod_res_device *)config->domain_devices;
1570     }
1571     resources_perms_ctx.config = config;
1572     return FWK_SUCCESS;
1573 }
1574 
1575 /* Module description */
1576 const struct fwk_module module_resource_perms = {
1577     .type = FWK_MODULE_TYPE_SERVICE,
1578     .init = mod_res_perms_resources_init,
1579     .process_bind_request = mod_res_perms_process_bind_request,
1580     .api_count = (unsigned int)MOD_RES_PERM_API_IDX_COUNT,
1581 };
1582