diff --git a/libpurgeablemem/c/src/purgeable_mem_c.c b/libpurgeablemem/c/src/purgeable_mem_c.c index 3d1d0d771375a968dd80edd5bb269386489d22f9..291e44276d49d4ef70a853400da475f7894fb9ea 100644 --- a/libpurgeablemem/c/src/purgeable_mem_c.c +++ b/libpurgeablemem/c/src/purgeable_mem_c.c @@ -20,6 +20,7 @@ #include /* FILE */ #include +#include "securec.h" #include "../../common/include/pm_ptr_util.h" #include "../../common/include/pm_util.h" #include "../../common/include/pm_state_c.h" @@ -68,10 +69,12 @@ static struct PurgMem *PurgMemCreate_(size_t len, struct PurgMemBuilder *builder return NULL; } size_t size = RoundUp_(len, PAGE_SIZE); - pugObj->dataPtr = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_PURGEABLE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (!pugObj->dataPtr) { + int type = MAP_ANONYMOUS; + type |= (UxpteIsEnabled() ? MAP_PURGEABLE : MAP_PRIVATE); + pugObj->dataPtr = mmap(NULL, size, PROT_READ | PROT_WRITE, type, -1, 0); + if (pugObj->dataPtr == MAP_FAILED) { HILOG_ERROR(LOG_CORE, "%{public}s: mmap dataPtr fail", __func__); + pugObj->dataPtr = NULL; goto free_pug_obj; } @@ -119,11 +122,11 @@ struct PurgMem *PurgMemCreate(size_t len, PurgMemModifyFunc func, void *funcPara HILOG_ERROR(LOG_CORE, "%{public}s: input len 0", __func__); return NULL; } - + /* a PurgMemObj must have builder */ + IF_NULL_LOG_ACTION(func, "%{public}s: input func is NULL", return NULL); struct PurgMem *purgMemObj = PurgMemCreate_(len, NULL); - /* no build func or create fail */ - if (!func || !purgMemObj) { - /* this PurgMemObj allow no builder temporaily */ + /* create fail */ + if (!purgMemObj) { return purgMemObj; } @@ -168,7 +171,7 @@ bool PurgMemDestroy(struct PurgMem *purgObj) err = PM_UNMAP_PURG_FAIL; } else { /* double check munmap result: if uxpte is set to no_present */ - if (USE_UXPT && !IsPurged_(purgObj)) { + if (UxpteIsEnabled() && !IsPurged_(purgObj)) { HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__); err = PM_UXPT_PRESENT_DATA_PURGED; } @@ -202,17 +205,21 @@ static bool IsPurgMemPtrValid_(struct PurgMem *purgObj) IF_NULL_LOG_ACTION(purgObj, "obj is NULL", return false); IF_NULL_LOG_ACTION(purgObj->dataPtr, "dataPtr is NULL", return false); IF_NULL_LOG_ACTION(purgObj->uxPageTable, "pageTable is NULL", return false); + IF_NULL_LOG_ACTION(purgObj->builder, "builder is NULL", return false); return true; } static inline bool PurgMemBuildData_(struct PurgMem *purgObj) { - bool succ = true; - /* succ is true when purgObj has no builder */ - if (purgObj->builder) { - succ = PurgMemBuilderBuildAll(purgObj->builder, purgObj->dataPtr, purgObj->dataSizeInput); - } + bool succ = false; + /* clear content before rebuild */ + if (memset_s(purgObj->dataPtr, RoundUp_(purgObj->dataSizeInput, PAGE_SIZE), 0, purgObj->dataSizeInput) != EOK) { + HILOG_ERROR(LOG_CORE, "%{public}s, clear content fail", __func__); + return succ; + } + /* @purgObj->builder is not NULL since it is checked by IsPurgMemPtrValid_() before */ + succ = PurgMemBuilderBuildAll(purgObj->builder, purgObj->dataPtr, purgObj->dataSizeInput); if (succ) { purgObj->buildDataCount++; } @@ -416,5 +423,5 @@ static bool IsPurged_(struct PurgMem *purgObj) HILOG_INFO(LOG_CORE, "%{public}s, has never built, return true", __func__); return true; } - return USE_UXPT && !UxpteIsPresent(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput); + return !UxpteIsPresent(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput); } diff --git a/libpurgeablemem/common/include/pm_util.h b/libpurgeablemem/common/include/pm_util.h index d2bb77524cd29a62f740527c20dfb4f860656e42..67ca33f73bd905ab2caf24618e19a0b9922cf883 100644 --- a/libpurgeablemem/common/include/pm_util.h +++ b/libpurgeablemem/common/include/pm_util.h @@ -28,10 +28,10 @@ extern "C" { * case 1: if there is no purgeable mem module in kernel. * case 2: if you want close libpurgeable, meanwhile doesn't affect user programs. */ -#define USE_UXPT false +#define USE_UXPT true -#define MAP_PURGEABLE 0x40 -#define MAP_USEREXPTE 0x80 +#define MAP_PURGEABLE 0x04 +#define MAP_USEREXPTE 0x08 #define PAGE_SHIFT 12 #define PAGE_SIZE (1 << PAGE_SHIFT) diff --git a/libpurgeablemem/common/src/ux_page_table_c.c b/libpurgeablemem/common/src/ux_page_table_c.c index fe29f1c8b9ef0ccfbc4a8ba22e69553923e50a1e..ba2bd78ad480fc295cae71fe46a3737cd42dd623 100644 --- a/libpurgeablemem/common/src/ux_page_table_c.c +++ b/libpurgeablemem/common/src/ux_page_table_c.c @@ -38,6 +38,8 @@ typedef struct UserExtendPageTable { uxpte_t *uxpte; } UxPageTableStruct; +static bool g_supportUxpt = false; + /* * ------------------------------------------------------------------------- * | virtual page number | | @@ -111,6 +113,7 @@ enum UxpteOp { UPT_IS_PRESENT = 3, }; +static void __attribute__((constructor)) CheckUxpt_(void); static void UxpteAdd_(uxpte_t *pte, size_t incNum); static void UxpteSub_(uxpte_t *pte, size_t decNum); @@ -122,9 +125,45 @@ static PMState UxpteOps_(UxPageTableStruct *upt, uint64_t addr, size_t len, enum static uxpte_t *MapUxptePages_(uint64_t dataAddr, size_t dataSize); static int UnmapUxptePages_(uxpte_t *ptes, size_t size); +static void __attribute__((constructor)) CheckUxpt_(void) +{ + int prot = PROT_READ | PROT_WRITE; + int type = MAP_ANONYMOUS | MAP_PURGEABLE; + size_t dataSize = PAGE_SIZE; + /* try to mmap purgable page */ + void *dataPtr = mmap(NULL, dataSize, prot, type, -1, 0); + if (dataPtr == MAP_FAILED) { + HILOG_ERROR(LOG_CORE, "%{public}s: not support MAP_PURG", __func__); + g_supportUxpt = false; + return; + } + /* try to mmap uxpt page */ + type = MAP_ANONYMOUS | MAP_USEREXPTE; + size_t uptSize = GetUxPageSize_((uint64_t)dataPtr, dataSize); + void *ptes = mmap(NULL, uptSize, prot, type, -1, UxptePageNo_((uint64_t)dataPtr) * PAGE_SIZE); + if (ptes != MAP_FAILED) { + g_supportUxpt = true; + /* free uxpt */ + if (munmap(ptes, uptSize)) { + HILOG_ERROR(LOG_CORE, "%{public}s: unmap uxpt fail", __func__); + } + } else { /* MAP_FAILED */ + g_supportUxpt = false; + HILOG_ERROR(LOG_CORE, "%{public}s: not support uxpt", __func__); + } + ptes = NULL; + /* free data */ + if (munmap(dataPtr, dataSize)) { + HILOG_ERROR(LOG_CORE, "%{public}s: unmap purg data fail", __func__); + } + dataPtr = NULL; + HILOG_INFO(LOG_CORE, "%{public}s: supportUxpt=%{public}s", __func__, (g_supportUxpt ? "1" : "0")); + return; +} + bool UxpteIsEnabled(void) { - return true; + return g_supportUxpt; } size_t UxPageTableSize(void) @@ -134,6 +173,10 @@ size_t UxPageTableSize(void) PMState InitUxPageTable(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + HILOG_DEBUG(LOG_CORE, "%{public}s: not support uxpt", __func__); + return PM_OK; + } upt->dataAddr = addr; upt->dataSize = len; upt->uxpte = MapUxptePages_(upt->dataAddr, upt->dataSize); @@ -146,6 +189,10 @@ PMState InitUxPageTable(UxPageTableStruct *upt, uint64_t addr, size_t len) PMState DeinitUxPageTable(UxPageTableStruct *upt) { + if (!g_supportUxpt) { + HILOG_DEBUG(LOG_CORE, "%{public}s: not support uxpt", __func__); + return PM_OK; + } size_t size = GetUxPageSize_(upt->dataAddr, upt->dataSize); int unmapRet = 0; if (upt->uxpte) { @@ -163,21 +210,33 @@ PMState DeinitUxPageTable(UxPageTableStruct *upt) void UxpteGet(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return; + } UxpteOps_(upt, addr, len, UPT_GET); } void UxptePut(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return; + } UxpteOps_(upt, addr, len, UPT_PUT); } void UxpteClear(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return; + } UxpteOps_(upt, addr, len, UPT_CLEAR); } bool UxpteIsPresent(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return true; + } PMState ret = UxpteOps_(upt, addr, len, UPT_IS_PRESENT); return ret == PM_OK; } @@ -310,10 +369,10 @@ static PMState UxpteOps_(UxPageTableStruct *upt, uint64_t addr, size_t len, enum static uxpte_t *MapUxptePages_(uint64_t dataAddr, size_t dataSize) { int prot = PROT_READ | PROT_WRITE; - int type = MAP_PRIVATE | MAP_ANONYMOUS | MAP_USEREXPTE; + int type = MAP_ANONYMOUS | MAP_USEREXPTE; size_t size = GetUxPageSize_(dataAddr, dataSize); uxpte_t *ptes = (uxpte_t*)mmap(NULL, size, prot, type, -1, UxptePageNo_(dataAddr) * PAGE_SIZE); - if (ptes == (void *)-1) { + if (ptes == MAP_FAILED) { HILOG_ERROR(LOG_CORE, "%{public}s: fail, return NULL", __func__); ptes = NULL; } diff --git a/libpurgeablemem/cpp/include/purgeable_mem.h b/libpurgeablemem/cpp/include/purgeable_mem.h index 37c774dad09002f07ff7484d06b61755ad04011a..9f2d461de321cac4f384ca6e52c56982e7a34e2c 100644 --- a/libpurgeablemem/cpp/include/purgeable_mem.h +++ b/libpurgeablemem/cpp/include/purgeable_mem.h @@ -33,7 +33,7 @@ public: * Input: @builder: using @builder to recover user data when this obj's content is purged. * @builder should be a unique_ptr to avolid memory manage chaos(memory leak). */ - PurgeableMem(size_t dataSize, std::unique_ptr builder = nullptr); + PurgeableMem(size_t dataSize, std::unique_ptr builder); /* * Destructor of class PurgeableMem. @@ -100,10 +100,10 @@ public: bool ModifyContentByBuilder(std::unique_ptr modifier); private: - void *dataPtr_; + void *dataPtr_ = nullptr; size_t dataSizeInput_; - std::unique_ptr builder_; - std::unique_ptr pageTable_; + std::unique_ptr builder_ = nullptr; + std::unique_ptr pageTable_ = nullptr; std::shared_mutex rwlock_; unsigned int buildDataCount_; diff --git a/libpurgeablemem/cpp/src/purgeable_mem.cpp b/libpurgeablemem/cpp/src/purgeable_mem.cpp index e1c10aca5a6003cffb1ec49dc05e8ee567498003..415782686e3389ca8a12335146675aef5a42b9b5 100644 --- a/libpurgeablemem/cpp/src/purgeable_mem.cpp +++ b/libpurgeablemem/cpp/src/purgeable_mem.cpp @@ -15,6 +15,7 @@ #include /* mmap */ +#include "securec.h" #include "../../common/include/pm_util.h" #include "../../common/include/pm_state_c.h" #include "pm_smartptr_util.h" @@ -37,24 +38,29 @@ static inline size_t RoundUp_(size_t val, size_t align) PurgeableMem::PurgeableMem(size_t dataSize, std::unique_ptr builder) { + dataPtr_ = nullptr; + builder_ = nullptr; + pageTable_ = nullptr; + buildDataCount_ = 0; + if (dataSize == 0) { return; } dataSizeInput_ = dataSize; + IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return); size_t size = RoundUp_(dataSizeInput_, PAGE_SIZE); - dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PURGEABLE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (!dataPtr_) { + int type = MAP_ANONYMOUS; + type |= (UxpteIsEnabled() ? MAP_PURGEABLE : MAP_PRIVATE); + dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, type, -1, 0); + if (dataPtr_ == MAP_FAILED) { + HILOG_ERROR(LOG_CORE, "%{public}s: mmap fail", __func__); + dataPtr_ = nullptr; return; } - pageTable_ = nullptr; - builder_ = nullptr; - buildDataCount_ = 0; + builder_ = std::move(builder); - if (builder) { - builder_ = std::move(builder); - } MAKE_UNIQUE(pageTable_, UxPageTable, "constructor uxpt make_unique fail", return, (uint64_t)dataPtr_, size); HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString_().c_str()); } @@ -66,7 +72,7 @@ PurgeableMem::~PurgeableMem() if (munmap(dataPtr_, RoundUp_(dataSizeInput_, PAGE_SIZE))) { HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__); } else { - if (USE_UXPT && !IsPurged_()) { + if (UxpteIsEnabled() && !IsPurged_()) { HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__); } dataPtr_ = nullptr; @@ -84,6 +90,7 @@ bool PurgeableMem::BeginRead() IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginRead", return false); IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptr in BeginRead", return false); + IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginRead", return false); pageTable_->GetUxpte((uint64_t)dataPtr_, dataSizeInput_); PMState err = PM_OK; @@ -140,6 +147,7 @@ bool PurgeableMem::BeginWrite() IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginWrite", return false); IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false); + IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginWrite", return false); pageTable_->GetUxpte((uint64_t)dataPtr_, dataSizeInput_); PMState err = PM_OK; @@ -213,16 +221,19 @@ bool PurgeableMem::IsPurged_() HILOG_INFO(LOG_CORE, "%{public}s, has never built, return true", __func__); return true; } - return USE_UXPT && (!pageTable_->CheckPresent((uint64_t)dataPtr_, dataSizeInput_)); + return !(pageTable_->CheckPresent((uint64_t)dataPtr_, dataSizeInput_)); } bool PurgeableMem::BuildContent_() { - bool succ = true; - /* succ is true when purgObj has no builder */ - if (builder_) { - succ = builder_->BuildAll(dataPtr_, dataSizeInput_); + bool succ = false; + /* clear content before rebuild */ + if (memset_s(dataPtr_, RoundUp_(dataSizeInput_, PAGE_SIZE), 0, dataSizeInput_) != EOK) { + HILOG_ERROR(LOG_CORE, "%{public}s, clear content fail", __func__); + return succ; } + /* builder_ and dataPtr_ is never nullptr since it is checked by BeginAccess() before */ + succ = builder_->BuildAll(dataPtr_, dataSizeInput_); if (succ) { buildDataCount_++; } diff --git a/libpurgeablemem/test/purgeable_cpp_test.cpp b/libpurgeablemem/test/purgeable_cpp_test.cpp index eb45d9a37c5f89f9977f9776e1b72fab095e3b63..c9f25e203f62c73802f873e1909183d5ff3f2ef8 100644 --- a/libpurgeablemem/test/purgeable_cpp_test.cpp +++ b/libpurgeablemem/test/purgeable_cpp_test.cpp @@ -154,9 +154,9 @@ HWTEST_F(PurgeableCppTest, MultiObjCreateTest, TestSize.Level1) HWTEST_F(PurgeableCppTest, ReadTest, TestSize.Level1) { const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0"; - PurgeableMem *pobj = new PurgeableMem(27); std::unique_ptr builder = std::make_unique('A', 'Z'); - ModifyPurgMemByBuilder(pobj, std::move(builder)); + PurgeableMem *pobj = new PurgeableMem(27, std::move(builder)); + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); pthread_t reclaimPid = reclaimThread.native_handle(); reclaimThread.detach();