1f0bfeaa8Sopenharmony_ci/*
2f0bfeaa8Sopenharmony_ci * Copyright (c) 2022 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_mem.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_ciPurgeableMem::PurgeableMem(size_t dataSize, std::unique_ptr<PurgeableMemBuilder> builder)
46f0bfeaa8Sopenharmony_ci{
47f0bfeaa8Sopenharmony_ci    dataPtr_ = nullptr;
48f0bfeaa8Sopenharmony_ci    builder_ = nullptr;
49f0bfeaa8Sopenharmony_ci    pageTable_ = nullptr;
50f0bfeaa8Sopenharmony_ci    buildDataCount_ = 0;
51f0bfeaa8Sopenharmony_ci
52f0bfeaa8Sopenharmony_ci    if (dataSize <= 0 || dataSize >= OHOS_MAXIMUM_PURGEABLE_MEMORY) {
53f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to apply for memory");
54f0bfeaa8Sopenharmony_ci        return;
55f0bfeaa8Sopenharmony_ci    }
56f0bfeaa8Sopenharmony_ci    dataSizeInput_ = dataSize;
57f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return);
58f0bfeaa8Sopenharmony_ci
59f0bfeaa8Sopenharmony_ci    if (!CreatePurgeableData()) {
60f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to create purgeabledata");
61f0bfeaa8Sopenharmony_ci        return;
62f0bfeaa8Sopenharmony_ci    }
63f0bfeaa8Sopenharmony_ci    builder_ = std::move(builder);
64f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString().c_str());
65f0bfeaa8Sopenharmony_ci}
66f0bfeaa8Sopenharmony_ci
67f0bfeaa8Sopenharmony_ciPurgeableMem::~PurgeableMem()
68f0bfeaa8Sopenharmony_ci{
69f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
70f0bfeaa8Sopenharmony_ci    if (dataPtr_) {
71f0bfeaa8Sopenharmony_ci        if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
72f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
73f0bfeaa8Sopenharmony_ci        } else {
74f0bfeaa8Sopenharmony_ci            if (UxpteIsEnabled() && !IsPurged()) {
75f0bfeaa8Sopenharmony_ci                PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__);
76f0bfeaa8Sopenharmony_ci            }
77f0bfeaa8Sopenharmony_ci            dataPtr_ = nullptr;
78f0bfeaa8Sopenharmony_ci        }
79f0bfeaa8Sopenharmony_ci    }
80f0bfeaa8Sopenharmony_ci    builder_.reset();
81f0bfeaa8Sopenharmony_ci    pageTable_.reset();
82f0bfeaa8Sopenharmony_ci}
83f0bfeaa8Sopenharmony_ci
84f0bfeaa8Sopenharmony_cibool PurgeableMem::IsPurged()
85f0bfeaa8Sopenharmony_ci{
86f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false);
87f0bfeaa8Sopenharmony_ci    return !(pageTable_->CheckPresent((uint64_t)dataPtr_, dataSizeInput_));
88f0bfeaa8Sopenharmony_ci}
89f0bfeaa8Sopenharmony_ci
90f0bfeaa8Sopenharmony_cibool PurgeableMem::CreatePurgeableData()
91f0bfeaa8Sopenharmony_ci{
92f0bfeaa8Sopenharmony_ci    PM_HILOG_DEBUG(LOG_CORE, "%{public}s", __func__);
93f0bfeaa8Sopenharmony_ci    pageTable_ = nullptr;
94f0bfeaa8Sopenharmony_ci    size_t size = RoundUp(dataSizeInput_, PAGE_SIZE);
95f0bfeaa8Sopenharmony_ci    unsigned int utype = MAP_ANONYMOUS;
96f0bfeaa8Sopenharmony_ci    utype |= (UxpteIsEnabled() ? MAP_PURGEABLE : MAP_PRIVATE);
97f0bfeaa8Sopenharmony_ci    int type = static_cast<int>(utype);
98f0bfeaa8Sopenharmony_ci
99f0bfeaa8Sopenharmony_ci    dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, type, -1, 0);
100f0bfeaa8Sopenharmony_ci    if (dataPtr_ == MAP_FAILED) {
101f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR(LOG_CORE, "%{public}s: mmap fail", __func__);
102f0bfeaa8Sopenharmony_ci        dataPtr_ = nullptr;
103f0bfeaa8Sopenharmony_ci        return false;
104f0bfeaa8Sopenharmony_ci    }
105f0bfeaa8Sopenharmony_ci    MAKE_UNIQUE(pageTable_, UxPageTable, "constructor uxpt make_unique fail", return false, (uint64_t)dataPtr_, size);
106f0bfeaa8Sopenharmony_ci    return true;
107f0bfeaa8Sopenharmony_ci}
108f0bfeaa8Sopenharmony_ci
109f0bfeaa8Sopenharmony_cibool PurgeableMem::Pin()
110f0bfeaa8Sopenharmony_ci{
111f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false);
112f0bfeaa8Sopenharmony_ci    pageTable_->GetUxpte((uint64_t)dataPtr_, dataSizeInput_);
113f0bfeaa8Sopenharmony_ci    return true;
114f0bfeaa8Sopenharmony_ci}
115f0bfeaa8Sopenharmony_ci
116f0bfeaa8Sopenharmony_cibool PurgeableMem::Unpin()
117f0bfeaa8Sopenharmony_ci{
118f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false);
119f0bfeaa8Sopenharmony_ci    pageTable_->PutUxpte((uint64_t)dataPtr_, dataSizeInput_);
120f0bfeaa8Sopenharmony_ci    return true;
121f0bfeaa8Sopenharmony_ci}
122f0bfeaa8Sopenharmony_ci
123f0bfeaa8Sopenharmony_civoid PurgeableMem::AfterRebuildSucc()
124f0bfeaa8Sopenharmony_ci{
125f0bfeaa8Sopenharmony_ci}
126f0bfeaa8Sopenharmony_ci
127f0bfeaa8Sopenharmony_ciint PurgeableMem::GetPinStatus() const
128f0bfeaa8Sopenharmony_ci{
129f0bfeaa8Sopenharmony_ci    return 0;
130f0bfeaa8Sopenharmony_ci}
131f0bfeaa8Sopenharmony_ci
132f0bfeaa8Sopenharmony_civoid PurgeableMem::ResizeData(size_t newSize)
133f0bfeaa8Sopenharmony_ci{
134f0bfeaa8Sopenharmony_ci    if (newSize <= 0 || newSize >= OHOS_MAXIMUM_PURGEABLE_MEMORY) {
135f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to apply for memory");
136f0bfeaa8Sopenharmony_ci        return;
137f0bfeaa8Sopenharmony_ci    }
138f0bfeaa8Sopenharmony_ci    if (dataPtr_) {
139f0bfeaa8Sopenharmony_ci        if (munmap(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE)) != 0) {
140f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
141f0bfeaa8Sopenharmony_ci        } else {
142f0bfeaa8Sopenharmony_ci            dataPtr_ = nullptr;
143f0bfeaa8Sopenharmony_ci        }
144f0bfeaa8Sopenharmony_ci    }
145f0bfeaa8Sopenharmony_ci    dataSizeInput_ = newSize;
146f0bfeaa8Sopenharmony_ci    if (!CreatePurgeableData()) {
147f0bfeaa8Sopenharmony_ci        PM_HILOG_DEBUG(LOG_CORE, "Failed to create purgeabledata");
148f0bfeaa8Sopenharmony_ci        return;
149f0bfeaa8Sopenharmony_ci    }
150f0bfeaa8Sopenharmony_ci}
151f0bfeaa8Sopenharmony_ci
152f0bfeaa8Sopenharmony_ciinline std::string PurgeableMem::ToString() const
153f0bfeaa8Sopenharmony_ci{
154f0bfeaa8Sopenharmony_ci    std::string dataptrStr = dataPtr_ ? std::to_string((unsigned long long)dataPtr_) : "0";
155f0bfeaa8Sopenharmony_ci    std::string pageTableStr = pageTable_ ? pageTable_->ToString() : "0";
156f0bfeaa8Sopenharmony_ci    return "dataAddr:" + dataptrStr + " dataSizeInput:" + std::to_string(dataSizeInput_) +
157f0bfeaa8Sopenharmony_ci        " " + pageTableStr;
158f0bfeaa8Sopenharmony_ci}
159f0bfeaa8Sopenharmony_ci} /* namespace PurgeableMem */
160f0bfeaa8Sopenharmony_ci} /* namespace OHOS */
161