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 <stdlib.h> /* malloc */
17f0bfeaa8Sopenharmony_ci#include <sys/mman.h> /* mmap */
18f0bfeaa8Sopenharmony_ci#include <pthread.h>
19f0bfeaa8Sopenharmony_ci#include <stdio.h> /* FILE */
20f0bfeaa8Sopenharmony_ci
21f0bfeaa8Sopenharmony_ci#include "securec.h"
22f0bfeaa8Sopenharmony_ci#include "pm_ptr_util.h"
23f0bfeaa8Sopenharmony_ci#include "pm_util.h"
24f0bfeaa8Sopenharmony_ci#include "pm_state_c.h"
25f0bfeaa8Sopenharmony_ci#include "ux_page_table_c.h"
26f0bfeaa8Sopenharmony_ci#include "purgeable_mem_builder_c.h"
27f0bfeaa8Sopenharmony_ci#include "pm_log_c.h"
28f0bfeaa8Sopenharmony_ci#include "purgeable_mem_c.h"
29f0bfeaa8Sopenharmony_ci
30f0bfeaa8Sopenharmony_ci#undef LOG_TAG
31f0bfeaa8Sopenharmony_ci#define LOG_TAG "PurgeableMemC"
32f0bfeaa8Sopenharmony_ci
33f0bfeaa8Sopenharmony_cistruct PurgMem {
34f0bfeaa8Sopenharmony_ci    void *dataPtr;
35f0bfeaa8Sopenharmony_ci    size_t dataSizeInput;
36f0bfeaa8Sopenharmony_ci    struct PurgMemBuilder *builder;
37f0bfeaa8Sopenharmony_ci    UxPageTableStruct *uxPageTable;
38f0bfeaa8Sopenharmony_ci    pthread_rwlock_t rwlock;
39f0bfeaa8Sopenharmony_ci    unsigned int buildDataCount;
40f0bfeaa8Sopenharmony_ci};
41f0bfeaa8Sopenharmony_ci
42f0bfeaa8Sopenharmony_cistatic inline void LogPurgMemInfo(struct PurgMem *obj)
43f0bfeaa8Sopenharmony_ci{
44f0bfeaa8Sopenharmony_ci    if (obj == NULL) {
45f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: obj is NULL!", __func__);
46f0bfeaa8Sopenharmony_ci        return;
47f0bfeaa8Sopenharmony_ci    }
48f0bfeaa8Sopenharmony_ci    PM_HILOG_INFO_C(LOG_CORE, "purgMemObj(%{public}lx) dataPtr(%{public}lx) dataSizeInput(%{public}zu)"
49f0bfeaa8Sopenharmony_ci        " builderPtr(%{public}lx) uxpt(%{public}lx)",
50f0bfeaa8Sopenharmony_ci        (unsigned long)obj, (unsigned long)(obj->dataPtr), obj->dataSizeInput,
51f0bfeaa8Sopenharmony_ci        (unsigned long)(obj->builder), (unsigned long)(obj->uxPageTable));
52f0bfeaa8Sopenharmony_ci}
53f0bfeaa8Sopenharmony_ci
54f0bfeaa8Sopenharmony_cistatic inline size_t RoundUp(size_t val, size_t align)
55f0bfeaa8Sopenharmony_ci{
56f0bfeaa8Sopenharmony_ci    if (val + align < val || val + align < align) {
57f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: Addition overflow!", __func__);
58f0bfeaa8Sopenharmony_ci        return val;
59f0bfeaa8Sopenharmony_ci    }
60f0bfeaa8Sopenharmony_ci    if (align == 0) {
61f0bfeaa8Sopenharmony_ci        return val;
62f0bfeaa8Sopenharmony_ci    }
63f0bfeaa8Sopenharmony_ci    return ((val + align - 1) / align) * align;
64f0bfeaa8Sopenharmony_ci}
65f0bfeaa8Sopenharmony_ci
66f0bfeaa8Sopenharmony_cistatic bool IsPurgMemPtrValid(struct PurgMem *purgObj);
67f0bfeaa8Sopenharmony_cistatic bool IsPurged(struct PurgMem *purgObj);
68f0bfeaa8Sopenharmony_cistatic int TypeCast(void);
69f0bfeaa8Sopenharmony_ci
70f0bfeaa8Sopenharmony_cistatic struct PurgMem *PurgMemCreate_(size_t len, struct PurgMemBuilder *builder)
71f0bfeaa8Sopenharmony_ci{
72f0bfeaa8Sopenharmony_ci    /* PurgMemObj allow no builder temporaily */
73f0bfeaa8Sopenharmony_ci    struct PurgMem *pugObj = NULL;
74f0bfeaa8Sopenharmony_ci    pugObj = (struct PurgMem *)malloc(sizeof(struct PurgMem));
75f0bfeaa8Sopenharmony_ci    if (!pugObj) {
76f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: malloc struct PurgMem fail", __func__);
77f0bfeaa8Sopenharmony_ci        return NULL;
78f0bfeaa8Sopenharmony_ci    }
79f0bfeaa8Sopenharmony_ci    size_t size = RoundUp(len, PAGE_SIZE);
80f0bfeaa8Sopenharmony_ci    int type = TypeCast();
81f0bfeaa8Sopenharmony_ci    pugObj->dataPtr = mmap(NULL, size, PROT_READ | PROT_WRITE, type, -1, 0);
82f0bfeaa8Sopenharmony_ci    if (pugObj->dataPtr == MAP_FAILED) {
83f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: mmap dataPtr fail", __func__);
84f0bfeaa8Sopenharmony_ci        pugObj->dataPtr = NULL;
85f0bfeaa8Sopenharmony_ci        goto free_pug_obj;
86f0bfeaa8Sopenharmony_ci    }
87f0bfeaa8Sopenharmony_ci
88f0bfeaa8Sopenharmony_ci    pugObj->uxPageTable = (UxPageTableStruct *)malloc(UxPageTableSize());
89f0bfeaa8Sopenharmony_ci    if (!(pugObj->uxPageTable)) {
90f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: malloc UxPageTableStruct fail", __func__);
91f0bfeaa8Sopenharmony_ci        goto unmap_data;
92f0bfeaa8Sopenharmony_ci    }
93f0bfeaa8Sopenharmony_ci    PMState err = InitUxPageTable(pugObj->uxPageTable, (uint64_t)(pugObj->dataPtr), size); /* dataPtr is aligned */
94f0bfeaa8Sopenharmony_ci    if (err != PM_OK) {
95f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE,
96f0bfeaa8Sopenharmony_ci            "%{public}s: InitUxPageTable fail, %{public}s", __func__, GetPMStateName(err));
97f0bfeaa8Sopenharmony_ci        goto free_uxpt;
98f0bfeaa8Sopenharmony_ci    }
99f0bfeaa8Sopenharmony_ci    int lockInitRet = pthread_rwlock_init(&(pugObj->rwlock), NULL);
100f0bfeaa8Sopenharmony_ci    if (lockInitRet != 0) {
101f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: pthread_rwlock_init fail, %{public}d", __func__, lockInitRet);
102f0bfeaa8Sopenharmony_ci        goto deinit_upt;
103f0bfeaa8Sopenharmony_ci    }
104f0bfeaa8Sopenharmony_ci    pugObj->builder = builder;
105f0bfeaa8Sopenharmony_ci    pugObj->dataSizeInput = len;
106f0bfeaa8Sopenharmony_ci    pugObj->buildDataCount = 0;
107f0bfeaa8Sopenharmony_ci
108f0bfeaa8Sopenharmony_ci    PM_HILOG_INFO_C(LOG_CORE, "%{public}s: LogPurgMemInfo:", __func__);
109f0bfeaa8Sopenharmony_ci    LogPurgMemInfo(pugObj);
110f0bfeaa8Sopenharmony_ci    return pugObj;
111f0bfeaa8Sopenharmony_ci
112f0bfeaa8Sopenharmony_cideinit_upt:
113f0bfeaa8Sopenharmony_ci    DeinitUxPageTable(pugObj->uxPageTable);
114f0bfeaa8Sopenharmony_cifree_uxpt:
115f0bfeaa8Sopenharmony_ci    free(pugObj->uxPageTable);
116f0bfeaa8Sopenharmony_ci    pugObj->uxPageTable = NULL;
117f0bfeaa8Sopenharmony_ciunmap_data:
118f0bfeaa8Sopenharmony_ci    munmap(pugObj->dataPtr, size);
119f0bfeaa8Sopenharmony_ci    pugObj->dataPtr = NULL;
120f0bfeaa8Sopenharmony_cifree_pug_obj:
121f0bfeaa8Sopenharmony_ci    free(pugObj);
122f0bfeaa8Sopenharmony_ci    pugObj = NULL;
123f0bfeaa8Sopenharmony_ci
124f0bfeaa8Sopenharmony_ci    return NULL;
125f0bfeaa8Sopenharmony_ci}
126f0bfeaa8Sopenharmony_ci
127f0bfeaa8Sopenharmony_cistruct PurgMem *PurgMemCreate(size_t len, PurgMemModifyFunc func, void *funcPara)
128f0bfeaa8Sopenharmony_ci{
129f0bfeaa8Sopenharmony_ci    if (len == 0) {
130f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: input len 0", __func__);
131f0bfeaa8Sopenharmony_ci        return NULL;
132f0bfeaa8Sopenharmony_ci    }
133f0bfeaa8Sopenharmony_ci    /* a PurgMemObj must have builder */
134f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(func, "%{public}s: input func is NULL", return NULL);
135f0bfeaa8Sopenharmony_ci    struct PurgMem *purgMemObj = PurgMemCreate_(len, NULL);
136f0bfeaa8Sopenharmony_ci    /* create fail */
137f0bfeaa8Sopenharmony_ci    if (!purgMemObj) {
138f0bfeaa8Sopenharmony_ci        return purgMemObj;
139f0bfeaa8Sopenharmony_ci    }
140f0bfeaa8Sopenharmony_ci
141f0bfeaa8Sopenharmony_ci    if (PurgMemAppendModify(purgMemObj, func, funcPara)) {
142f0bfeaa8Sopenharmony_ci        return purgMemObj;
143f0bfeaa8Sopenharmony_ci    }
144f0bfeaa8Sopenharmony_ci
145f0bfeaa8Sopenharmony_ci    /* append func fail meas create builder failed */
146f0bfeaa8Sopenharmony_ci    PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: append mod func fail", __func__);
147f0bfeaa8Sopenharmony_ci    if (!PurgMemDestroy(purgMemObj)) {
148f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: destroy PurgMem fail after append modFunc fail", __func__);
149f0bfeaa8Sopenharmony_ci    }
150f0bfeaa8Sopenharmony_ci    return NULL;
151f0bfeaa8Sopenharmony_ci}
152f0bfeaa8Sopenharmony_ci
153f0bfeaa8Sopenharmony_cibool PurgMemDestroy(struct PurgMem *purgObj)
154f0bfeaa8Sopenharmony_ci{
155f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(purgObj, "input is NULL", return true);
156f0bfeaa8Sopenharmony_ci    PM_HILOG_INFO_C(LOG_CORE, "%{public}s: LogPurgMemInfo:", __func__);
157f0bfeaa8Sopenharmony_ci    LogPurgMemInfo(purgObj);
158f0bfeaa8Sopenharmony_ci
159f0bfeaa8Sopenharmony_ci    PMState err = PM_OK;
160f0bfeaa8Sopenharmony_ci    /* destroy rwlock */
161f0bfeaa8Sopenharmony_ci    int ret = pthread_rwlock_destroy(&(purgObj->rwlock));
162f0bfeaa8Sopenharmony_ci    if (ret != 0) {
163f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: pthread_rwlock_destroy fail, %{public}d", __func__, ret);
164f0bfeaa8Sopenharmony_ci    }
165f0bfeaa8Sopenharmony_ci    /* destroy builder */
166f0bfeaa8Sopenharmony_ci    if (purgObj->builder) {
167f0bfeaa8Sopenharmony_ci        if (!PurgMemBuilderDestroy(purgObj->builder)) {
168f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: PurgMemBuilderDestroy fail", __func__);
169f0bfeaa8Sopenharmony_ci            err = PMB_DESTORY_FAIL;
170f0bfeaa8Sopenharmony_ci        } else {
171f0bfeaa8Sopenharmony_ci            purgObj->builder = NULL;
172f0bfeaa8Sopenharmony_ci        }
173f0bfeaa8Sopenharmony_ci    }
174f0bfeaa8Sopenharmony_ci    /* unmap purgeable mem region */
175f0bfeaa8Sopenharmony_ci    if (purgObj->dataPtr) {
176f0bfeaa8Sopenharmony_ci        size_t size = RoundUp(purgObj->dataSizeInput, PAGE_SIZE);
177f0bfeaa8Sopenharmony_ci        if (munmap(purgObj->dataPtr, size) != 0) {
178f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__);
179f0bfeaa8Sopenharmony_ci            err = PM_UNMAP_PURG_FAIL;
180f0bfeaa8Sopenharmony_ci        } else {
181f0bfeaa8Sopenharmony_ci            /* double check munmap result: if uxpte is set to no_present */
182f0bfeaa8Sopenharmony_ci            if (UxpteIsEnabled() && !IsPurged(purgObj)) {
183f0bfeaa8Sopenharmony_ci                PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__);
184f0bfeaa8Sopenharmony_ci                err = PM_UXPT_PRESENT_DATA_PURGED;
185f0bfeaa8Sopenharmony_ci            }
186f0bfeaa8Sopenharmony_ci            purgObj->dataPtr = NULL;
187f0bfeaa8Sopenharmony_ci        }
188f0bfeaa8Sopenharmony_ci    }
189f0bfeaa8Sopenharmony_ci    /* unmap uxpt */
190f0bfeaa8Sopenharmony_ci    if (purgObj->uxPageTable) {
191f0bfeaa8Sopenharmony_ci        PMState deinitRet = DeinitUxPageTable(purgObj->uxPageTable);
192f0bfeaa8Sopenharmony_ci        if (deinitRet != PM_OK) {
193f0bfeaa8Sopenharmony_ci            PM_HILOG_ERROR_C(LOG_CORE,
194f0bfeaa8Sopenharmony_ci                "%{public}s: deinit upt fail, %{public}s", __func__, GetPMStateName(deinitRet));
195f0bfeaa8Sopenharmony_ci            err = deinitRet;
196f0bfeaa8Sopenharmony_ci        } else {
197f0bfeaa8Sopenharmony_ci            free(purgObj->uxPageTable);
198f0bfeaa8Sopenharmony_ci            purgObj->uxPageTable = NULL;
199f0bfeaa8Sopenharmony_ci        }
200f0bfeaa8Sopenharmony_ci    }
201f0bfeaa8Sopenharmony_ci
202f0bfeaa8Sopenharmony_ci    if (err == PM_OK) {
203f0bfeaa8Sopenharmony_ci        free(purgObj);
204f0bfeaa8Sopenharmony_ci        purgObj = NULL; /* set input para NULL to avoid UAF */
205f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: succ", __func__);
206f0bfeaa8Sopenharmony_ci        return true;
207f0bfeaa8Sopenharmony_ci    }
208f0bfeaa8Sopenharmony_ci    PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: fail, %{public}s", __func__, GetPMStateName(err));
209f0bfeaa8Sopenharmony_ci    return false;
210f0bfeaa8Sopenharmony_ci}
211f0bfeaa8Sopenharmony_ci
212f0bfeaa8Sopenharmony_cistatic bool IsPurgMemPtrValid(struct PurgMem *purgObj)
213f0bfeaa8Sopenharmony_ci{
214f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(purgObj, "obj is NULL", return false);
215f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(purgObj->dataPtr, "dataPtr is NULL", return false);
216f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(purgObj->uxPageTable, "pageTable is NULL", return false);
217f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(purgObj->builder, "builder is NULL", return false);
218f0bfeaa8Sopenharmony_ci
219f0bfeaa8Sopenharmony_ci    return true;
220f0bfeaa8Sopenharmony_ci}
221f0bfeaa8Sopenharmony_ci
222f0bfeaa8Sopenharmony_cistatic inline bool PurgMemBuildData(struct PurgMem *purgObj)
223f0bfeaa8Sopenharmony_ci{
224f0bfeaa8Sopenharmony_ci    bool succ = false;
225f0bfeaa8Sopenharmony_ci    /* clear content before rebuild */
226f0bfeaa8Sopenharmony_ci    if (memset_s(purgObj->dataPtr, RoundUp(purgObj->dataSizeInput, PAGE_SIZE), 0, purgObj->dataSizeInput) != EOK) {
227f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s, clear content fail", __func__);
228f0bfeaa8Sopenharmony_ci        return succ;
229f0bfeaa8Sopenharmony_ci    }
230f0bfeaa8Sopenharmony_ci    /* @purgObj->builder is not NULL since it is checked by IsPurgMemPtrValid() before */
231f0bfeaa8Sopenharmony_ci    succ = PurgMemBuilderBuildAll(purgObj->builder, purgObj->dataPtr, purgObj->dataSizeInput);
232f0bfeaa8Sopenharmony_ci    if (succ) {
233f0bfeaa8Sopenharmony_ci        purgObj->buildDataCount++;
234f0bfeaa8Sopenharmony_ci    }
235f0bfeaa8Sopenharmony_ci    return succ;
236f0bfeaa8Sopenharmony_ci}
237f0bfeaa8Sopenharmony_ci
238f0bfeaa8Sopenharmony_cistatic PMState TryBeginRead(struct PurgMem *purgObj)
239f0bfeaa8Sopenharmony_ci{
240f0bfeaa8Sopenharmony_ci    int rwlockRet = pthread_rwlock_rdlock(&(purgObj->rwlock));
241f0bfeaa8Sopenharmony_ci    if (rwlockRet != 0) {
242f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: rdlock fail. %{public}d", __func__, rwlockRet);
243f0bfeaa8Sopenharmony_ci        return PM_LOCK_READ_FAIL;
244f0bfeaa8Sopenharmony_ci    }
245f0bfeaa8Sopenharmony_ci
246f0bfeaa8Sopenharmony_ci    if (!IsPurged(purgObj)) {
247f0bfeaa8Sopenharmony_ci        PM_HILOG_INFO_C(LOG_CORE,
248f0bfeaa8Sopenharmony_ci            "%{public}s: not purged, return true. MAP_PUG=0x%{public}x", __func__, MAP_PURGEABLE);
249f0bfeaa8Sopenharmony_ci        return PM_DATA_NO_PURGED;
250f0bfeaa8Sopenharmony_ci    }
251f0bfeaa8Sopenharmony_ci
252f0bfeaa8Sopenharmony_ci    rwlockRet = pthread_rwlock_unlock(&(purgObj->rwlock));
253f0bfeaa8Sopenharmony_ci    if (rwlockRet != 0) {
254f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: rd unlock fail. %{public}d", __func__, rwlockRet);
255f0bfeaa8Sopenharmony_ci        return PM_UNLOCK_READ_FAIL;
256f0bfeaa8Sopenharmony_ci    }
257f0bfeaa8Sopenharmony_ci
258f0bfeaa8Sopenharmony_ci    return PM_DATA_PURGED;
259f0bfeaa8Sopenharmony_ci}
260f0bfeaa8Sopenharmony_ci
261f0bfeaa8Sopenharmony_cistatic PMState BeginReadBuildData(struct PurgMem *purgObj)
262f0bfeaa8Sopenharmony_ci{
263f0bfeaa8Sopenharmony_ci    bool rebuildRet = false;
264f0bfeaa8Sopenharmony_ci    int rwlockRet = pthread_rwlock_wrlock(&(purgObj->rwlock));
265f0bfeaa8Sopenharmony_ci    if (rwlockRet) {
266f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: wrlock fail. %{public}d", __func__, rwlockRet);
267f0bfeaa8Sopenharmony_ci        return PM_LOCK_WRITE_FAIL;
268f0bfeaa8Sopenharmony_ci    }
269f0bfeaa8Sopenharmony_ci
270f0bfeaa8Sopenharmony_ci    if (IsPurged(purgObj)) {
271f0bfeaa8Sopenharmony_ci        rebuildRet = PurgMemBuildData(purgObj);
272f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE,
273f0bfeaa8Sopenharmony_ci            "%{public}s: purged, after built %{public}s", __func__, rebuildRet ? "succ" : "fail");
274f0bfeaa8Sopenharmony_ci    }
275f0bfeaa8Sopenharmony_ci
276f0bfeaa8Sopenharmony_ci    rwlockRet = pthread_rwlock_unlock(&(purgObj->rwlock));
277f0bfeaa8Sopenharmony_ci    if (rwlockRet != 0) {
278f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: wr unlock fail. %{public}d", __func__, rwlockRet);
279f0bfeaa8Sopenharmony_ci        return PM_UNLOCK_WRITE_FAIL;
280f0bfeaa8Sopenharmony_ci    }
281f0bfeaa8Sopenharmony_ci
282f0bfeaa8Sopenharmony_ci    if (!rebuildRet) {
283f0bfeaa8Sopenharmony_ci        return PMB_BUILD_ALL_FAIL;
284f0bfeaa8Sopenharmony_ci    }
285f0bfeaa8Sopenharmony_ci
286f0bfeaa8Sopenharmony_ci    return PMB_BUILD_ALL_SUCC;
287f0bfeaa8Sopenharmony_ci}
288f0bfeaa8Sopenharmony_ci
289f0bfeaa8Sopenharmony_cibool PurgMemBeginRead(struct PurgMem *purgObj)
290f0bfeaa8Sopenharmony_ci{
291f0bfeaa8Sopenharmony_ci    if (!IsPurgMemPtrValid(purgObj)) {
292f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: para is invalid", __func__);
293f0bfeaa8Sopenharmony_ci        return false;
294f0bfeaa8Sopenharmony_ci    }
295f0bfeaa8Sopenharmony_ci    PM_HILOG_INFO_C(LOG_CORE, "%{public}s: LogPurgMemInfo:", __func__);
296f0bfeaa8Sopenharmony_ci    LogPurgMemInfo(purgObj);
297f0bfeaa8Sopenharmony_ci    bool ret = false;
298f0bfeaa8Sopenharmony_ci    PMState err = PM_OK;
299f0bfeaa8Sopenharmony_ci    UxpteGet(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput);
300f0bfeaa8Sopenharmony_ci    while (true) {
301f0bfeaa8Sopenharmony_ci        err = TryBeginRead(purgObj);
302f0bfeaa8Sopenharmony_ci        if (err == PM_DATA_NO_PURGED) {
303f0bfeaa8Sopenharmony_ci            ret = true;
304f0bfeaa8Sopenharmony_ci            break;
305f0bfeaa8Sopenharmony_ci        } else if (err != PM_DATA_PURGED) {
306f0bfeaa8Sopenharmony_ci            break;
307f0bfeaa8Sopenharmony_ci        }
308f0bfeaa8Sopenharmony_ci
309f0bfeaa8Sopenharmony_ci        err = BeginReadBuildData(purgObj);
310f0bfeaa8Sopenharmony_ci        if (err != PMB_BUILD_ALL_SUCC) {
311f0bfeaa8Sopenharmony_ci            ret = false;
312f0bfeaa8Sopenharmony_ci            break;
313f0bfeaa8Sopenharmony_ci        }
314f0bfeaa8Sopenharmony_ci    }
315f0bfeaa8Sopenharmony_ci
316f0bfeaa8Sopenharmony_ci    if (!ret) {
317f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: %{public}s, UxptePut.", __func__, GetPMStateName(err));
318f0bfeaa8Sopenharmony_ci        UxptePut(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput);
319f0bfeaa8Sopenharmony_ci    }
320f0bfeaa8Sopenharmony_ci    return ret;
321f0bfeaa8Sopenharmony_ci}
322f0bfeaa8Sopenharmony_ci
323f0bfeaa8Sopenharmony_cibool PurgMemBeginWrite(struct PurgMem *purgObj)
324f0bfeaa8Sopenharmony_ci{
325f0bfeaa8Sopenharmony_ci    if (!IsPurgMemPtrValid(purgObj)) {
326f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: para is invalid", __func__);
327f0bfeaa8Sopenharmony_ci        return false;
328f0bfeaa8Sopenharmony_ci    }
329f0bfeaa8Sopenharmony_ci    PM_HILOG_INFO_C(LOG_CORE, "%{public}s: LogPurgMemInfo:", __func__);
330f0bfeaa8Sopenharmony_ci    LogPurgMemInfo(purgObj);
331f0bfeaa8Sopenharmony_ci    int rwlockRet = 0;
332f0bfeaa8Sopenharmony_ci    bool rebuildRet = false;
333f0bfeaa8Sopenharmony_ci    PMState err = PM_OK;
334f0bfeaa8Sopenharmony_ci
335f0bfeaa8Sopenharmony_ci    UxpteGet(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput);
336f0bfeaa8Sopenharmony_ci
337f0bfeaa8Sopenharmony_ci    rwlockRet = pthread_rwlock_wrlock(&(purgObj->rwlock));
338f0bfeaa8Sopenharmony_ci    if (rwlockRet != 0) {
339f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: wrlock fail. %{public}d", __func__, rwlockRet);
340f0bfeaa8Sopenharmony_ci        err = PM_LOCK_WRITE_FAIL;
341f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: %{public}s, return false, UxptePut.", __func__, GetPMStateName(err));
342f0bfeaa8Sopenharmony_ci        UxptePut(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput);
343f0bfeaa8Sopenharmony_ci        return false;
344f0bfeaa8Sopenharmony_ci    }
345f0bfeaa8Sopenharmony_ci
346f0bfeaa8Sopenharmony_ci    if (!IsPurged(purgObj)) {
347f0bfeaa8Sopenharmony_ci        return true;
348f0bfeaa8Sopenharmony_ci    }
349f0bfeaa8Sopenharmony_ci
350f0bfeaa8Sopenharmony_ci    /* data is purged */
351f0bfeaa8Sopenharmony_ci    rebuildRet = PurgMemBuildData(purgObj);
352f0bfeaa8Sopenharmony_ci    PM_HILOG_INFO_C(LOG_CORE, "%{public}s: purged, built %{public}s", __func__, rebuildRet ? "succ" : "fail");
353f0bfeaa8Sopenharmony_ci    if (rebuildRet) {
354f0bfeaa8Sopenharmony_ci        return true;
355f0bfeaa8Sopenharmony_ci    }
356f0bfeaa8Sopenharmony_ci    /* data is purged and rebuild failed. return false */
357f0bfeaa8Sopenharmony_ci    err = PMB_BUILD_ALL_FAIL;
358f0bfeaa8Sopenharmony_ci    rwlockRet = pthread_rwlock_unlock(&(purgObj->rwlock));
359f0bfeaa8Sopenharmony_ci    if (rwlockRet != 0) {
360f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: wr unlock fail. %{public}d", __func__, rwlockRet);
361f0bfeaa8Sopenharmony_ci    }
362f0bfeaa8Sopenharmony_ci
363f0bfeaa8Sopenharmony_ci    PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: %{public}s, return false, UxptePut.", __func__, GetPMStateName(err));
364f0bfeaa8Sopenharmony_ci    UxptePut(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput);
365f0bfeaa8Sopenharmony_ci    return false;
366f0bfeaa8Sopenharmony_ci}
367f0bfeaa8Sopenharmony_ci
368f0bfeaa8Sopenharmony_cistatic inline void EndAccessPurgMem(struct PurgMem *purgObj)
369f0bfeaa8Sopenharmony_ci{
370f0bfeaa8Sopenharmony_ci    if (!IsPurgMemPtrValid(purgObj)) {
371f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: para is invalid", __func__);
372f0bfeaa8Sopenharmony_ci        return;
373f0bfeaa8Sopenharmony_ci    }
374f0bfeaa8Sopenharmony_ci    int rwlockRet = 0;
375f0bfeaa8Sopenharmony_ci    rwlockRet = pthread_rwlock_unlock(&(purgObj->rwlock));
376f0bfeaa8Sopenharmony_ci    if (rwlockRet != 0) {
377f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: unlock fail. %{public}d", __func__, rwlockRet);
378f0bfeaa8Sopenharmony_ci    }
379f0bfeaa8Sopenharmony_ci    UxptePut(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput);
380f0bfeaa8Sopenharmony_ci}
381f0bfeaa8Sopenharmony_ci
382f0bfeaa8Sopenharmony_civoid PurgMemEndRead(struct PurgMem *purgObj)
383f0bfeaa8Sopenharmony_ci{
384f0bfeaa8Sopenharmony_ci    EndAccessPurgMem(purgObj);
385f0bfeaa8Sopenharmony_ci}
386f0bfeaa8Sopenharmony_ci
387f0bfeaa8Sopenharmony_civoid PurgMemEndWrite(struct PurgMem *purgObj)
388f0bfeaa8Sopenharmony_ci{
389f0bfeaa8Sopenharmony_ci    EndAccessPurgMem(purgObj);
390f0bfeaa8Sopenharmony_ci}
391f0bfeaa8Sopenharmony_ci
392f0bfeaa8Sopenharmony_civoid *PurgMemGetContent(struct PurgMem *purgObj)
393f0bfeaa8Sopenharmony_ci{
394f0bfeaa8Sopenharmony_ci    if (!IsPurgMemPtrValid(purgObj)) {
395f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: para is invalid", __func__);
396f0bfeaa8Sopenharmony_ci        return NULL;
397f0bfeaa8Sopenharmony_ci    }
398f0bfeaa8Sopenharmony_ci    return purgObj->dataPtr;
399f0bfeaa8Sopenharmony_ci}
400f0bfeaa8Sopenharmony_ci
401f0bfeaa8Sopenharmony_cisize_t PurgMemGetContentSize(struct PurgMem *purgObj)
402f0bfeaa8Sopenharmony_ci{
403f0bfeaa8Sopenharmony_ci    if (!IsPurgMemPtrValid(purgObj)) {
404f0bfeaa8Sopenharmony_ci        PM_HILOG_ERROR_C(LOG_CORE, "%{public}s: para is invalid", __func__);
405f0bfeaa8Sopenharmony_ci        return 0;
406f0bfeaa8Sopenharmony_ci    }
407f0bfeaa8Sopenharmony_ci    return purgObj->dataSizeInput;
408f0bfeaa8Sopenharmony_ci}
409f0bfeaa8Sopenharmony_ci
410f0bfeaa8Sopenharmony_cibool PurgMemAppendModify(struct PurgMem *purgObj, PurgMemModifyFunc func, void *funcPara)
411f0bfeaa8Sopenharmony_ci{
412f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(func, "input func is NULL", return true);
413f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(purgObj, "input purgObj is NULL", return false);
414f0bfeaa8Sopenharmony_ci    /* apply modify */
415f0bfeaa8Sopenharmony_ci    bool succ = func(purgObj->dataPtr, purgObj->dataSizeInput, funcPara);
416f0bfeaa8Sopenharmony_ci    if (!succ) {
417f0bfeaa8Sopenharmony_ci        return false;
418f0bfeaa8Sopenharmony_ci    }
419f0bfeaa8Sopenharmony_ci    struct PurgMemBuilder *builder = PurgMemBuilderCreate(func, funcPara, NULL);
420f0bfeaa8Sopenharmony_ci    IF_NULL_LOG_ACTION(builder, "PurgMemBuilderCreate fail", return false);
421f0bfeaa8Sopenharmony_ci
422f0bfeaa8Sopenharmony_ci    if (purgObj->builder == NULL) { /* PurgMemObj has no builder previous */
423f0bfeaa8Sopenharmony_ci        purgObj->builder = builder;
424f0bfeaa8Sopenharmony_ci        return true;
425f0bfeaa8Sopenharmony_ci    }
426f0bfeaa8Sopenharmony_ci    return PurgMemBuilderAppendBuilder(purgObj->builder, builder);
427f0bfeaa8Sopenharmony_ci}
428f0bfeaa8Sopenharmony_ci
429f0bfeaa8Sopenharmony_cistatic bool IsPurged(struct PurgMem *purgObj)
430f0bfeaa8Sopenharmony_ci{
431f0bfeaa8Sopenharmony_ci    /* first access, return true means purged */
432f0bfeaa8Sopenharmony_ci    if (purgObj->buildDataCount == 0) {
433f0bfeaa8Sopenharmony_ci        PM_HILOG_INFO_C(LOG_CORE, "%{public}s, has never built, return true", __func__);
434f0bfeaa8Sopenharmony_ci        return true;
435f0bfeaa8Sopenharmony_ci    }
436f0bfeaa8Sopenharmony_ci    return !UxpteIsPresent(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput);
437f0bfeaa8Sopenharmony_ci}
438f0bfeaa8Sopenharmony_ci
439f0bfeaa8Sopenharmony_cistatic int TypeCast(void)
440f0bfeaa8Sopenharmony_ci{
441f0bfeaa8Sopenharmony_ci    unsigned int utype = MAP_ANONYMOUS;
442f0bfeaa8Sopenharmony_ci    utype |= (UxpteIsEnabled() ? MAP_PURGEABLE : MAP_PRIVATE);
443f0bfeaa8Sopenharmony_ci    int type = (int) utype;
444f0bfeaa8Sopenharmony_ci    return type;
445f0bfeaa8Sopenharmony_ci}