| // 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 <lib/boot-shim/boot-shim.h> |
| #include <lib/boot-shim/pool-mem-config.h> |
| #include <lib/boot-shim/test-helper.h> |
| #include <lib/memalloc/pool.h> |
| |
| #include <forward_list> |
| #include <memory> |
| |
| #include <zxtest/zxtest.h> |
| |
| namespace { |
| |
| constexpr uint64_t kChunkSize = memalloc::Pool::kBookkeepingChunkSize; |
| |
| // The pool uses a callback to convert "physical" address regions allocated for |
| // bookkeeping space to accessible pointers. The callback for testing purposes |
| // just ignores that "physical" address and allocates a new chunk for the Pool |
| // code to store its bookkeeping data in. |
| memalloc::Pool::BookkeepingAddressToPointer ForTestPool() { |
| // The list in the (move-only) lambda just keeps the pointers all live for |
| // the lifetime of the Pool (which owns the wrapped and returned lambda). |
| using Bookkeeping = std::forward_list<std::unique_ptr<std::byte[]>>; |
| return [bookkeeping = Bookkeeping()](uint64_t addr, uint64_t size) mutable { |
| std::byte* chunk = new std::byte[size]; // Uninitialized space. |
| bookkeeping.emplace_front(chunk); |
| return chunk; |
| }; |
| } |
| |
| using TestShim = boot_shim::BootShim<boot_shim::PoolMemConfigItem>; |
| |
| TEST(BootShimTests, PoolMemConfigItem) { |
| boot_shim::testing::TestHelper test; |
| TestShim shim("PoolMemConfigItem", test.log()); |
| |
| auto [buffer, owner] = test.GetZbiBuffer(); |
| TestShim::DataZbi zbi(buffer); |
| |
| auto& item = shim.Get<boot_shim::PoolMemConfigItem>(); |
| memalloc::Pool pool(ForTestPool()); |
| |
| // Not initialized yet: no item. |
| EXPECT_EQ(0, item.size_bytes()); |
| |
| // Initialize with an empty pool: still no item. |
| item.Init(pool); |
| EXPECT_EQ(0, item.size_bytes()); |
| |
| // Make sure no item means no item. |
| EXPECT_TRUE(shim.AppendItems(zbi).is_ok()); |
| |
| for (auto [header, payload] : zbi) { |
| EXPECT_NE(header->type, ZBI_TYPE_MEM_CONFIG); |
| } |
| EXPECT_TRUE(zbi.take_error().is_ok()); |
| |
| // Now actually initialize the pool. |
| memalloc::Range test_pool_ranges[] = { |
| { |
| .addr = 0, |
| .size = kChunkSize * 1000, |
| .type = memalloc::Type::kFreeRam, |
| }, |
| { |
| .addr = kChunkSize * 50, |
| .size = kChunkSize * 2, |
| .type = memalloc::Type::kPeripheral, |
| }, |
| }; |
| EXPECT_TRUE(pool.Init(std::array{cpp20::span<memalloc::Range>(test_pool_ranges)}).is_ok()); |
| auto alloc_result = pool.Allocate(memalloc::Type::kPoolTestPayload, kChunkSize * 100); |
| ASSERT_TRUE(alloc_result.is_ok()); |
| EXPECT_EQ(kChunkSize * 52, alloc_result.value()); |
| |
| constexpr zbi_mem_range_t kExpectedZbiRanges[] = { |
| { |
| .paddr = 0, |
| .length = kChunkSize * 50, |
| .type = ZBI_MEM_RANGE_RAM, |
| }, |
| { |
| .paddr = kChunkSize * 50, |
| .length = kChunkSize * 2, |
| .type = ZBI_MEM_RANGE_PERIPHERAL, |
| }, |
| { |
| .paddr = kChunkSize * 52, |
| .length = kChunkSize * 948, |
| .type = ZBI_MEM_RANGE_RAM, |
| }, |
| }; |
| |
| // The item points to the Pool so it regenerates its results from it on each |
| // call without repeating pool.Init(item). |
| EXPECT_GT(item.size_bytes(), sizeof(kExpectedZbiRanges)); |
| |
| EXPECT_TRUE(shim.AppendItems(zbi).is_ok()); |
| |
| TestShim::DataZbi::payload_type item_payload; |
| for (auto [header, payload] : zbi) { |
| if (header->type == ZBI_TYPE_MEM_CONFIG) { |
| EXPECT_TRUE(item_payload.empty()); |
| item_payload = payload; |
| } |
| } |
| EXPECT_TRUE(zbi.take_error().is_ok()); |
| |
| EXPECT_EQ(cpp20::span(kExpectedZbiRanges).size_bytes(), item_payload.size_bytes()); |
| |
| const cpp20::span mem_config{ |
| reinterpret_cast<const zbi_mem_range_t*>(item_payload.data()), |
| item_payload.size_bytes() / sizeof(zbi_mem_range_t), |
| }; |
| ASSERT_EQ(std::size(kExpectedZbiRanges), std::size(mem_config)); |
| for (size_t i = 0; i < std::size(kExpectedZbiRanges); ++i) { |
| EXPECT_EQ(kExpectedZbiRanges[i].paddr, mem_config[i].paddr); |
| EXPECT_EQ(kExpectedZbiRanges[i].length, mem_config[i].length); |
| EXPECT_EQ(kExpectedZbiRanges[i].type, mem_config[i].type); |
| } |
| } |
| |
| } // namespace |