1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <sys/mman.h> /* mmap */
17
18 #include "securec.h"
19 #include "pm_util.h"
20 #include "pm_state_c.h"
21 #include "pm_smartptr_util.h"
22 #include "pm_log.h"
23
24 #include "purgeable_mem.h"
25
26 namespace OHOS {
27 namespace PurgeableMem {
28 #ifdef LOG_TAG
29 #undef LOG_TAG
30 #endif
31 #define LOG_TAG "PurgeableMem"
32
RoundUp(size_t val,size_t align)33 static inline size_t RoundUp(size_t val, size_t align)
34 {
35 if (align == 0) {
36 return val;
37 }
38 return ((val + align - 1) / align) * align;
39 }
40
PurgeableMem(size_t dataSize,std::unique_ptr<PurgeableMemBuilder> builder)41 PurgeableMem::PurgeableMem(size_t dataSize, std::unique_ptr<PurgeableMemBuilder> builder)
42 {
43 dataPtr_ = nullptr;
44 builder_ = nullptr;
45 pageTable_ = nullptr;
46 buildDataCount_ = 0;
47
48 if (dataSize == 0) {
49 return;
50 }
51 dataSizeInput_ = dataSize;
52 IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return);
53
54 CreatePurgeableData_();
55 builder_ = std::move(builder);
56 PM_HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString().c_str());
57 }
58
~PurgeableMem()59 PurgeableMem::~PurgeableMem()
60 {
61 PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
62 if (dataPtr_) {
63 if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
64 PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
65 } else {
66 if (UxpteIsEnabled() && !IsPurged()) {
67 PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__);
68 }
69 dataPtr_ = nullptr;
70 }
71 }
72 builder_.reset();
73 pageTable_.reset();
74 }
75
IsPurged()76 bool PurgeableMem::IsPurged()
77 {
78 IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false);
79 return !(pageTable_->CheckPresent((uint64_t)dataPtr_, dataSizeInput_));
80 }
81
CreatePurgeableData_()82 bool PurgeableMem::CreatePurgeableData_()
83 {
84 PM_HILOG_DEBUG(LOG_CORE, "%{public}s", __func__);
85 pageTable_ = nullptr;
86 size_t size = RoundUp(dataSizeInput_, PAGE_SIZE);
87 unsigned int utype = MAP_ANONYMOUS;
88 utype |= (UxpteIsEnabled() ? MAP_PURGEABLE : MAP_PRIVATE);
89 int type = static_cast<int>(utype);
90
91 dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, type, -1, 0);
92 if (dataPtr_ == MAP_FAILED) {
93 PM_HILOG_ERROR(LOG_CORE, "%{public}s: mmap fail", __func__);
94 dataPtr_ = nullptr;
95 return false;
96 }
97 MAKE_UNIQUE(pageTable_, UxPageTable, "constructor uxpt make_unique fail", return false, (uint64_t)dataPtr_, size);
98 return true;
99 }
100
Pin()101 bool PurgeableMem::Pin()
102 {
103 IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false);
104 pageTable_->GetUxpte((uint64_t)dataPtr_, dataSizeInput_);
105 return true;
106 }
107
Unpin()108 bool PurgeableMem::Unpin()
109 {
110 IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false);
111 pageTable_->PutUxpte((uint64_t)dataPtr_, dataSizeInput_);
112 return true;
113 }
114
AfterRebuildSucc()115 void PurgeableMem::AfterRebuildSucc()
116 {
117 }
118
GetPinStatus() const119 int PurgeableMem::GetPinStatus() const
120 {
121 return 0;
122 }
123
ResizeData(size_t newSize)124 void PurgeableMem::ResizeData(size_t newSize)
125 {
126 if (newSize <= 0) {
127 return;
128 }
129 if (dataPtr_) {
130 if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
131 PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
132 } else {
133 dataPtr_ = nullptr;
134 }
135 }
136 dataSizeInput_ = newSize;
137 CreatePurgeableData_();
138 }
139
ToString() const140 inline std::string PurgeableMem::ToString() const
141 {
142 std::string dataptrStr = dataPtr_ ? std::to_string((unsigned long long)dataPtr_) : "0";
143 std::string pageTableStr = pageTable_ ? pageTable_->ToString() : "0";
144 return "dataAddr:" + dataptrStr + " dataSizeInput:" + std::to_string(dataSizeInput_) +
145 " " + pageTableStr;
146 }
147 } /* namespace PurgeableMem */
148 } /* namespace OHOS */
149