| // 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 |