| /* |
| * Copyright 2022 The Hafnium Authors. |
| * |
| * Use of this source code is governed by a BSD-style |
| * license that can be found in the LICENSE file or at |
| * https://opensource.org/licenses/BSD-3-Clause. |
| */ |
| |
| #include "hf/boot_info.h" |
| |
| #include "hf/arch/mm.h" |
| |
| #include "hf/assert.h" |
| #include "hf/dlog.h" |
| #include "hf/ffa.h" |
| #include "hf/memiter.h" |
| #include "hf/mm.h" |
| #include "hf/std.h" |
| |
| #include "vmapi/hf/ffa.h" |
| |
| /** |
| * Initializes the ffa_boot_info_header in accordance to the specification. |
| */ |
| static void ffa_boot_info_header_init(struct ffa_boot_info_header *header, |
| size_t blob_size, |
| enum ffa_version vm_ffa_version) |
| { |
| assert(header != NULL); |
| assert(blob_size != 0U); |
| |
| header->signature = FFA_BOOT_INFO_SIG; |
| header->version = vm_ffa_version; |
| header->info_blob_size = blob_size; |
| header->desc_size = sizeof(struct ffa_boot_info_desc); |
| header->desc_count = 0; |
| header->desc_offset = |
| (uint32_t)offsetof(struct ffa_boot_info_header, boot_info); |
| header->reserved = 0U; |
| } |
| |
| static void 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) |
| { |
| assert(info_desc != NULL); |
| |
| /* |
| * Init name size with 0s, as it is currently unused. Data can be |
| * identified checking the type field. |
| */ |
| memset_s(info_desc, FFA_BOOT_INFO_NAME_LEN, 0, FFA_BOOT_INFO_NAME_LEN); |
| |
| info_desc->type = |
| std_type ? FFA_BOOT_INFO_TYPE_STD : FFA_BOOT_INFO_TYPE_IMPDEF; |
| info_desc->type <<= FFA_BOOT_INFO_TYPE_SHIFT; |
| info_desc->type |= (type_id & FFA_BOOT_INFO_TYPE_ID_MASK); |
| |
| info_desc->reserved = 0U; |
| info_desc->flags = |
| ((content_format << FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT) & |
| FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_MASK); |
| info_desc->size = size; |
| info_desc->content = content; |
| } |
| |
| /* |
| * Write initialization parameter to the boot info descriptor array. |
| */ |
| static void 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) |
| { |
| assert(header != NULL); |
| |
| /* Check that writing the data won't surpass the blob memory limit. */ |
| if (header->desc_count >= max_info_desc_count) { |
| dlog_error( |
| "Boot info memory is full. No space for a " |
| "descriptor.\n"); |
| return; |
| } |
| |
| ffa_boot_info_desc_init(&header->boot_info[header->desc_count], |
| content_format, std_type, type_id, size, |
| content); |
| |
| header->desc_count++; |
| } |
| |
| /** |
| * Looks for the FF-A manifest boot information node, and writes the |
| * requested information into the boot info memory. |
| */ |
| bool ffa_boot_info_node(struct fdt_node *boot_info_node, |
| struct partition_pkg *pkg, |
| enum ffa_version vm_ffa_version) |
| { |
| struct memiter data; |
| struct ffa_boot_info_header *boot_info_header; |
| const size_t boot_info_size = |
| pa_difference(pkg->boot_info.begin, pkg->boot_info.end); |
| const size_t max_boot_info_desc_count = |
| (boot_info_size - |
| offsetof(struct ffa_boot_info_header, boot_info)) / |
| sizeof(struct ffa_boot_info_desc); |
| bool ret = false; |
| |
| assert(boot_info_node != NULL); |
| assert(pkg != NULL); |
| |
| boot_info_header = (struct ffa_boot_info_header *)ptr_from_va( |
| va_from_pa(pkg->boot_info.begin)); |
| |
| assert(boot_info_header != NULL); |
| |
| /* |
| * FF-A v1.1 EAC0 specification states the region for the boot info |
| * descriptors, and the contents of the boot info shall be contiguous. |
| * Together they constitute the boot info blob. The are for the boot |
| * info blob is allocated in the SP's respective package. |
| * Retrieve from the SP package the size of the region for the boot info |
| * descriptors. The size of boot info contents to be incremented, |
| * depending on the info specified in the partition's FF-A manifest. |
| */ |
| ffa_boot_info_header_init(boot_info_header, boot_info_size, |
| vm_ffa_version); |
| |
| if (!fdt_is_compatible(boot_info_node, "arm,ffa-manifest-boot-info")) { |
| dlog_verbose("The node 'boot-info' is not compatible.\n"); |
| return false; |
| } |
| |
| dlog_verbose(" FF-A Boot Info: base %lx\n", |
| (uintptr_t)ptr_from_va(va_from_pa(pkg->boot_info.begin))); |
| |
| if (fdt_read_property(boot_info_node, "ffa_manifest", &data) && |
| memiter_size(&data) == 0U) { |
| ipaddr_t manifest_address = ipa_from_pa(pkg->pm.begin); |
| const uint32_t pm_size = |
| pa_difference(pkg->pm.begin, pkg->pm.end); |
| |
| dlog_verbose(" FF-A Manifest: %lx\n", |
| ipa_addr(manifest_address)); |
| boot_info_write_desc(boot_info_header, |
| FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR, |
| true, FFA_BOOT_INFO_TYPE_ID_FDT, pm_size, |
| ipa_addr(manifest_address), |
| max_boot_info_desc_count); |
| |
| /* |
| * Incrementing the size of the boot information blob with the |
| * size of the partition's manifest. |
| */ |
| boot_info_header->info_blob_size += pm_size; |
| |
| ret = true; |
| } |
| |
| if (fdt_read_property(boot_info_node, "hob_list", &data) && |
| memiter_size(&data) == 0U) { |
| ipaddr_t hob_address = ipa_from_pa(pkg->hob.begin); |
| const uint32_t hob_size = |
| pa_difference(pkg->hob.begin, pkg->hob.end); |
| |
| dlog_verbose(" Hob List: %lx, size: %x\n", |
| ipa_addr(hob_address), hob_size); |
| boot_info_write_desc(boot_info_header, |
| FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR, |
| true, FFA_BOOT_INFO_TYPE_ID_HOB, hob_size, |
| ipa_addr(hob_address), |
| max_boot_info_desc_count); |
| |
| /* |
| * Incrementing the size of the boot information blob with the |
| * size of the partition's manifest. |
| */ |
| boot_info_header->info_blob_size += hob_size; |
| |
| ret = true; |
| } |
| |
| if (ret) { |
| /* |
| * Flush the data cache in case partition initializes with |
| * caches disabled. |
| */ |
| arch_mm_flush_dcache((void *)boot_info_header, |
| boot_info_header->info_blob_size); |
| } |
| |
| return ret; |
| } |