blob: d6c5a4a8a00afe5a31a9d41677983dbba189fc20 [file] [log] [blame]
/*
* Copyright 2018 The Hafnium Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hf/boot_params.h"
#include "hf/dlog.h"
#include "hf/fdt_handler.h"
#include "hf/layout.h"
/**
* Default implementation assumes the FDT has been linked into the image.
*
* This can be overridden e.g. to provide a fixed address or an address passed
* by the loader.
*/
#pragma weak plat_get_fdt_addr
paddr_t plat_get_fdt_addr(void)
{
return layout_fdt_begin();
}
/**
* Default implementation assumes the initrd has been linked into the image.
*
* This can be overridden e.g. to provide a fixed address or an address passed
* by the loader.
*/
#pragma weak plat_get_initrd_range
void plat_get_initrd_range(struct mm_stage1_locked stage1_locked,
paddr_t *begin, paddr_t *end, struct mpool *ppool)
{
(void)stage1_locked;
(void)ppool;
*begin = layout_initrd_begin();
*end = layout_initrd_end();
}
/**
* Default implementation assumes the FDT address is passed to the kernel.
*
* TODO: make this part of the VM configuration as secondary VMs will also need
* to take arguments.
*/
#pragma weak plat_get_kernel_arg
uintreg_t plat_get_kernel_arg(void)
{
return (uintreg_t)pa_addr(plat_get_fdt_addr());
}
/**
* Default implementation extracts the boot parameters from the FDT but the
* initrd is provided separately.
*/
#pragma weak plat_get_boot_params
bool plat_get_boot_params(struct mm_stage1_locked stage1_locked,
struct boot_params *p, struct mpool *ppool)
{
struct fdt_header *fdt;
struct fdt_node n;
bool ret = false;
plat_get_initrd_range(stage1_locked, &p->initrd_begin, &p->initrd_end,
ppool);
p->kernel_arg = plat_get_kernel_arg();
/* Get the memory map from the FDT. */
fdt = fdt_map(stage1_locked, plat_get_fdt_addr(), &n, ppool);
if (!fdt) {
return false;
}
if (!fdt_find_child(&n, "")) {
dlog("Unable to find FDT root node.\n");
goto out_unmap_fdt;
}
fdt_find_cpus(&n, p->cpu_ids, &p->cpu_count);
p->mem_ranges_count = 0;
fdt_find_memory_ranges(&n, p);
ret = true;
out_unmap_fdt:
if (!fdt_unmap(stage1_locked, fdt, ppool)) {
dlog("Unable to unmap fdt.");
return false;
}
return ret;
}
/**
* Default implementation updates the FDT which is the argument passed to the
* primary VM's kernel.
*
* TODO: in future, each VM will declare whether it expects an argument passed
* and that will be static data e.g. it will provide its own FDT so there will
* be no FDT modification. This is done because each VM has a very different
* view of the system and we don't want to force VMs to require loader code when
* another loader can load the data for it.
*/
#pragma weak plat_update_boot_params
bool plat_update_boot_params(struct mm_stage1_locked stage1_locked,
struct boot_params_update *p, struct mpool *ppool)
{
return fdt_patch(stage1_locked, plat_get_fdt_addr(), p, ppool);
}