blob: 14f59bcfb3cde1fb41ecb46a66b5a9c7c86c6caf [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "legacy-boot.h"
#include <inttypes.h>
#include <lib/memalloc/pool.h>
#include <lib/memalloc/range.h>
#include <lib/zbitl/items/mem-config.h>
#include <zircon/assert.h>
#include <array>
#include <ktl/array.h>
#include <ktl/iterator.h>
#include <ktl/limits.h>
#include <ktl/span.h>
#include <phys/allocation.h>
#include <phys/main.h>
#include <phys/page-table.h>
#include <phys/symbolize.h>
#include <pretty/sizes.h>
#include <ktl/enforce.h>
extern "C" {
// TODO(fxbug.dev/79166): In the linuxboot case, the linking logic gives the
// wrong value for PHYS_LOAD_ADDRESS in the linuxboot case; work around that
// for now.
[[gnu::weak]] extern ktl::byte LINUXBOOT_LOAD_ADDRESS[];
} // extern "C"
namespace {
template <typename T>
ktl::span<const ktl::byte> AsBytes(const T& obj) {
ktl::span span{ktl::data(obj), ktl::size(obj)};
return ktl::as_bytes(span);
}
} // namespace
void LegacyBootInitMemory() {
constexpr auto as_memrange =
[](auto obj, memalloc::Type type = memalloc::Type::kLegacyBootData) -> memalloc::Range {
auto bytes = AsBytes(obj);
return {
.addr = reinterpret_cast<uint64_t>(bytes.data()),
.size = static_cast<uint64_t>(bytes.size()),
.type = type,
};
};
// TODO(fxbug.dev/79166): See LINUXBOOT_LOAD_ADDRESS comment above.
uint64_t phys_start = &LINUXBOOT_LOAD_ADDRESS ? reinterpret_cast<uint64_t>(LINUXBOOT_LOAD_ADDRESS)
: reinterpret_cast<uint64_t>(PHYS_LOAD_ADDRESS);
uint64_t phys_end = reinterpret_cast<uint64_t>(_end);
auto in_load_image = [phys_start, phys_end](auto obj) -> bool {
auto bytes = AsBytes(obj);
uint64_t start = reinterpret_cast<uint64_t>(bytes.data());
uint64_t end = start + bytes.size();
return phys_start <= start && end <= phys_end;
};
// Do not fill in the last three ranges in the array yet; we only need to
// account for them if they do not lie within the shim's load image.
memalloc::Range ranges[] = {
{
.addr = phys_start,
.size = phys_end - phys_start,
.type = memalloc::Type::kPhysKernel,
},
as_memrange(gLegacyBoot.ramdisk, memalloc::Type::kDataZbi),
{},
{},
{},
};
size_t num_ranges = 2;
if (!in_load_image(gLegacyBoot.cmdline)) {
ranges[num_ranges++] = as_memrange(gLegacyBoot.cmdline);
}
if (!in_load_image(gLegacyBoot.bootloader)) {
ranges[num_ranges++] = as_memrange(gLegacyBoot.bootloader);
}
if (!in_load_image(gLegacyBoot.mem_config)) {
ranges[num_ranges++] = as_memrange(gLegacyBoot.mem_config);
}
ktl::array all_ranges = {
memalloc::AsRanges(gLegacyBoot.mem_config),
ktl::span<memalloc::Range>({ranges}).subspan(0, num_ranges),
};
auto& pool = Allocation::GetPool();
ZX_ASSERT(pool.Init(all_ranges).is_ok());
}