Reserve boot image memory in one go.
Load boot image components into the reserved memory.
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: Pixel 2 XL boots.
Test: m test-art-target-gtest
Test: testrunner.py --target --optimizing
Bug: 77856493
Change-Id: I214f947979bc0bbfc6df4312527504e90b88a01d
diff --git a/libartbase/base/mem_map_test.cc b/libartbase/base/mem_map_test.cc
index 396f12b..ab3d18f 100644
--- a/libartbase/base/mem_map_test.cc
+++ b/libartbase/base/mem_map_test.cc
@@ -540,6 +540,7 @@
PROT_READ | PROT_WRITE,
/* low_4gb */ false,
/* reuse */ false,
+ /* reservation */ nullptr,
&error_msg);
ASSERT_TRUE(map.IsValid());
ASSERT_TRUE(error_msg.empty());
@@ -549,6 +550,7 @@
PROT_READ | PROT_WRITE,
/* low_4gb */ false,
/* reuse */ true,
+ /* reservation */ nullptr,
&error_msg);
ASSERT_TRUE(map2.IsValid());
ASSERT_TRUE(error_msg.empty());
@@ -720,4 +722,108 @@
}
}
+TEST_F(MemMapTest, Reservation) {
+ CommonInit();
+ std::string error_msg;
+ ScratchFile scratch_file;
+ constexpr size_t kMapSize = 5 * kPageSize;
+ std::unique_ptr<uint8_t[]> data(new uint8_t[kMapSize]());
+ ASSERT_TRUE(scratch_file.GetFile()->WriteFully(&data[0], kMapSize));
+
+ MemMap reservation = MemMap::MapAnonymous("Test reservation",
+ /* addr */ nullptr,
+ kMapSize,
+ PROT_NONE,
+ /* low_4gb */ false,
+ &error_msg);
+ ASSERT_TRUE(reservation.IsValid());
+ ASSERT_TRUE(error_msg.empty());
+
+ // Map first part of the reservation.
+ constexpr size_t kChunk1Size = kPageSize - 1u;
+ static_assert(kChunk1Size < kMapSize, "We want to split the reservation.");
+ uint8_t* addr1 = reservation.Begin();
+ MemMap map1 = MemMap::MapFileAtAddress(addr1,
+ /* byte_count */ kChunk1Size,
+ PROT_READ,
+ MAP_PRIVATE,
+ scratch_file.GetFd(),
+ /* start */ 0,
+ /* low_4gb */ false,
+ scratch_file.GetFilename().c_str(),
+ /* reuse */ false,
+ &reservation,
+ &error_msg);
+ ASSERT_TRUE(map1.IsValid()) << error_msg;
+ ASSERT_TRUE(error_msg.empty());
+ ASSERT_EQ(map1.Size(), kChunk1Size);
+ ASSERT_EQ(addr1, map1.Begin());
+ ASSERT_TRUE(reservation.IsValid());
+ // Entire pages are taken from the `reservation`.
+ ASSERT_LT(map1.End(), map1.BaseEnd());
+ ASSERT_EQ(map1.BaseEnd(), reservation.Begin());
+
+ // Map second part as an anonymous mapping.
+ constexpr size_t kChunk2Size = 2 * kPageSize;
+ DCHECK_LT(kChunk2Size, reservation.Size()); // We want to split the reservation.
+ uint8_t* addr2 = reservation.Begin();
+ MemMap map2 = MemMap::MapAnonymous("MiddleReservation",
+ addr2,
+ /* byte_count */ kChunk2Size,
+ PROT_READ,
+ /* low_4gb */ false,
+ /* reuse */ false,
+ &reservation,
+ &error_msg);
+ ASSERT_TRUE(map2.IsValid()) << error_msg;
+ ASSERT_TRUE(error_msg.empty());
+ ASSERT_EQ(map2.Size(), kChunk2Size);
+ ASSERT_EQ(addr2, map2.Begin());
+ ASSERT_EQ(map2.End(), map2.BaseEnd()); // kChunk2Size is page aligned.
+ ASSERT_EQ(map2.BaseEnd(), reservation.Begin());
+
+ // Map the rest of the reservation except the last byte.
+ const size_t kChunk3Size = reservation.Size() - 1u;
+ uint8_t* addr3 = reservation.Begin();
+ MemMap map3 = MemMap::MapFileAtAddress(addr3,
+ /* byte_count */ kChunk3Size,
+ PROT_READ,
+ MAP_PRIVATE,
+ scratch_file.GetFd(),
+ /* start */ dchecked_integral_cast<size_t>(addr3 - addr1),
+ /* low_4gb */ false,
+ scratch_file.GetFilename().c_str(),
+ /* reuse */ false,
+ &reservation,
+ &error_msg);
+ ASSERT_TRUE(map3.IsValid()) << error_msg;
+ ASSERT_TRUE(error_msg.empty());
+ ASSERT_EQ(map3.Size(), kChunk3Size);
+ ASSERT_EQ(addr3, map3.Begin());
+ // Entire pages are taken from the `reservation`, so it's now exhausted.
+ ASSERT_FALSE(reservation.IsValid());
+
+ // Now split the MiddleReservation.
+ constexpr size_t kChunk2ASize = kPageSize - 1u;
+ DCHECK_LT(kChunk2ASize, map2.Size()); // We want to split the reservation.
+ MemMap map2a = map2.TakeReservedMemory(kChunk2ASize);
+ ASSERT_TRUE(map2a.IsValid()) << error_msg;
+ ASSERT_TRUE(error_msg.empty());
+ ASSERT_EQ(map2a.Size(), kChunk2ASize);
+ ASSERT_EQ(addr2, map2a.Begin());
+ ASSERT_TRUE(map2.IsValid());
+ ASSERT_LT(map2a.End(), map2a.BaseEnd());
+ ASSERT_EQ(map2a.BaseEnd(), map2.Begin());
+
+ // And take the rest of the middle reservation.
+ const size_t kChunk2BSize = map2.Size() - 1u;
+ uint8_t* addr2b = map2.Begin();
+ MemMap map2b = map2.TakeReservedMemory(kChunk2BSize);
+ ASSERT_TRUE(map2b.IsValid()) << error_msg;
+ ASSERT_TRUE(error_msg.empty());
+ ASSERT_EQ(map2b.Size(), kChunk2ASize);
+ ASSERT_EQ(addr2b, map2b.Begin());
+ ASSERT_FALSE(map2.IsValid());
+}
+
} // namespace art