1 /* 2 * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 #include <string.h> 10 11 #include <common/debug.h> 12 #include <services/el3_spmd_logical_sp.h> 13 #include <services/ffa_svc.h> 14 15 #if ENABLE_SPMD_LP 16 static bool is_spmd_lp_inited; 17 static bool is_spmc_inited; 18 19 /* 20 * Helper function to obtain the array storing the EL3 21 * SPMD Logical Partition descriptors. 22 */ 23 static struct spmd_lp_desc *get_spmd_el3_lp_array(void) 24 { 25 return (struct spmd_lp_desc *) SPMD_LP_DESCS_START; 26 } 27 28 /******************************************************************************* 29 * Validate any logical partition descriptors before we initialize. 30 * Initialization of said partitions will be taken care of during SPMD boot. 31 ******************************************************************************/ 32 static int el3_spmd_sp_desc_validate(struct spmd_lp_desc *lp_array) 33 { 34 /* Check the array bounds are valid. */ 35 assert(SPMD_LP_DESCS_END > SPMD_LP_DESCS_START); 36 37 /* If no SPMD logical partitions are implemented then simply bail out. */ 38 if (SPMD_LP_DESCS_COUNT == 0U) { 39 return -1; 40 } 41 42 for (uint32_t index = 0U; index < SPMD_LP_DESCS_COUNT; index++) { 43 struct spmd_lp_desc *lp_desc = &lp_array[index]; 44 45 /* Validate our logical partition descriptors. */ 46 if (lp_desc == NULL) { 47 ERROR("Invalid SPMD Logical SP Descriptor\n"); 48 return -EINVAL; 49 } 50 51 /* 52 * Ensure the ID follows the convention to indicate it resides 53 * in the secure world. 54 */ 55 if (!ffa_is_secure_world_id(lp_desc->sp_id)) { 56 ERROR("Invalid SPMD Logical SP ID (0x%x)\n", 57 lp_desc->sp_id); 58 return -EINVAL; 59 } 60 61 /* Ensure SPMD logical partition is in valid range. */ 62 if (!is_spmd_lp_id(lp_desc->sp_id)) { 63 ERROR("Invalid SPMD Logical Partition ID (0x%x)\n", 64 lp_desc->sp_id); 65 return -EINVAL; 66 } 67 68 /* Ensure the UUID is not the NULL UUID. */ 69 if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 && 70 lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) { 71 ERROR("Invalid UUID for SPMD Logical SP (0x%x)\n", 72 lp_desc->sp_id); 73 return -EINVAL; 74 } 75 76 /* Ensure init function callback is registered. */ 77 if (lp_desc->init == NULL) { 78 ERROR("Missing init function for Logical SP(0x%x)\n", 79 lp_desc->sp_id); 80 return -EINVAL; 81 } 82 83 /* Ensure that SPMD LP only supports sending direct requests. */ 84 if (lp_desc->properties != FFA_PARTITION_DIRECT_REQ_SEND) { 85 ERROR("Invalid SPMD logical partition properties (0x%x)\n", 86 lp_desc->properties); 87 return -EINVAL; 88 } 89 90 /* Ensure that all partition IDs are unique. */ 91 for (uint32_t inner_idx = index + 1; 92 inner_idx < SPMD_LP_DESCS_COUNT; inner_idx++) { 93 if (lp_desc->sp_id == lp_array[inner_idx].sp_id) { 94 ERROR("Duplicate SPMD logical SP ID Detected (0x%x)\n", 95 lp_desc->sp_id); 96 return -EINVAL; 97 } 98 } 99 } 100 return 0; 101 } 102 #endif 103 104 /* 105 * Initialize SPMD logical partitions. This function assumes that it is called 106 * only after the SPMC has successfully initialized. 107 */ 108 int32_t spmd_logical_sp_init(void) 109 { 110 #if ENABLE_SPMD_LP 111 int32_t rc = 0; 112 struct spmd_lp_desc *spmd_lp_descs; 113 114 if (is_spmd_lp_inited == true) { 115 return 0; 116 } 117 118 if (is_spmc_inited == false) { 119 return -1; 120 } 121 122 spmd_lp_descs = get_spmd_el3_lp_array(); 123 124 /* Perform initial validation of the SPMD Logical Partitions. */ 125 rc = el3_spmd_sp_desc_validate(spmd_lp_descs); 126 if (rc != 0) { 127 ERROR("Logical SPMD Partition validation failed!\n"); 128 return rc; 129 } 130 131 VERBOSE("SPMD Logical Secure Partition init start.\n"); 132 for (unsigned int i = 0U; i < SPMD_LP_DESCS_COUNT; i++) { 133 rc = spmd_lp_descs[i].init(); 134 if (rc != 0) { 135 ERROR("SPMD Logical SP (0x%x) failed to initialize\n", 136 spmd_lp_descs[i].sp_id); 137 return rc; 138 } 139 VERBOSE("SPMD Logical SP (0x%x) Initialized\n", 140 spmd_lp_descs[i].sp_id); 141 } 142 143 INFO("SPMD Logical Secure Partition init completed.\n"); 144 if (rc == 0) { 145 is_spmd_lp_inited = true; 146 } 147 return rc; 148 #else 149 return 0; 150 #endif 151 } 152 153 void spmd_logical_sp_set_spmc_initialized(void) 154 { 155 #if ENABLE_SPMD_LP 156 is_spmc_inited = true; 157 #endif 158 } 159 160 void spmd_logical_sp_set_spmc_failure(void) 161 { 162 #if ENABLE_SPMD_LP 163 is_spmc_inited = false; 164 #endif 165 } 166