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