/* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "los_rootfs.h" #include "los_bootargs.h" #include "los_base.h" #include "string.h" #include "sys/mount.h" #include "sys/stat.h" #include "sys/types.h" #if defined(LOSCFG_STORAGE_SPINOR) || defined(LOSCFG_STORAGE_SPINAND) || defined(LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7) #include "mtd_list.h" #include "mtd_partition.h" #endif #ifdef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7 #include "cfiflash.h" #endif #ifdef LOSCFG_STORAGE_EMMC #include "disk.h" #include "ff.h" #endif #ifdef LOSCFG_STORAGE_EMMC struct disk_divide_info *StorageBlockGetEmmc(void); struct block_operations *StorageBlockGetMmcOps(void); char *StorageBlockGetEmmcNodeName(void *block); STATIC INT32 AddEmmcParts(INT32 rootAddr, INT32 rootSize, INT32 userAddr, INT32 userSize) { INT32 ret; los_disk *emmcDisk = los_get_mmcdisk_bytype(EMMC); if (emmcDisk == NULL) { PRINT_ERR("Get EMMC disk failed!\n"); return LOS_NOK; } void *block = ((struct drv_data *)emmcDisk->dev->data)->priv; const char *node_name = StorageBlockGetEmmcNodeName(block); if (los_disk_deinit(emmcDisk->disk_id) != ENOERR) { PRINT_ERR("Failed to deinit emmc disk!\n"); return LOS_NOK; } struct disk_divide_info *emmc = StorageBlockGetEmmc(); ret = add_mmc_partition(emmc, rootAddr / EMMC_SEC_SIZE, rootSize / EMMC_SEC_SIZE); if (ret != LOS_OK) { PRINT_ERR("Failed to add mmc root partition!\n"); return LOS_NOK; } #ifdef LOSCFG_PLATFORM_PATCHFS UINT64 patchStartCnt = userAddr / EMMC_SEC_SIZE; UINT64 patchSizeCnt = PATCH_SIZE / EMMC_SEC_SIZE; ret = add_mmc_partition(emmc, patchStartCnt, patchSizeCnt); if (ret != LOS_OK) { PRINT_ERR("Failed to add mmc patch partition!\n"); return LOS_NOK; } userAddr += PATCH_SIZE; #endif UINT64 storageStartCnt = userAddr / EMMC_SEC_SIZE; UINT64 storageSizeCnt = userSize / EMMC_SEC_SIZE; UINT64 userdataStartCnt = storageStartCnt + storageSizeCnt; UINT64 userdataSizeCnt = emmcDisk->sector_count - userdataStartCnt; ret = add_mmc_partition(emmc, storageStartCnt, storageSizeCnt); if (ret != LOS_OK) { PRINT_ERR("Failed to add mmc storage partition!\n"); return LOS_NOK; } ret = add_mmc_partition(emmc, userdataStartCnt, userdataSizeCnt); if (ret != LOS_OK) { PRINT_ERR("Failed to add mmc userdata partition!\n"); return LOS_NOK; } LOS_Msleep(10); /* 100, sleep time. waiting for device identification */ INT32 diskId = los_alloc_diskid_byname(node_name); if (diskId < 0) { PRINT_ERR("Failed to alloc disk %s!\n", node_name); return LOS_NOK; } if (los_disk_init(node_name, StorageBlockGetMmcOps(), block, diskId, emmc) != ENOERR) { PRINT_ERR("Failed to init emmc disk!\n"); return LOS_NOK; } return LOS_OK; } #endif STATIC INT32 AddPartitions(CHAR *dev, UINT64 rootAddr, UINT64 rootSize, UINT64 userAddr, UINT64 userSize) { #ifdef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7 if ((strcmp(dev, "cfi-flash") == 0) && (rootAddr != CFIFLASH_ROOT_ADDR)) { PRINT_ERR("Error rootAddr, must be %#0x!\n", CFIFLASH_ROOT_ADDR); return LOS_NOK; } #endif #if defined(LOSCFG_STORAGE_SPINOR) || defined(LOSCFG_STORAGE_SPINAND) || defined(LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7) INT32 ret; INT32 blk0 = 0; INT32 blk2 = 2; if (strcmp(dev, "flash") == 0 || strcmp(dev, FLASH_TYPE) == 0) { ret = add_mtd_partition(FLASH_TYPE, rootAddr, rootSize, blk0); if (ret != LOS_OK) { PRINT_ERR("Failed to add mtd root partition!\n"); return LOS_NOK; } ret = add_mtd_partition(FLASH_TYPE, userAddr, userSize, blk2); if (ret != LOS_OK) { PRINT_ERR("Failed to add mtd storage partition!\n"); return LOS_NOK; } return LOS_OK; } #endif #ifdef LOSCFG_STORAGE_EMMC if (strcmp(dev, "emmc") == 0) { return AddEmmcParts(rootAddr, rootSize, userAddr, userSize); } #endif PRINT_ERR("Unsupport dev type: %s\n", dev); return LOS_NOK; } STATIC INT32 ParseRootArgs(CHAR **dev, CHAR **fstype, UINT64 *rootAddr, UINT64 *rootSize, UINT32 *mountFlags) { INT32 ret; CHAR *rootAddrStr = NULL; CHAR *rootSizeStr = NULL; CHAR *rwTag = NULL; ret = LOS_GetArgValue("root", dev); if (ret != LOS_OK) { PRINT_ERR("Cannot find root!"); return ret; } ret = LOS_GetArgValue("fstype", fstype); if (ret != LOS_OK) { PRINT_ERR("Cannot find fstype!"); return ret; } ret = LOS_GetArgValue("rootaddr", &rootAddrStr); if (ret != LOS_OK) { *rootAddr = ROOTFS_ADDR; } else { *rootAddr = LOS_SizeStrToNum(rootAddrStr); } ret = LOS_GetArgValue("rootsize", &rootSizeStr); if (ret != LOS_OK) { *rootSize = ROOTFS_SIZE; } else { *rootSize = LOS_SizeStrToNum(rootSizeStr); } ret = LOS_GetArgValue("ro", &rwTag); if (ret == LOS_OK) { *mountFlags = MS_RDONLY; } else { *mountFlags = 0; } return LOS_OK; } STATIC INT32 ParseUserArgs(UINT64 rootAddr, UINT64 rootSize, UINT64 *userAddr, UINT64 *userSize) { INT32 ret; CHAR *userAddrStr = NULL; CHAR *userSizeStr = NULL; ret = LOS_GetArgValue("useraddr", &userAddrStr); if (ret != LOS_OK) { *userAddr = rootAddr + rootSize; } else { *userAddr = LOS_SizeStrToNum(userAddrStr); } ret = LOS_GetArgValue("usersize", &userSizeStr); if (ret != LOS_OK) { *userSize = USERFS_SIZE; } else { *userSize = LOS_SizeStrToNum(userSizeStr); } return LOS_OK; } STATIC INT32 MountPartitions(CHAR *fsType, UINT32 mountFlags) { INT32 ret; INT32 err; /* Mount rootfs */ ret = mount(ROOT_DEV_NAME, ROOT_DIR_NAME, fsType, mountFlags, NULL); if (ret != LOS_OK) { err = get_errno(); PRINT_ERR("Failed to mount %s, rootDev %s, errno %d: %s\n", ROOT_DIR_NAME, ROOT_DEV_NAME, err, strerror(err)); return ret; } #ifdef LOSCFG_STORAGE_EMMC #ifdef LOSCFG_PLATFORM_PATCHFS /* Mount patch */ ret = mkdir(PATCH_DIR_NAME, DEFAULT_MOUNT_DIR_MODE); if ((ret != LOS_OK) && ((err = get_errno()) != EEXIST)) { PRINT_ERR("Failed to mkdir %s, errno %d: %s\n", PATCH_DIR_NAME, err, strerror(err)); return ret; } ret = mount(PATCH_DEV_NAME, PATCH_DIR_NAME, fsType, 0, DEFAULT_MOUNT_DATA); if ((ret != LOS_OK) && ((err = get_errno()) == ENOTSUP)) { ret = format(PATCH_DEV_NAME, 0, FM_FAT32); if (ret != LOS_OK) { PRINT_ERR("Failed to format %s\n", PATCH_DEV_NAME); return ret; } ret = mount(PATCH_DEV_NAME, PATCH_DIR_NAME, fsType, 0, DEFAULT_MOUNT_DATA); if (ret != LOS_OK) { err = get_errno(); } } if (ret != LOS_OK) { PRINT_ERR("Failed to mount %s, errno %d: %s\n", PATCH_DIR_NAME, err, strerror(err)); return ret; } #endif #endif /* Mount userfs */ ret = mkdir(STORAGE_DIR_NAME, DEFAULT_MOUNT_DIR_MODE); if ((ret != LOS_OK) && ((err = get_errno()) != EEXIST)) { PRINT_ERR("Failed to mkdir %s, errno %d: %s\n", STORAGE_DIR_NAME, err, strerror(err)); return ret; } ret = mount(USER_DEV_NAME, STORAGE_DIR_NAME, fsType, 0, DEFAULT_MOUNT_DATA); if (ret != LOS_OK) { err = get_errno(); PRINT_ERR("Failed to mount %s, errno %d: %s\n", STORAGE_DIR_NAME, err, strerror(err)); return ret; } #ifdef LOSCFG_STORAGE_EMMC /* Mount userdata */ ret = mkdir(USERDATA_DIR_NAME, DEFAULT_MOUNT_DIR_MODE); if ((ret != LOS_OK) && ((err = get_errno()) != EEXIST)) { PRINT_ERR("Failed to mkdir %s, errno %d: %s\n", USERDATA_DIR_NAME, err, strerror(err)); return ret; } ret = mount(USERDATA_DEV_NAME, USERDATA_DIR_NAME, fsType, 0, DEFAULT_MOUNT_DATA); if ((ret != LOS_OK) && ((err = get_errno()) == ENOTSUP)) { ret = format(USERDATA_DEV_NAME, 0, FM_FAT32); if (ret != LOS_OK) { PRINT_ERR("Failed to format %s\n", USERDATA_DEV_NAME); return ret; } ret = mount(USERDATA_DEV_NAME, USERDATA_DIR_NAME, fsType, 0, DEFAULT_MOUNT_DATA); if (ret != LOS_OK) { err = get_errno(); } } if (ret != LOS_OK) { PRINT_ERR("Failed to mount %s, errno %d: %s\n", USERDATA_DIR_NAME, err, strerror(err)); return ret; } #endif return LOS_OK; } STATIC INT32 CheckValidation(UINT64 rootAddr, UINT64 rootSize, UINT64 userAddr, UINT64 userSize) { UINT64 alignSize = LOS_GetAlignsize(); if (alignSize == 0) { return LOS_OK; } if ((rootAddr & (alignSize - 1)) || (rootSize & (alignSize - 1)) || (userAddr & (alignSize - 1)) || (userSize & (alignSize - 1))) { PRINT_ERR("The address or size value should be 0x%llx aligned!\n", alignSize); return LOS_NOK; } return LOS_OK; } INT32 OsMountRootfs() { INT32 ret; CHAR *dev = NULL; CHAR *fstype = NULL; UINT64 rootAddr; UINT64 rootSize; UINT64 userAddr; UINT64 userSize; UINT32 mountFlags; ret = ParseRootArgs(&dev, &fstype, &rootAddr, &rootSize, &mountFlags); if (ret != LOS_OK) { return ret; } ret = ParseUserArgs(rootAddr, rootSize, &userAddr, &userSize); if (ret != LOS_OK) { return ret; } ret = CheckValidation(rootAddr, rootSize, userAddr, userSize); if (ret != LOS_OK) { return ret; } ret = AddPartitions(dev, rootAddr, rootSize, userAddr, userSize); if (ret != LOS_OK) { return ret; } ret = MountPartitions(fstype, mountFlags); if (ret != LOS_OK) { return ret; } return LOS_OK; }