// Copyright 2020 The Android Open Source Project // // 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 // // http://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 "host-common/address_space_shared_slots_host_memory_allocator.h" #include namespace android { namespace emulation { namespace { typedef AddressSpaceSharedSlotsHostMemoryAllocatorContext ASSSHMAC; typedef ASSSHMAC::MemBlock MemBlock; typedef MemBlock::FreeSubblocks_t FreeSubblocks_t; int add_memory_mapping(uint64_t gpa, void *ptr, uint64_t size) { return 1; } int remove_memory_mapping(uint64_t gpa, void *ptr, uint64_t size) { return 1; } struct address_space_device_control_ops create_address_space_device_control_ops() { struct address_space_device_control_ops ops = {}; ops.add_memory_mapping = &add_memory_mapping; ops.remove_memory_mapping = &remove_memory_mapping; return ops; } uint64_t getPhysAddrStartLocked(void) { return 2020; } int allocSharedHostRegionLocked(uint64_t page_aligned_size, uint64_t* offset) { *offset = page_aligned_size * 10; return 0; } int freeSharedHostRegionLocked(uint64_t offset) { return 0; } AddressSpaceHwFuncs create_AddressSpaceHwFuncs() { AddressSpaceHwFuncs hw = {}; hw.allocSharedHostRegionLocked = &allocSharedHostRegionLocked; hw.freeSharedHostRegionLocked = &freeSharedHostRegionLocked; hw.getPhysAddrStartLocked = &getPhysAddrStartLocked; return hw; } } TEST(MemBlock_findFreeSubblock, Simple) { FreeSubblocks_t fsb; EXPECT_TRUE(MemBlock::findFreeSubblock(&fsb, 11) == fsb.end()); fsb[100] = 10; EXPECT_TRUE(MemBlock::findFreeSubblock(&fsb, 11) == fsb.end()); FreeSubblocks_t::const_iterator i; i = MemBlock::findFreeSubblock(&fsb, 7); ASSERT_TRUE(i != fsb.end()); EXPECT_EQ(i->first, 100); EXPECT_EQ(i->second, 10); fsb[200] = 6; i = MemBlock::findFreeSubblock(&fsb, 7); ASSERT_TRUE(i != fsb.end()); EXPECT_EQ(i->first, 100); EXPECT_EQ(i->second, 10); fsb[300] = 8; i = MemBlock::findFreeSubblock(&fsb, 7); ASSERT_TRUE(i != fsb.end()); EXPECT_EQ(i->first, 300); EXPECT_EQ(i->second, 8); } TEST(MemBlock_tryMergeSubblocks, NoMerge) { FreeSubblocks_t fsb; auto i = fsb.insert({10, 5}).first; auto j = fsb.insert({20, 5}).first; auto r = MemBlock::tryMergeSubblocks(&fsb, i, i, j); EXPECT_EQ(fsb.size(), 2); EXPECT_EQ(fsb[10], 5); EXPECT_EQ(fsb[20], 5); EXPECT_TRUE(r == i); } TEST(MemBlock_tryMergeSubblocks, Merge) { FreeSubblocks_t fsb; auto i = fsb.insert({10, 10}).first; auto j = fsb.insert({20, 5}).first; auto r = MemBlock::tryMergeSubblocks(&fsb, i, i, j); EXPECT_EQ(fsb.size(), 1); EXPECT_EQ(fsb[10], 15); ASSERT_TRUE(r != fsb.end()); EXPECT_EQ(r->first, 10); EXPECT_EQ(r->second, 15); } TEST(MemBlock, allocate) { const struct address_space_device_control_ops ops = create_address_space_device_control_ops(); const AddressSpaceHwFuncs hw = create_AddressSpaceHwFuncs(); MemBlock block(&ops, &hw, 100); EXPECT_TRUE(block.isAllFree()); EXPECT_EQ(block.physBase, 2020 + 100 * 10); EXPECT_EQ(block.allocate(110), 0); // too large uint32_t off; off = block.allocate(50); EXPECT_GE(off, 2020 + 100 * 10); off = block.allocate(47); EXPECT_GE(off, 2020 + 100 * 10); off = block.allocate(2); EXPECT_GE(off, 2020 + 100 * 10); off = block.allocate(2); EXPECT_EQ(off, 0); off = block.allocate(1); EXPECT_GE(off, 2020 + 100 * 10); off = block.allocate(1); EXPECT_EQ(off, 0); } TEST(MemBlock, unallocate) { const struct address_space_device_control_ops ops = create_address_space_device_control_ops(); const AddressSpaceHwFuncs hw = create_AddressSpaceHwFuncs(); MemBlock block(&ops, &hw, 100); EXPECT_TRUE(block.isAllFree()); EXPECT_EQ(block.physBase, 2020 + 100 * 10); uint32_t off60 = block.allocate(60); EXPECT_GE(off60, 2020 + 100 * 10); uint32_t off20 = block.allocate(20); EXPECT_GE(off20, 2020 + 100 * 10); uint32_t off30 = block.allocate(30); EXPECT_EQ(off30, 0); block.unallocate(off20, 20); off30 = block.allocate(30); EXPECT_GE(off30, 2020 + 100 * 10); block.unallocate(off60, 60); block.unallocate(off30, 30); EXPECT_TRUE(block.isAllFree()); } } // namespace emulation } // namespace android