1 /* 2 * Copyright (c) 2024, Intel Corporation. All rights reserved. 3 * Copyright (c) 2025, Altera Corporation. All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 /* system header files*/ 9 #include <assert.h> 10 #include <endian.h> 11 #include <string.h> 12 13 /* CRC function header */ 14 #include <common/tf_crc32.h> 15 16 /* Cadense qspi driver*/ 17 #include <qspi/cadence_qspi.h> 18 19 /* Mailbox driver*/ 20 #include <socfpga_mailbox.h> 21 22 #include <socfpga_ros.h> 23 24 #define WORD_SIZE (sizeof(uint32_t)) 25 26 static void swap_bits(char *const data, uint32_t len) 27 { 28 uint32_t x, y; 29 char tmp; 30 31 for (x = 0U; x < len; x++) { 32 tmp = 0U; 33 for (y = 0U; y < 8; y++) { 34 tmp <<= 1; 35 if (data[x] & 1) { 36 tmp |= 1; 37 } 38 data[x] >>= 1; 39 } 40 data[x] = tmp; 41 } 42 } 43 44 static uint32_t get_current_image_index(spt_table_t *spt_buf, uint32_t *const img_index) 45 { 46 if (spt_buf == NULL || img_index == NULL) { 47 return ROS_RET_INVALID; 48 } 49 50 uint32_t ret; 51 unsigned long current_image; 52 uint32_t rsu_status[RSU_STATUS_RES_SIZE]; 53 54 if (spt_buf->partitions < SPT_MIN_PARTITIONS || spt_buf->partitions > SPT_MAX_PARTITIONS) { 55 return ROS_IMAGE_PARTNUM_OVFL; 56 } 57 58 ret = mailbox_rsu_status(rsu_status, RSU_STATUS_RES_SIZE); 59 if (ret != MBOX_RET_OK) { 60 return ROS_RET_NOT_RSU_MODE; 61 } 62 63 current_image = ADDR_64(rsu_status[1], rsu_status[0]); 64 NOTICE("ROS: Current image is at 0x%08lx\n", current_image); 65 66 *img_index = 0U; 67 for (uint32_t index = 0U ; index < spt_buf->partitions; index++) { 68 if (spt_buf->partition[index].offset == current_image) { 69 *img_index = index; 70 break; 71 } 72 } 73 74 if (*img_index == 0U) { 75 return ROS_IMAGE_INDEX_ERR; 76 } 77 78 return ROS_RET_OK; 79 } 80 81 static uint32_t load_and_check_spt(spt_table_t *spt_ptr, size_t offset) 82 { 83 84 if (spt_ptr == NULL || offset == 0U) { 85 return ROS_RET_INVALID; 86 } 87 88 int ret; 89 uint32_t calc_crc; 90 static spt_table_t spt_data; 91 92 ret = cad_qspi_read(spt_ptr, offset, SPT_SIZE); 93 if (ret != 0U) { 94 return ROS_QSPI_READ_ERROR; 95 } 96 97 if (spt_ptr->magic_number != SPT_MAGIC_NUMBER) { 98 return ROS_SPT_BAD_MAGIC_NUM; 99 } 100 101 if (spt_ptr->partitions < SPT_MIN_PARTITIONS || spt_ptr->partitions > SPT_MAX_PARTITIONS) { 102 return ROS_IMAGE_PARTNUM_OVFL; 103 } 104 105 memcpy_s(&spt_data, (sizeof(spt_table_t) / WORD_SIZE), 106 spt_ptr, (SPT_SIZE / WORD_SIZE)); 107 spt_data.checksum = 0U; 108 swap_bits((char *)&spt_data, SPT_SIZE); 109 110 calc_crc = tf_crc32(0, (uint8_t *)&spt_data, SPT_SIZE); 111 if (bswap32(spt_ptr->checksum) != calc_crc) { 112 return ROS_SPT_CRC_ERROR; 113 } 114 115 NOTICE("ROS: SPT table at 0x%08lx is verified\n", offset); 116 return ROS_RET_OK; 117 } 118 119 static uint32_t get_spt(spt_table_t *spt_buf) 120 { 121 if (spt_buf == NULL) { 122 return ROS_RET_INVALID; 123 } 124 125 uint32_t ret; 126 uint32_t spt_offset[RSU_GET_SPT_RESP_SIZE]; 127 128 /* Get SPT offset from SDM via mailbox commands */ 129 ret = mailbox_rsu_get_spt_offset(spt_offset, RSU_GET_SPT_RESP_SIZE); 130 if (ret != MBOX_RET_OK) { 131 WARN("ROS: Not booted in RSU mode\n"); 132 return ROS_RET_NOT_RSU_MODE; 133 } 134 135 /* Print the SPT table addresses */ 136 VERBOSE("ROS: SPT0 0x%08lx\n", ADDR_64(spt_offset[0], spt_offset[1])); 137 VERBOSE("ROS: SPT1 0x%08lx\n", ADDR_64(spt_offset[2], spt_offset[3])); 138 139 /* Load and validate SPT1*/ 140 ret = load_and_check_spt(spt_buf, ADDR_64(spt_offset[2], spt_offset[3])); 141 if (ret != ROS_RET_OK) { 142 /* Load and validate SPT0*/ 143 ret = load_and_check_spt(spt_buf, ADDR_64(spt_offset[0], spt_offset[1])); 144 if (ret != ROS_RET_OK) { 145 WARN("Both SPT tables are unusable\n"); 146 return ret; 147 } 148 } 149 150 return ROS_RET_OK; 151 } 152 153 uint32_t ros_qspi_get_ssbl_offset(unsigned long *offset) 154 { 155 if (offset == NULL) { 156 return ROS_RET_INVALID; 157 } 158 159 uint32_t ret, img_index; 160 size_t len; 161 char ssbl_name[SPT_PARTITION_NAME_LENGTH]; 162 static spt_table_t spt; 163 164 ret = get_spt(&spt); 165 if (ret != ROS_RET_OK) { 166 return ret; 167 } 168 169 ret = get_current_image_index(&spt, &img_index); 170 if (ret != ROS_RET_OK) { 171 return ret; 172 } 173 174 if (strncmp(spt.partition[img_index].name, FACTORY_IMAGE, 175 SPT_PARTITION_NAME_LENGTH) == 0U) { 176 strcpy_secure(ssbl_name, SPT_PARTITION_NAME_LENGTH, FACTORY_SSBL); 177 } else { 178 strcpy_secure(ssbl_name, SPT_PARTITION_NAME_LENGTH, SSBL_PREFIX); 179 len = strnlen_secure(ssbl_name, SPT_PARTITION_NAME_LENGTH); 180 strcpy_secure(ssbl_name + len, SPT_PARTITION_NAME_LENGTH - len, 181 spt.partition[img_index].name); 182 } 183 184 for (uint32_t index = 0U; index < spt.partitions; index++) { 185 if (strncmp(spt.partition[index].name, ssbl_name, 186 SPT_PARTITION_NAME_LENGTH) == 0U) { 187 *offset = spt.partition[index].offset; 188 NOTICE("ROS: Corresponding SSBL is at 0x%08lx\n", *offset); 189 return ROS_RET_OK; 190 } 191 } 192 193 return ROS_IMAGE_INDEX_ERR; 194 } 195