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