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/assert.h"
12 #include "hf/dlog.h"
13 #include "hf/ffa.h"
14 #include "hf/memiter.h"
15 #include "hf/std.h"
16 
17 #include "vmapi/hf/ffa.h"
18 
19 /**
20  * Initializes the ffa_boot_info_header in accordance to the specification.
21  */
ffa_boot_info_header_init(struct ffa_boot_info_header * header,size_t blob_size)22 static void ffa_boot_info_header_init(struct ffa_boot_info_header *header,
23 				      size_t blob_size)
24 {
25 	assert(header != NULL);
26 	assert(blob_size != 0U);
27 
28 	header->signature = FFA_BOOT_INFO_SIG;
29 	header->version = FFA_BOOT_INFO_VERSION;
30 	header->info_blob_size = blob_size;
31 	header->desc_size = sizeof(struct ffa_boot_info_desc);
32 	header->desc_count = 0;
33 	header->desc_offset =
34 		(uint32_t)offsetof(struct ffa_boot_info_header, boot_info);
35 	header->reserved = 0U;
36 }
37 
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)38 static void ffa_boot_info_desc_init(struct ffa_boot_info_desc *info_desc,
39 				    uint8_t content_format, bool std_type,
40 				    uint8_t type_id, uint32_t size,
41 				    uint64_t content)
42 {
43 	assert(info_desc != NULL);
44 
45 	/*
46 	 * Init name size with 0s, as it is currently unused. Data can be
47 	 * identified checking the type field.
48 	 */
49 	memset_s(info_desc, FFA_BOOT_INFO_NAME_LEN, 0, FFA_BOOT_INFO_NAME_LEN);
50 
51 	info_desc->type = std_type == true ? FFA_BOOT_INFO_TYPE_STD
52 					   : FFA_BOOT_INFO_TYPE_IMPDEF;
53 	info_desc->type <<= FFA_BOOT_INFO_TYPE_SHIFT;
54 	info_desc->type |= (type_id & FFA_BOOT_INFO_TYPE_ID_MASK);
55 
56 	info_desc->reserved = 0U;
57 	info_desc->flags =
58 		((content_format << FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT) &
59 		 FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_MASK);
60 	info_desc->size = size;
61 	info_desc->content = content;
62 }
63 
64 /*
65  * Write initialization parameter to the boot info descriptor array.
66  */
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)67 static void boot_info_write_desc(struct ffa_boot_info_header *header,
68 				 uint8_t content_format, bool std_type,
69 				 uint8_t type_id, uint32_t size,
70 				 uint64_t content,
71 				 const size_t max_info_desc_count)
72 {
73 	assert(header != NULL);
74 
75 	/* Check that writing the data won't surpass the blob memory limit. */
76 	if (header->desc_count >= max_info_desc_count) {
77 		dlog_error(
78 			"Boot info memory is full. No space for a "
79 			"descriptor.\n");
80 		return;
81 	}
82 
83 	ffa_boot_info_desc_init(&header->boot_info[header->desc_count],
84 				content_format, std_type, type_id, size,
85 				content);
86 
87 	header->desc_count++;
88 }
89 
90 /**
91  * Looks for the FF-A manifest boot information node, and writes the
92  * requested information into the boot info memory.
93  */
ffa_boot_info_node(struct fdt_node * boot_info_node,vaddr_t pkg_address,struct sp_pkg_header * pkg_header)94 bool ffa_boot_info_node(struct fdt_node *boot_info_node, vaddr_t pkg_address,
95 			struct sp_pkg_header *pkg_header)
96 {
97 	struct memiter data;
98 	struct ffa_boot_info_header *boot_info_header =
99 		(struct ffa_boot_info_header *)ptr_from_va(pkg_address);
100 	const size_t boot_info_size = sp_pkg_get_boot_info_size(pkg_header);
101 	const size_t max_boot_info_desc_count =
102 		(boot_info_size -
103 		 offsetof(struct ffa_boot_info_header, boot_info)) /
104 		sizeof(struct ffa_boot_info_desc);
105 
106 	assert(boot_info_node != NULL);
107 	assert(pkg_header != NULL);
108 	assert(boot_info_header != NULL);
109 
110 	/*
111 	 * FF-A v1.1 EAC0 specification states the region for the boot info
112 	 * descriptors, and the contents of the boot info shall be contiguous.
113 	 * Together they constitute the boot info blob. The are for the boot
114 	 * info blob is allocated in the SP's respective package.
115 	 * Retrieve from the SP package the size of the region for the boot info
116 	 * descriptors. The size of boot info contents to be incremented,
117 	 * depending on the info specified in the partition's FF-A manifest.
118 	 */
119 	ffa_boot_info_header_init(boot_info_header, boot_info_size);
120 
121 	if (!fdt_is_compatible(boot_info_node, "arm,ffa-manifest-boot-info")) {
122 		dlog_verbose("The node 'boot-info' is not compatible.\n");
123 		return false;
124 	}
125 
126 	dlog_verbose("  FF-A Boot Info:\n");
127 
128 	if (fdt_read_property(boot_info_node, "ffa_manifest", &data) &&
129 	    memiter_size(&data) == 0U) {
130 		ipaddr_t manifest_address = ipa_init(
131 			va_addr(va_add(pkg_address, pkg_header->pm_offset)));
132 
133 		dlog_verbose("    FF-A Manifest\n");
134 		boot_info_write_desc(
135 			boot_info_header,
136 			FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR, true,
137 			FFA_BOOT_INFO_TYPE_ID_FDT, pkg_header->pm_size,
138 			ipa_addr(manifest_address), max_boot_info_desc_count);
139 
140 		/*
141 		 * Incrementing the size of the boot information blob with the
142 		 * size of the partition's manifest.
143 		 */
144 		boot_info_header->info_blob_size += pkg_header->pm_size;
145 
146 		/*
147 		 * Flush the data cache in case partition initializes with
148 		 * caches disabled.
149 		 */
150 		arch_mm_flush_dcache((void *)boot_info_header,
151 				     boot_info_header->info_blob_size);
152 		return true;
153 	}
154 
155 	return false;
156 }
157