blob: 093de438d3bfd32b9e6ad15819c7695248481dd1 [file] [log] [blame]
/*
* Copyright 2024 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/partition_pkg.h"
#include <stdint.h>
#include "hf/arch/std.h"
#include "hf/addr.h"
#include "hf/check.h"
#include "hf/dlog.h"
#include "hf/mm.h"
#include "hf/sp_pkg.h"
#include "hf/std.h"
#include "hf/transfer_list.h"
static void dump_partition_package(struct partition_pkg *pkg)
{
dlog_verbose("%s: total %lx %lx\n", __func__, pa_addr(pkg->total.begin),
pa_addr(pkg->total.end));
dlog_verbose("%s: pm: %lx %lx\n", __func__, pa_addr(pkg->pm.begin),
pa_addr(pkg->pm.end));
dlog_verbose("%s: img: %lx %lx\n", __func__, pa_addr(pkg->img.begin),
pa_addr(pkg->img.end));
dlog_verbose("%s: boot_info: %lx %lx\n", __func__,
pa_addr(pkg->boot_info.begin),
pa_addr(pkg->boot_info.end));
if (mem_range_is_valid(pkg->hob)) {
dlog_verbose("%s: hob %lx %lx\n", __func__,
pa_addr(pkg->hob.begin), pa_addr(pkg->hob.end));
}
}
static bool partition_pkg_from_sp_pkg(struct mm_stage1_locked stage1_locked,
paddr_t pkg_start,
struct partition_pkg *pkg,
struct mpool *ppool)
{
struct sp_pkg_header header;
bool ret = sp_pkg_init(stage1_locked, pkg_start, &header, ppool);
size_t total_mem_size = sp_pkg_get_mem_size(&header);
pkg->total.begin = pkg_start;
pkg->total.end = pa_add(pkg_start, total_mem_size);
pkg->pm.begin = pa_add(pkg_start, header.pm_offset);
pkg->pm.end = pa_add(pkg->pm.begin, header.pm_size);
pkg->img.begin = pa_add(pkg_start, header.img_offset);
pkg->img.end = pa_add(pkg->img.begin, header.img_size);
/*
* Repurpose the first page of the SP Package.
* FF-A boot info will overwrite the package, but it doesn't
* matter at this stage, given Hafnium already parsed it.
*/
pkg->boot_info.begin = pkg_start;
pkg->boot_info.end = pa_add(pkg_start, header.pm_offset);
/* HOB section doesn't exist in the SP Pkg type. */
pkg->hob.begin = pa_init(0);
pkg->hob.end = pa_init(0);
dump_partition_package(pkg);
/* Map the whole package as RO. */
CHECK(mm_identity_map(stage1_locked, pkg->total.begin, pkg->total.end,
MM_MODE_R, ppool) != NULL);
return ret;
}
bool partition_pkg_init(struct mm_stage1_locked stage1_locked,
paddr_t pkg_start, struct partition_pkg *pkg,
struct mpool *ppool)
{
bool ret = false;
paddr_t pkg_first_page = pa_add(pkg_start, PAGE_SIZE);
uint32_t *magic;
void *mapped_ptr;
/* Firstly, map a single page to be able to read package header. */
mapped_ptr = mm_identity_map(stage1_locked, pkg_start, pkg_first_page,
MM_MODE_R, ppool);
assert(mapped_ptr != NULL);
assert(pkg != NULL);
magic = (uint32_t *)mapped_ptr;
switch (*magic) {
case SP_PKG_HEADER_MAGIC:
/*
* Leave memory mapped in case it succeeded, to be cleared
* later.
*/
if (!partition_pkg_from_sp_pkg(stage1_locked, pkg_start, pkg,
ppool)) {
goto out;
}
break;
default:
dlog_error("%s: invalid secure partition package %x @ %lx\n",
__func__, *magic, (uint64_t)magic);
goto out;
}
dump_partition_package(pkg);
/**
* The total memory range should encompass the remaining.
* Assert that none of the memory ranges are out of bounds.
*/
assert(mem_range_contains_range(pkg->total, pkg->img));
assert(mem_range_contains_range(pkg->total, pkg->pm));
assert(mem_range_contains_range(pkg->total, pkg->boot_info));
assert(!mem_range_is_valid(pkg->hob) ||
mem_range_contains_range(pkg->total, pkg->hob));
/* Map Boot info section as RW. */
if (pa_addr(pkg->boot_info.begin) != 0U &&
pa_addr(pkg->boot_info.end) != 0U) {
CHECK(mm_identity_map(stage1_locked, pkg->boot_info.begin,
pkg->boot_info.end, MM_MODE_R | MM_MODE_W,
ppool) != NULL);
}
ret = true;
out:
/* If failing unmap the memory. */
if (!ret) {
CHECK(mm_unmap(stage1_locked, pkg_start, pkg_first_page,
ppool));
}
return ret;
}
void partition_pkg_deinit(struct mm_stage1_locked stage1_locked,
struct partition_pkg *pkg, struct mpool *ppool)
{
CHECK(mm_unmap(stage1_locked, pkg->total.begin, pkg->total.end, ppool));
}