1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "page_util.h"
18
19 #include "android-base/stringprintf.h"
20
21 namespace art {
22
23 using android::base::StringPrintf;
24
GetPageFlagsOrCount(art::File & kpage_file,uint64_t page_frame_number,uint64_t & page_flags_or_count,std::string & error_msg)25 bool GetPageFlagsOrCount(art::File& kpage_file,
26 uint64_t page_frame_number,
27 /*out*/ uint64_t& page_flags_or_count,
28 /*out*/ std::string& error_msg) {
29 return GetPageFlagsOrCounts(kpage_file,
30 ArrayRef<const uint64_t>(&page_frame_number, 1u),
31 ArrayRef<uint64_t>(&page_flags_or_count, 1u),
32 error_msg);
33 }
34
GetPageFlagsOrCounts(File & kpage_file,ArrayRef<const uint64_t> page_frame_numbers,ArrayRef<uint64_t> page_flags_or_counts,std::string & error_msg)35 bool GetPageFlagsOrCounts(File& kpage_file,
36 ArrayRef<const uint64_t> page_frame_numbers,
37 /*out*/ ArrayRef<uint64_t> page_flags_or_counts,
38 /*out*/ std::string& error_msg) {
39 static_assert(kPageFlagsEntrySize == kPageCountEntrySize, "entry size check");
40 CHECK_NE(page_frame_numbers.size(), 0u);
41 CHECK_EQ(page_flags_or_counts.size(), page_frame_numbers.size());
42 CHECK(page_frame_numbers.data() != nullptr);
43 CHECK(page_flags_or_counts.data() != nullptr);
44
45 size_t size = page_frame_numbers.size();
46 size_t i = 0;
47 while (i != size) {
48 size_t start = i;
49 ++i;
50 while (i != size && page_frame_numbers[i] - page_frame_numbers[start] == i - start) {
51 ++i;
52 }
53 // Read 64-bit entries from /proc/kpageflags or /proc/kpagecount.
54 if (!kpage_file.PreadFully(page_flags_or_counts.data() + start,
55 (i - start) * kPageMapEntrySize,
56 page_frame_numbers[start] * kPageFlagsEntrySize)) {
57 error_msg = StringPrintf("Failed to read the page flags or counts from %s, error: %s",
58 kpage_file.GetPath().c_str(),
59 strerror(errno));
60 return false;
61 }
62 }
63
64 return true;
65 }
66
GetPageFrameNumber(File & page_map_file,size_t virtual_page_index,uint64_t & page_frame_number,std::string & error_msg)67 bool GetPageFrameNumber(File& page_map_file,
68 size_t virtual_page_index,
69 /*out*/ uint64_t& page_frame_number,
70 /*out*/ std::string& error_msg) {
71 return GetPageFrameNumbers(
72 page_map_file, virtual_page_index, ArrayRef<uint64_t>(&page_frame_number, 1u), error_msg);
73 }
74
GetPageFrameNumbers(File & page_map_file,size_t virtual_page_index,ArrayRef<uint64_t> page_frame_numbers,std::string & error_msg)75 bool GetPageFrameNumbers(File& page_map_file,
76 size_t virtual_page_index,
77 /*out*/ ArrayRef<uint64_t> page_frame_numbers,
78 /*out*/ std::string& error_msg) {
79 CHECK_NE(page_frame_numbers.size(), 0u);
80 CHECK(page_frame_numbers.data() != nullptr);
81
82 // Read 64-bit entries from /proc/$pid/pagemap to get the physical page frame numbers.
83 if (!page_map_file.PreadFully(page_frame_numbers.data(),
84 page_frame_numbers.size() * kPageMapEntrySize,
85 virtual_page_index * kPageMapEntrySize)) {
86 error_msg = StringPrintf("Failed to read virtual page index entries from %s, error: %s",
87 page_map_file.GetPath().c_str(),
88 strerror(errno));
89 return false;
90 }
91
92 // Extract page frame numbers from pagemap entries.
93 for (uint64_t& page_frame_number : page_frame_numbers) {
94 page_frame_number &= kPageFrameNumberMask;
95 }
96
97 return true;
98 }
99
100 } // namespace art
101