1f0bfeaa8Sopenharmony_ci/*
2f0bfeaa8Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3f0bfeaa8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4f0bfeaa8Sopenharmony_ci * you may not use this file except in compliance with the License.
5f0bfeaa8Sopenharmony_ci * You may obtain a copy of the License at
6f0bfeaa8Sopenharmony_ci *
7f0bfeaa8Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8f0bfeaa8Sopenharmony_ci *
9f0bfeaa8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10f0bfeaa8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11f0bfeaa8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f0bfeaa8Sopenharmony_ci * See the License for the specific language governing permissions and
13f0bfeaa8Sopenharmony_ci * limitations under the License.
14f0bfeaa8Sopenharmony_ci */
15f0bfeaa8Sopenharmony_ci
16f0bfeaa8Sopenharmony_ci#include <sys/mman.h> /* mmap */
17f0bfeaa8Sopenharmony_ci
18f0bfeaa8Sopenharmony_ci#include "securec.h"
19f0bfeaa8Sopenharmony_ci#include "pm_util.h"
20f0bfeaa8Sopenharmony_ci#include "pm_state_c.h"
21f0bfeaa8Sopenharmony_ci#include "pm_smartptr_util.h"
22f0bfeaa8Sopenharmony_ci#include "pm_log.h"
23f0bfeaa8Sopenharmony_ci
24f0bfeaa8Sopenharmony_ci#include "purgeable_ashmem.h"
25f0bfeaa8Sopenharmony_ci
26f0bfeaa8Sopenharmony_cinamespace OHOS {
27f0bfeaa8Sopenharmony_cinamespace PurgeableMem {
28f0bfeaa8Sopenharmony_ci#ifdef LOG_TAG
29f0bfeaa8Sopenharmony_ci#undef LOG_TAG
30f0bfeaa8Sopenharmony_ci#endif
31f0bfeaa8Sopenharmony_ci#define LOG_TAG "PurgeableMem"
32f0bfeaa8Sopenharmony_ci
33f0bfeaa8Sopenharmony_cistatic inline size_t RoundUp(size_t val, size_t align)
34f0bfeaa8Sopenharmony_ci{
35f0bfeaa8Sopenharmony_ci    if (val + align < val || val + align < align) {
36f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR(LOG_CORE, "%{public}s: Addition overflow!", __func__);
37f0bfeaa8Sopenharmony_ci        return val;
38f0bfeaa8Sopenharmony_ci    }
39f0bfeaa8Sopenharmony_ci    if (align == 0) {
40f0bfeaa8Sopenharmony_ci        return val;
41f0bfeaa8Sopenharmony_ci    }
42f0bfeaa8Sopenharmony_ci    return ((val + align - 1) / align) * align;
43f0bfeaa8Sopenharmony_ci}
44f0bfeaa8Sopenharmony_ci
45f0bfeaa8Sopenharmony_ciPurgeableAshMem::PurgeableAshMem(std::unique_ptr<PurgeableMemBuilder> builder)
46f0bfeaa8Sopenharmony_ci{
47f0bfeaa8Sopenharmony_ci    dataPtr_ = nullptr;
48f0bfeaa8Sopenharmony_ci    builder_ = nullptr;
49f0bfeaa8Sopenharmony_ci    ashmemFd_ = -1;
50f0bfeaa8Sopenharmony_ci    buildDataCount_ = 0;
51f0bfeaa8Sopenharmony_ci    isSupport_ = false;
52f0bfeaa8Sopenharmony_ci    isChange_ = false;
53f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return);
54f0bfeaa8Sopenharmony_ci    builder_ = std::move(builder);
55f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString().c_str());
56f0bfeaa8Sopenharmony_ci}
57f0bfeaa8Sopenharmony_ci
58f0bfeaa8Sopenharmony_ciPurgeableAshMem::PurgeableAshMem(size_t dataSize, std::unique_ptr<PurgeableMemBuilder> builder)
59f0bfeaa8Sopenharmony_ci{
60f0bfeaa8Sopenharmony_ci    dataPtr_ = nullptr;
61f0bfeaa8Sopenharmony_ci    builder_ = nullptr;
62f0bfeaa8Sopenharmony_ci    ashmemFd_ = -1;
63f0bfeaa8Sopenharmony_ci    buildDataCount_ = 0;
64f0bfeaa8Sopenharmony_ci    isSupport_ = false;
65f0bfeaa8Sopenharmony_ci    isChange_ = false;
66f0bfeaa8Sopenharmony_ci    if (dataSize == 0) {
67f0bfeaa8Sopenharmony_ci        return;
68f0bfeaa8Sopenharmony_ci    }
69f0bfeaa8Sopenharmony_ci    dataSizeInput_ = dataSize;
70f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return);
71f0bfeaa8Sopenharmony_ci
72f0bfeaa8Sopenharmony_ci    if (!CreatePurgeableData()) {
73f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to create purgeabledata");
74f0bfeaa8Sopenharmony_ci        return;
75f0bfeaa8Sopenharmony_ci    }
76f0bfeaa8Sopenharmony_ci    builder_ = std::move(builder);
77f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString().c_str());
78f0bfeaa8Sopenharmony_ci}
79f0bfeaa8Sopenharmony_ci
80f0bfeaa8Sopenharmony_ciPurgeableAshMem::~PurgeableAshMem()
81f0bfeaa8Sopenharmony_ci{
82f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
83f0bfeaa8Sopenharmony_ci    if (!isChange_ && dataPtr_) {
84f0bfeaa8Sopenharmony_ci        if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
85f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
86f0bfeaa8Sopenharmony_ci        } else {
87f0bfeaa8Sopenharmony_ci            if (UxpteIsEnabled() && !IsPurged()) {
88f0bfeaa8Sopenharmony_ci                PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__);
89f0bfeaa8Sopenharmony_ci            }
90f0bfeaa8Sopenharmony_ci            dataPtr_ = nullptr;
91f0bfeaa8Sopenharmony_ci            close(ashmemFd_);
92f0bfeaa8Sopenharmony_ci        }
93f0bfeaa8Sopenharmony_ci    }
94f0bfeaa8Sopenharmony_ci    builder_.reset();
95f0bfeaa8Sopenharmony_ci}
96f0bfeaa8Sopenharmony_ci
97f0bfeaa8Sopenharmony_ciint PurgeableAshMem::GetAshmemFd()
98f0bfeaa8Sopenharmony_ci{
99f0bfeaa8Sopenharmony_ci    return ashmemFd_;
100f0bfeaa8Sopenharmony_ci}
101f0bfeaa8Sopenharmony_ci
102f0bfeaa8Sopenharmony_cibool PurgeableAshMem::IsPurged()
103f0bfeaa8Sopenharmony_ci{
104f0bfeaa8Sopenharmony_ci    if (!isSupport_) {
105f0bfeaa8Sopenharmony_ci        return false;
106f0bfeaa8Sopenharmony_ci    }
107f0bfeaa8Sopenharmony_ci    int ret = ioctl(ashmemFd_, PURGEABLE_ASHMEM_IS_PURGED);
108f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s: IsPurged %{public}d", __func__, ret);
109f0bfeaa8Sopenharmony_ci    return ret > 0 ? true : false;
110f0bfeaa8Sopenharmony_ci}
111f0bfeaa8Sopenharmony_ci
112f0bfeaa8Sopenharmony_cibool PurgeableAshMem::CreatePurgeableData()
113f0bfeaa8Sopenharmony_ci{
114f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s", __func__);
115f0bfeaa8Sopenharmony_ci    if (dataSizeInput_ == 0) {
116f0bfeaa8Sopenharmony_ci        return false;
117f0bfeaa8Sopenharmony_ci    }
118f0bfeaa8Sopenharmony_ci    size_t size = RoundUp(dataSizeInput_, PAGE_SIZE);
119f0bfeaa8Sopenharmony_ci    int fd = AshmemCreate("PurgeableAshmem", size);
120f0bfeaa8Sopenharmony_ci    if (fd < 0) {
121f0bfeaa8Sopenharmony_ci        return false;
122f0bfeaa8Sopenharmony_ci    }
123f0bfeaa8Sopenharmony_ci    if (AshmemSetProt(fd, PROT_READ | PROT_WRITE) < 0) {
124f0bfeaa8Sopenharmony_ci        close(fd);
125f0bfeaa8Sopenharmony_ci        return false;
126f0bfeaa8Sopenharmony_ci    }
127f0bfeaa8Sopenharmony_ci    ashmemFd_ = fd;
128f0bfeaa8Sopenharmony_ci    pin_ = { static_cast<uint32_t>(0), static_cast<uint32_t>(0) };
129f0bfeaa8Sopenharmony_ci    dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd_, 0);
130f0bfeaa8Sopenharmony_ci    if (dataPtr_ == MAP_FAILED) {
131f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR(LOG_CORE, "%{public}s: mmap fail", __func__);
132f0bfeaa8Sopenharmony_ci        dataPtr_ = nullptr;
133f0bfeaa8Sopenharmony_ci        close(ashmemFd_);
134f0bfeaa8Sopenharmony_ci        return false;
135f0bfeaa8Sopenharmony_ci    }
136f0bfeaa8Sopenharmony_ci    TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_SET_PURGEABLE));
137f0bfeaa8Sopenharmony_ci    if (TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_GET_PURGEABLE)) == 1) {
138f0bfeaa8Sopenharmony_ci        isSupport_ = true;
139f0bfeaa8Sopenharmony_ci    }
140f0bfeaa8Sopenharmony_ci    Unpin();
141f0bfeaa8Sopenharmony_ci    return true;
142f0bfeaa8Sopenharmony_ci}
143f0bfeaa8Sopenharmony_ci
144f0bfeaa8Sopenharmony_cibool PurgeableAshMem::Pin()
145f0bfeaa8Sopenharmony_ci{
146f0bfeaa8Sopenharmony_ci    if (!isSupport_) {
147f0bfeaa8Sopenharmony_ci        return true;
148f0bfeaa8Sopenharmony_ci    }
149f0bfeaa8Sopenharmony_ci    if (ashmemFd_ > 0) {
150f0bfeaa8Sopenharmony_ci        TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_PIN, &pin_));
151f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "%{public}s: fd:%{public}d PURGEABLE_GET_PIN_STATE: %{public}d",
152f0bfeaa8Sopenharmony_ci                       __func__, ashmemFd_, ioctl(ashmemFd_, ASHMEM_GET_PIN_STATUS, &pin_));
153f0bfeaa8Sopenharmony_ci    } else {
154f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "ashmemFd_ not exist!!");
155f0bfeaa8Sopenharmony_ci        return false;
156f0bfeaa8Sopenharmony_ci    }
157f0bfeaa8Sopenharmony_ci    return true;
158f0bfeaa8Sopenharmony_ci}
159f0bfeaa8Sopenharmony_ci
160f0bfeaa8Sopenharmony_cibool PurgeableAshMem::Unpin()
161f0bfeaa8Sopenharmony_ci{
162f0bfeaa8Sopenharmony_ci    if (!isSupport_) {
163f0bfeaa8Sopenharmony_ci        return true;
164f0bfeaa8Sopenharmony_ci    }
165f0bfeaa8Sopenharmony_ci    if (ashmemFd_ > 0) {
166f0bfeaa8Sopenharmony_ci        TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_UNPIN, &pin_));
167f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "%{public}s: fd:%{public}d PURGEABLE_GET_PIN_STATE: %{public}d",
168f0bfeaa8Sopenharmony_ci                       __func__, ashmemFd_, ioctl(ashmemFd_, ASHMEM_GET_PIN_STATUS, &pin_));
169f0bfeaa8Sopenharmony_ci    } else {
170f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "ashmemFd_ not exist!!");
171f0bfeaa8Sopenharmony_ci        return false;
172f0bfeaa8Sopenharmony_ci    }
173f0bfeaa8Sopenharmony_ci    return true;
174f0bfeaa8Sopenharmony_ci}
175f0bfeaa8Sopenharmony_ci
176f0bfeaa8Sopenharmony_ciint PurgeableAshMem::GetPinStatus() const
177f0bfeaa8Sopenharmony_ci{
178f0bfeaa8Sopenharmony_ci    int ret = 0;
179f0bfeaa8Sopenharmony_ci    if (!isSupport_) {
180f0bfeaa8Sopenharmony_ci        return ret;
181f0bfeaa8Sopenharmony_ci    }
182f0bfeaa8Sopenharmony_ci    ret = ioctl(ashmemFd_, ASHMEM_GET_PIN_STATUS, &pin_);
183f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s: GetPinStatus %{public}d", __func__, ret);
184f0bfeaa8Sopenharmony_ci    return ret;
185f0bfeaa8Sopenharmony_ci}
186f0bfeaa8Sopenharmony_ci
187f0bfeaa8Sopenharmony_civoid PurgeableAshMem::AfterRebuildSucc()
188f0bfeaa8Sopenharmony_ci{
189f0bfeaa8Sopenharmony_ci    TEMP_FAILURE_RETRY(ioctl(ashmemFd_, PURGEABLE_ASHMEM_REBUILD_SUCCESS));
190f0bfeaa8Sopenharmony_ci}
191f0bfeaa8Sopenharmony_ci
192f0bfeaa8Sopenharmony_civoid PurgeableAshMem::ResizeData(size_t newSize)
193f0bfeaa8Sopenharmony_ci{
194f0bfeaa8Sopenharmony_ci    if (newSize <= 0 || newSize >= OHOS_MAXIMUM_PURGEABLE_MEMORY) {
195f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to apply for memory");
196f0bfeaa8Sopenharmony_ci        return;
197f0bfeaa8Sopenharmony_ci    }
198f0bfeaa8Sopenharmony_ci    if (dataPtr_) {
199f0bfeaa8Sopenharmony_ci        if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
200f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
201f0bfeaa8Sopenharmony_ci        } else {
202f0bfeaa8Sopenharmony_ci            dataPtr_ = nullptr;
203f0bfeaa8Sopenharmony_ci            if (ashmemFd_ > 0) {
204f0bfeaa8Sopenharmony_ci                close(ashmemFd_);
205f0bfeaa8Sopenharmony_ci            }
206f0bfeaa8Sopenharmony_ci        }
207f0bfeaa8Sopenharmony_ci    }
208f0bfeaa8Sopenharmony_ci    dataSizeInput_ = newSize;
209f0bfeaa8Sopenharmony_ci    if (!CreatePurgeableData()) {
210f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to create purgeabledata");
211f0bfeaa8Sopenharmony_ci        return;
212f0bfeaa8Sopenharmony_ci    }
213f0bfeaa8Sopenharmony_ci}
214f0bfeaa8Sopenharmony_ci
215f0bfeaa8Sopenharmony_cibool PurgeableAshMem::ChangeAshmemData(size_t size, int fd, void *data)
216f0bfeaa8Sopenharmony_ci{
217f0bfeaa8Sopenharmony_ci    if (size <= 0 || size >= OHOS_MAXIMUM_PURGEABLE_MEMORY) {
218f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to apply for memory");
219f0bfeaa8Sopenharmony_ci        return false;
220f0bfeaa8Sopenharmony_ci    }
221f0bfeaa8Sopenharmony_ci    if (dataPtr_) {
222f0bfeaa8Sopenharmony_ci        if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
223f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
224f0bfeaa8Sopenharmony_ci        } else {
225f0bfeaa8Sopenharmony_ci            dataPtr_ = nullptr;
226f0bfeaa8Sopenharmony_ci            if (ashmemFd_ > 0) {
227f0bfeaa8Sopenharmony_ci                close(ashmemFd_);
228f0bfeaa8Sopenharmony_ci            }
229f0bfeaa8Sopenharmony_ci        }
230f0bfeaa8Sopenharmony_ci    }
231f0bfeaa8Sopenharmony_ci    dataSizeInput_ = size;
232f0bfeaa8Sopenharmony_ci    ashmemFd_ = fd;
233f0bfeaa8Sopenharmony_ci    dataPtr_ = data;
234f0bfeaa8Sopenharmony_ci    buildDataCount_++;
235f0bfeaa8Sopenharmony_ci    isChange_ = true;
236f0bfeaa8Sopenharmony_ci    TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_SET_PURGEABLE));
237f0bfeaa8Sopenharmony_ci    if (TEMP_FAILURE_RETRY(ioctl(ashmemFd_, ASHMEM_GET_PURGEABLE)) == 1) {
238f0bfeaa8Sopenharmony_ci        isSupport_ = true;
239f0bfeaa8Sopenharmony_ci    }
240f0bfeaa8Sopenharmony_ci    Unpin();
241f0bfeaa8Sopenharmony_ci    return true;
242f0bfeaa8Sopenharmony_ci}
243f0bfeaa8Sopenharmony_ci
244f0bfeaa8Sopenharmony_ciinline std::string PurgeableAshMem::ToString() const
245f0bfeaa8Sopenharmony_ci{
246f0bfeaa8Sopenharmony_ci    return "";
247f0bfeaa8Sopenharmony_ci}
248f0bfeaa8Sopenharmony_ci} /* namespace PurgeableMem */
249f0bfeaa8Sopenharmony_ci} /* namespace OHOS */
250