blob: 79e96f274b4092e7b74f8f7ceb871ce8273cef5f [file] [log] [blame] [edit]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "../mem_config.h"
#include <lib/zbitl/error_string.h>
#include <lib/zbitl/image.h>
#include <lib/zbitl/items/mem_config.h>
#include <lib/zbitl/memory.h>
#include <lib/zbitl/storage_traits.h>
#include <lib/zbitl/view.h>
#include <zircon/boot/e820.h>
#include <zircon/boot/image.h>
#include <efi/boot-services.h>
#include <efi/runtime-services.h>
#include <fbl/array.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
// GMock matcher to determine if a given zbitl::View result was successful,
// printing the error if not.
//
// Can be used as: EXPECT_THAT(view.operation(), IsOk());
MATCHER(IsOk, "") {
if (arg.is_ok()) {
return true;
}
*result_listener << "had error: " << zbitl::ViewErrorString(arg.error_value());
return false;
}
// As above, but also matches against the value:
//
// EXPECT_THAT(view.operation(), IsOkAndHolds(Eq(3u)));
template <typename X>
auto IsOkAndHolds(X matcher) {
return ::testing::AllOf(
IsOk(), ::testing::ResultOf([](const auto& val) { return val.value(); }, matcher));
}
using ZbiMemoryImage = zbitl::Image<fbl::Array<std::byte>>;
// Create an empty zbitl::Image that can be written to.
ZbiMemoryImage CreateImage() {
ZbiMemoryImage image;
// Initialise the ZBI header
auto result = image.clear();
ZX_ASSERT(result.is_ok());
return image;
}
// Return a zbitl::View of the given ZbiMemoryImage.
zbitl::View<zbitl::ByteView> AsView(const ZbiMemoryImage& image) {
return zbitl::View(zbitl::ByteView(image.storage().data(), image.storage().size()));
}
// Append the given payload to a zbitl::Image.
//
// Abort on error.
void AppendPayload(ZbiMemoryImage& zbi, uint32_t type, zbitl::ByteView bytes) {
auto result = zbi.Append(zbi_header_t{.type = type}, bytes);
ZX_ASSERT(result.is_ok());
}
// Append the given objects together as a series of bytes.
template <typename... T>
std::basic_string<std::byte> JoinBytes(const T&... object) {
std::basic_string<std::byte> result;
// Add the bytes from a single item to |result|.
auto add_item = [&result](const auto& x) {
zbitl::ByteView object_bytes = zbitl::AsBytes(x);
result.append(object_bytes);
};
// Add each item.
(add_item(object), ...);
return result;
}
// Determine if two `zbi_mem_range_t` values are the same.
bool MemRangeEqual(const zbi_mem_range_t& a, const zbi_mem_range_t& b) {
return std::tie(a.length, a.paddr, a.reserved, a.type) ==
std::tie(b.length, b.paddr, b.reserved, b.type);
}
TEST(ToMemRange, Efi) {
constexpr efi_memory_descriptor efi{
.Type = EfiConventionalMemory,
.PhysicalStart = 0x1234'abcd'ffff'0000,
.VirtualStart = 0xaaaa'aaaa'aaaa'aaaa,
.NumberOfPages = 100,
.Attribute = EFI_MEMORY_MORE_RELIABLE,
};
constexpr zbi_mem_range_t expected{
.paddr = 0x1234'abcd'ffff'0000,
.length = 409600, // ZX_PAGE_SIZE * 100
.type = ZBI_MEM_RANGE_RAM,
};
EXPECT_TRUE(MemRangeEqual(zbitl::internal::ToMemRange(efi), expected));
}
TEST(ToMemRange, EfiReservedMemory) {
auto efi = efi_memory_descriptor{
.Type = EfiMemoryMappedIO,
.PhysicalStart = 0x0,
.VirtualStart = 0x0,
.NumberOfPages = 1,
.Attribute = 0,
};
EXPECT_EQ(zbitl::internal::ToMemRange(efi).type, static_cast<uint32_t>(ZBI_MEM_RANGE_RESERVED));
}
TEST(ToMemRange, E820) {
auto input = e820entry_t{
.addr = 0x1234'abcd'ffff'0000,
.size = 0x10'0000,
.type = E820_RAM,
};
auto expected = zbi_mem_range_t{
.paddr = 0x1234'abcd'ffff'0000,
.length = 0x10'0000,
.type = ZBI_MEM_RANGE_RAM,
};
EXPECT_TRUE(MemRangeEqual(zbitl::internal::ToMemRange(input), expected));
}
TEST(MemRangeIterator, DefaultContainer) {
zbitl::MemRangeTable container;
EXPECT_EQ(container.begin(), container.end());
EXPECT_THAT(container.take_error(), IsOk());
}
TEST(MemRangeIterator, EmptyZbi) {
ZbiMemoryImage zbi = CreateImage();
zbitl::MemRangeTable container{AsView(zbi)};
// Expect nothing to be found.
EXPECT_EQ(container.begin(), container.end());
EXPECT_THAT(container.size(), IsOkAndHolds(0u));
EXPECT_THAT(container.take_error(), IsOk());
}
TEST(MemRangeIterator, BadZbi) {
zbi_header_t header = ZBI_CONTAINER_HEADER(0);
header.crc32 = 0xffffffff; // bad CRC.
zbitl::View<zbitl::ByteView> view(zbitl::AsBytes(header));
zbitl::MemRangeTable container{view};
// Expect nothing to be found.
EXPECT_EQ(container.begin(), container.end());
// Expect an error.
auto error = container.take_error();
ASSERT_TRUE(error.is_error());
EXPECT_EQ(error.error_value().zbi_error, "bad crc32 field in item without CRC");
// Expect size() to return an error.
auto size_error = container.size();
ASSERT_TRUE(size_error.is_error());
EXPECT_EQ(size_error.error_value().zbi_error, "bad crc32 field in item without CRC");
}
TEST(MemRangeIterator, RequireErrorToBeCalled) {
ZbiMemoryImage zbi = CreateImage();
// Iterate through an empty item and then destroy it without calling Error().
ASSERT_DEATH(
{
zbitl::MemRangeTable container{AsView(zbi)};
// Expect nothing to be found.
EXPECT_EQ(container.begin(), container.end());
// Don't call `take_error`: expect process death during object destruction.
},
"destroyed .* without check");
}
TEST(MemRangeIterator, NoErrorNeededAfterMove) {
ZbiMemoryImage zbi = CreateImage();
zbitl::MemRangeTable container{AsView(zbi)};
// Iterate through an empty item.
container.begin();
// Move the value, and check the error in its new location. We shouldn't
// need to check the first any longer.
zbitl::MemRangeTable new_container = std::move(container);
EXPECT_THAT(new_container.take_error(), IsOk());
}
TEST(MemRangeIterator, EmptyPayload) {
// Construct a ZBI with an empty E820 memory map.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_E820_TABLE, {});
// Expect nothing to be found.
zbitl::MemRangeTable container{AsView(zbi)};
EXPECT_EQ(container.begin(), container.end());
EXPECT_THAT(container.take_error(), IsOk());
}
TEST(MemRangeIterator, EfiItem) {
// Construct a ZBI with a single payload consisting of EFI entries.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_EFI_MEMORY_MAP,
JoinBytes(uint64_t{sizeof(efi_memory_descriptor)},
efi_memory_descriptor{
.PhysicalStart = 0x1000,
.NumberOfPages = 1,
},
efi_memory_descriptor{
.PhysicalStart = 0x2000,
.NumberOfPages = 1,
}));
// Ensure the entries are correct.
zbitl::MemRangeTable container{AsView(zbi)};
EXPECT_THAT(container.size(), IsOkAndHolds(2u));
std::vector<zbi_mem_range_t> ranges(container.begin(), container.end());
ASSERT_TRUE(container.take_error().is_ok());
ASSERT_EQ(ranges.size(), 2u);
EXPECT_EQ(ranges[0].paddr, 0x1000u);
EXPECT_EQ(ranges[1].paddr, 0x2000u);
}
TEST(MemRangeIterator, ZbiMemRangeItem) {
// Construct a ZBI with a single payload consisting of zbi_mem_range_t entries.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_MEM_CONFIG,
JoinBytes(
zbi_mem_range_t{
.paddr = 0x1000,
.length = 0x1000,
},
zbi_mem_range_t{
.paddr = 0x2000,
.length = 0x1000,
}));
// Ensure the entries are correct.
zbitl::MemRangeTable container{AsView(zbi)};
EXPECT_THAT(container.size(), IsOkAndHolds(2u));
std::vector<zbi_mem_range_t> ranges(container.begin(), container.end());
ASSERT_TRUE(container.take_error().is_ok());
ASSERT_EQ(ranges.size(), 2u);
EXPECT_EQ(ranges[0].paddr, 0x1000u);
EXPECT_EQ(ranges[1].paddr, 0x2000u);
}
TEST(MemRangeIterator, E820Item) {
// Construct a ZBI with a single payload consisting of e820entry_t entries.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_E820_TABLE,
JoinBytes(
e820entry_t{
.addr = 0x1000,
.size = 0x1000,
},
e820entry_t{
.addr = 0x2000,
.size = 0x1000,
}));
// Ensure the entries are correct.
zbitl::MemRangeTable container{AsView(zbi)};
EXPECT_THAT(container.size(), IsOkAndHolds(2u));
std::vector<zbi_mem_range_t> ranges(container.begin(), container.end());
ASSERT_TRUE(container.take_error().is_ok());
ASSERT_EQ(ranges.size(), 2u);
EXPECT_EQ(ranges[0].paddr, 0x1000u);
EXPECT_EQ(ranges[1].paddr, 0x2000u);
}
TEST(MemRangeIterator, MixedItems) {
// Construct a ZBI with a mixed set of payloads.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_E820_TABLE,
zbitl::AsBytes(e820entry_t{
.addr = 0x1000,
.size = 0x1000,
}));
AppendPayload(zbi, ZBI_TYPE_MEM_CONFIG,
zbitl::AsBytes(zbi_mem_range_t{
.paddr = 0x2000,
.length = 0x2000,
}));
AppendPayload(zbi, ZBI_TYPE_EFI_MEMORY_MAP,
JoinBytes(uint64_t{sizeof(efi_memory_descriptor)}, efi_memory_descriptor{
.PhysicalStart = 0x3000,
.NumberOfPages = 3,
}));
// Ensure the entries are correct.
zbitl::MemRangeTable container{AsView(zbi)};
EXPECT_THAT(container.size(), IsOkAndHolds(3u));
std::vector<zbi_mem_range_t> ranges(container.begin(), container.end());
ASSERT_TRUE(container.take_error().is_ok());
ASSERT_EQ(ranges.size(), 3u);
EXPECT_EQ(ranges[0].paddr, 0x1000u);
EXPECT_EQ(ranges[1].paddr, 0x2000u);
EXPECT_EQ(ranges[2].paddr, 0x3000u);
}
TEST(MemRangeIterator, OtherItems) {
// Construct a ZBI with non-memory payloads.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_PLATFORM_ID, {});
AppendPayload(zbi, ZBI_TYPE_PLATFORM_ID, {});
AppendPayload(zbi, ZBI_TYPE_MEM_CONFIG,
zbitl::AsBytes(zbi_mem_range_t{
.paddr = 0x1000,
.length = 0x1000,
}));
// Ensure the entries are correct.
zbitl::MemRangeTable container{AsView(zbi)};
EXPECT_THAT(container.size(), IsOkAndHolds(1u));
std::vector<zbi_mem_range_t> ranges(container.begin(), container.end());
ASSERT_TRUE(container.take_error().is_ok());
ASSERT_EQ(ranges.size(), 1u);
EXPECT_EQ(ranges[0].paddr, 0x1000u);
}
// Call size() in the middle of iterating through a ZBI.
TEST(MemRangeIterator, SizeDuringIteration) {
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_E820_TABLE,
zbitl::AsBytes(e820entry_t{
.addr = 0x1000,
.size = 0x1000,
}));
AppendPayload(zbi, ZBI_TYPE_MEM_CONFIG,
zbitl::AsBytes(zbi_mem_range_t{
.paddr = 0x2000,
.length = 0x2000,
}));
// Start iteration.
zbitl::MemRangeTable container{AsView(zbi)};
auto it = container.begin();
EXPECT_EQ((*it).paddr, 0x1000u);
// Call size.
EXPECT_THAT(container.size(), IsOkAndHolds(2u));
// Finish the iteration.
EXPECT_EQ((*it).paddr, 0x1000u);
++it;
EXPECT_EQ((*it).paddr, 0x2000u);
++it;
EXPECT_EQ(it, container.end());
EXPECT_TRUE(container.take_error().is_ok());
}
TEST(MemRangeIterator, EfiRealData) {
// Binary dump of the EFI table produced by OVMF (an open source EFI
// implementation) running on QEMU.
//
// Collected by performing a hexdump to serial of the
// "ZBI_TYPE_EFI_MEMORY_MAP" ZBI entry of an EFI platform on boot.
constexpr uint8_t efi_table[] = {
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x06, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xe0, 0xf1, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf3, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x48, 0x7c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x4f, 0x7e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x52, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x53, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x81, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x9b, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xa5, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xa6, 0x7e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0xa7, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0xa9, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb1, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xcd, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa1, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0,
0xa1, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xb0, 0xb9, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xbc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbe, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xbf, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
0xbf, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf0, 0xbf, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe7, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe9, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0,
0xea, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xb0, 0xec, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xed, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
zbitl::ByteView payload{reinterpret_cast<const std::byte*>(efi_table), sizeof(efi_table)};
// Construct a ZBI with the EFI payload.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_EFI_MEMORY_MAP, payload);
// Ensure we read the correct number of entries.
zbitl::MemRangeTable container{AsView(zbi)};
std::vector<zbi_mem_range_t> ranges(container.begin(), container.end());
ASSERT_TRUE(container.take_error().is_ok());
ASSERT_EQ(ranges.size(), 40u);
// Verify the first and last entries.
EXPECT_TRUE(MemRangeEqual(
zbi_mem_range_t{
.paddr = 0,
.length = 4096,
.type = ZBI_MEM_RANGE_RAM,
},
ranges.front()));
EXPECT_TRUE(MemRangeEqual(
zbi_mem_range_t{
.paddr = 0xffc00000,
.length = 0x400000,
.type = ZBI_MEM_RANGE_RESERVED,
},
ranges.back()));
}
TEST(MemRangeMerger, Empty) {
std::vector<zbi_mem_range_t> input{};
zbitl::MemRangeMerger merger(input.begin(), input.end());
EXPECT_EQ(merger.begin(), merger.end());
}
TEST(MemRangeMerger, SingleItem) {
// Create an input with just a single range.
std::vector<zbi_mem_range_t> input = {
zbi_mem_range_t{
.paddr = 1,
.length = 2,
.type = 3,
},
};
zbitl::MemRangeMerger merger(input.begin(), input.end());
EXPECT_NE(merger.begin(), merger.end());
// Check first element.
auto it = merger.begin();
EXPECT_EQ(it->paddr, 1u);
EXPECT_EQ(it->length, 2u);
EXPECT_EQ(it->type, 3u);
// Should be no more elements.
++it;
EXPECT_EQ(it, merger.end());
}
TEST(MemRangeMerger, MergeItems) {
// Create an input with multiple ranges to be merged.
std::vector<zbi_mem_range_t> input = {
zbi_mem_range_t{
.paddr = 0,
.length = 100,
.type = 1,
},
zbi_mem_range_t{
.paddr = 100,
.length = 200,
.type = 1,
},
zbi_mem_range_t{
.paddr = 300,
.length = 100,
.type = 1,
},
};
zbitl::MemRangeMerger merger(input.begin(), input.end());
// Merge the items.
std::vector<zbi_mem_range_t> result(merger.begin(), merger.end());
// Ensure we got the correctly merged results.
ASSERT_EQ(result.size(), 1u);
EXPECT_EQ(result[0].paddr, 0u);
EXPECT_EQ(result[0].length, 400u);
EXPECT_EQ(result[0].type, 1u);
}
TEST(MemRangeMerger, ShouldNotCombineNonContiguousItems) {
// Ensure we don't merge non-contiguous items.
std::vector<zbi_mem_range_t> input = {
zbi_mem_range_t{
.paddr = 0,
.length = 1,
.type = 1,
},
zbi_mem_range_t{
.paddr = 2, // skips byte 1; should not be merged.
.length = 1,
.type = 1,
},
zbi_mem_range_t{
.paddr = 3, // not the same type; should not be merged.
.length = 1,
.type = 2,
},
};
zbitl::MemRangeMerger merger(input.begin(), input.end());
// Merge the items.
std::vector<zbi_mem_range_t> result(merger.begin(), merger.end());
// Ensure the input matches the output.
ASSERT_EQ(result.size(), input.size());
for (size_t i = 0; i < input.size(); i++) {
EXPECT_EQ(input[i].paddr, result[i].paddr);
EXPECT_EQ(input[i].length, result[i].length);
EXPECT_EQ(input[i].type, result[i].type);
}
}
TEST(MemRangeMerger, MemRangeTableIterator) {
// Create a MemRangeTable, and use it as our input.
ZbiMemoryImage zbi = CreateImage();
AppendPayload(zbi, ZBI_TYPE_EFI_MEMORY_MAP,
JoinBytes(uint64_t{sizeof(efi_memory_descriptor)},
efi_memory_descriptor{
.Type = 1,
.PhysicalStart = 0x1000,
.NumberOfPages = 1,
},
efi_memory_descriptor{
.Type = 1,
.PhysicalStart = 0x2000,
.NumberOfPages = 2,
}));
// Merge elements together.
zbitl::MemRangeTable container{AsView(zbi)};
zbitl::MemRangeMerger merger(container.begin(), container.end());
std::vector<zbi_mem_range_t> ranges(merger.begin(), merger.end());
ASSERT_TRUE(container.take_error().is_ok());
ASSERT_EQ(ranges.size(), 1u);
EXPECT_EQ(ranges[0].paddr, 0x1000u);
EXPECT_EQ(ranges[0].length, 0x3000u);
EXPECT_EQ(ranges[0].type, 1u);
}
} // namespace