blob: f4046c48efa65c0bc18821c27426762b5cceb73d [file] [log] [blame]
/*
* 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;
}