1 /*
2  * Copyright 2022 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include "hf/boot_info.h"
10 
11 #include "hf/arch/mm.h"
12 
13 #include "hf/assert.h"
14 #include "hf/dlog.h"
15 #include "hf/ffa.h"
16 #include "hf/memiter.h"
17 #include "hf/mm.h"
18 #include "hf/std.h"
19 
20 #include "vmapi/hf/ffa.h"
21 
22 /**
23  * Initializes the ffa_boot_info_header in accordance to the specification.
24  */
ffa_boot_info_header_init(struct ffa_boot_info_header * header,size_t blob_size,enum ffa_version vm_ffa_version)25 static void ffa_boot_info_header_init(struct ffa_boot_info_header *header,
26 				      size_t blob_size,
27 				      enum ffa_version vm_ffa_version)
28 {
29 	assert(header != NULL);
30 	assert(blob_size != 0U);
31 
32 	header->signature = FFA_BOOT_INFO_SIG;
33 	header->version = vm_ffa_version;
34 	header->info_blob_size = blob_size;
35 	header->desc_size = sizeof(struct ffa_boot_info_desc);
36 	header->desc_count = 0;
37 	header->desc_offset =
38 		(uint32_t)offsetof(struct ffa_boot_info_header, boot_info);
39 	header->reserved = 0U;
40 }
41 
ffa_boot_info_desc_init(struct ffa_boot_info_desc * info_desc,uint8_t content_format,bool std_type,uint8_t type_id,uint32_t size,uint64_t content)42 static void ffa_boot_info_desc_init(struct ffa_boot_info_desc *info_desc,
43 				    uint8_t content_format, bool std_type,
44 				    uint8_t type_id, uint32_t size,
45 				    uint64_t content)
46 {
47 	assert(info_desc != NULL);
48 
49 	/*
50 	 * Init name size with 0s, as it is currently unused. Data can be
51 	 * identified checking the type field.
52 	 */
53 	memset_s(info_desc, FFA_BOOT_INFO_NAME_LEN, 0, FFA_BOOT_INFO_NAME_LEN);
54 
55 	info_desc->type =
56 		std_type ? FFA_BOOT_INFO_TYPE_STD : FFA_BOOT_INFO_TYPE_IMPDEF;
57 	info_desc->type <<= FFA_BOOT_INFO_TYPE_SHIFT;
58 	info_desc->type |= (type_id & FFA_BOOT_INFO_TYPE_ID_MASK);
59 
60 	info_desc->reserved = 0U;
61 	info_desc->flags =
62 		((content_format << FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT) &
63 		 FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_MASK);
64 	info_desc->size = size;
65 	info_desc->content = content;
66 }
67 
68 /*
69  * Write initialization parameter to the boot info descriptor array.
70  */
boot_info_write_desc(struct ffa_boot_info_header * header,uint8_t content_format,bool std_type,uint8_t type_id,uint32_t size,uint64_t content,const size_t max_info_desc_count)71 static void boot_info_write_desc(struct ffa_boot_info_header *header,
72 				 uint8_t content_format, bool std_type,
73 				 uint8_t type_id, uint32_t size,
74 				 uint64_t content,
75 				 const size_t max_info_desc_count)
76 {
77 	assert(header != NULL);
78 
79 	/* Check that writing the data won't surpass the blob memory limit. */
80 	if (header->desc_count >= max_info_desc_count) {
81 		dlog_error(
82 			"Boot info memory is full. No space for a "
83 			"descriptor.\n");
84 		return;
85 	}
86 
87 	ffa_boot_info_desc_init(&header->boot_info[header->desc_count],
88 				content_format, std_type, type_id, size,
89 				content);
90 
91 	header->desc_count++;
92 }
93 
94 /**
95  * Looks for the FF-A manifest boot information node, and writes the
96  * requested information into the boot info memory.
97  */
ffa_boot_info_node(struct fdt_node * boot_info_node,struct partition_pkg * pkg,enum ffa_version vm_ffa_version)98 bool ffa_boot_info_node(struct fdt_node *boot_info_node,
99 			struct partition_pkg *pkg,
100 			enum ffa_version vm_ffa_version)
101 {
102 	struct memiter data;
103 	struct ffa_boot_info_header *boot_info_header;
104 	const size_t boot_info_size =
105 		pa_difference(pkg->boot_info.begin, pkg->boot_info.end);
106 	const size_t max_boot_info_desc_count =
107 		(boot_info_size -
108 		 offsetof(struct ffa_boot_info_header, boot_info)) /
109 		sizeof(struct ffa_boot_info_desc);
110 	bool ret = false;
111 
112 	assert(boot_info_node != NULL);
113 	assert(pkg != NULL);
114 
115 	boot_info_header = (struct ffa_boot_info_header *)ptr_from_va(
116 		va_from_pa(pkg->boot_info.begin));
117 
118 	assert(boot_info_header != NULL);
119 
120 	/*
121 	 * FF-A v1.1 EAC0 specification states the region for the boot info
122 	 * descriptors, and the contents of the boot info shall be contiguous.
123 	 * Together they constitute the boot info blob. The are for the boot
124 	 * info blob is allocated in the SP's respective package.
125 	 * Retrieve from the SP package the size of the region for the boot info
126 	 * descriptors. The size of boot info contents to be incremented,
127 	 * depending on the info specified in the partition's FF-A manifest.
128 	 */
129 	ffa_boot_info_header_init(boot_info_header, boot_info_size,
130 				  vm_ffa_version);
131 
132 	if (!fdt_is_compatible(boot_info_node, "arm,ffa-manifest-boot-info")) {
133 		dlog_verbose("The node 'boot-info' is not compatible.\n");
134 		return false;
135 	}
136 
137 	dlog_verbose("  FF-A Boot Info: base %lx\n",
138 		     (uintptr_t)ptr_from_va(va_from_pa(pkg->boot_info.begin)));
139 
140 	if (fdt_read_property(boot_info_node, "ffa_manifest", &data) &&
141 	    memiter_size(&data) == 0U) {
142 		ipaddr_t manifest_address = ipa_from_pa(pkg->pm.begin);
143 		const uint32_t pm_size =
144 			pa_difference(pkg->pm.begin, pkg->pm.end);
145 
146 		dlog_verbose("    FF-A Manifest: %lx\n",
147 			     ipa_addr(manifest_address));
148 		boot_info_write_desc(boot_info_header,
149 				     FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR,
150 				     true, FFA_BOOT_INFO_TYPE_ID_FDT, pm_size,
151 				     ipa_addr(manifest_address),
152 				     max_boot_info_desc_count);
153 
154 		/*
155 		 * Incrementing the size of the boot information blob with the
156 		 * size of the partition's manifest.
157 		 */
158 		boot_info_header->info_blob_size += pm_size;
159 
160 		ret = true;
161 	}
162 
163 	if (fdt_read_property(boot_info_node, "hob_list", &data) &&
164 	    memiter_size(&data) == 0U) {
165 		ipaddr_t hob_address = ipa_from_pa(pkg->hob.begin);
166 		const uint32_t hob_size =
167 			pa_difference(pkg->hob.begin, pkg->hob.end);
168 
169 		dlog_verbose("    Hob List: %lx, size: %x\n",
170 			     ipa_addr(hob_address), hob_size);
171 		boot_info_write_desc(boot_info_header,
172 				     FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR,
173 				     true, FFA_BOOT_INFO_TYPE_ID_HOB, hob_size,
174 				     ipa_addr(hob_address),
175 				     max_boot_info_desc_count);
176 
177 		/*
178 		 * Incrementing the size of the boot information blob with the
179 		 * size of the partition's manifest.
180 		 */
181 		boot_info_header->info_blob_size += hob_size;
182 
183 		ret = true;
184 	}
185 
186 	if (ret) {
187 		/*
188 		 * Flush the data cache in case partition initializes with
189 		 * caches disabled.
190 		 */
191 		arch_mm_flush_dcache((void *)boot_info_header,
192 				     boot_info_header->info_blob_size);
193 	}
194 
195 	return ret;
196 }
197