1/* 2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this list of 9 * conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 * of conditions and the following disclaimer in the documentation and/or other materials 13 * provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 16 * to endorse or promote products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "mtd_partition.h" 33#include "stdlib.h" 34#include "stdio.h" 35#include "pthread.h" 36#include "mtd_list.h" 37#include "los_config.h" 38#include "los_mux.h" 39#include "fs/driver.h" 40#include "mtd/mtd_legacy_lite.h" 41 42#define DRIVER_NAME_ADD_SIZE 3 43pthread_mutex_t g_mtdPartitionLock = PTHREAD_MUTEX_INITIALIZER; 44 45static VOID YaffsLockInit(VOID) __attribute__((weakref("yaffsfs_OSInitialisation"))); 46static VOID YaffsLockDeinit(VOID) __attribute__((weakref("yaffsfs_OsDestroy"))); 47static INT32 Jffs2LockInit(VOID) __attribute__((weakref("Jffs2MutexCreate"))); 48static VOID Jffs2LockDeinit(VOID) __attribute__((weakref("Jffs2MutexDelete"))); 49 50partition_param *g_nandPartParam = NULL; 51partition_param *g_spinorPartParam = NULL; 52mtd_partition *g_spinorPartitionHead = NULL; 53mtd_partition *g_nandPartitionHead = NULL; 54 55#define RWE_RW_RW 0755 56 57partition_param *GetNandPartParam(VOID) 58{ 59 return g_nandPartParam; 60} 61 62partition_param *GetSpinorPartParam(VOID) 63{ 64 return g_spinorPartParam; 65} 66 67mtd_partition *GetSpinorPartitionHead(VOID) 68{ 69 return g_spinorPartitionHead; 70} 71 72 73static VOID MtdNandParamAssign(partition_param *nandParam, const struct MtdDev *nandMtd) 74{ 75 LOS_ListInit(&g_nandPartitionHead->node_info); 76 /* 77 * If the user do not want to use block mtd or char mtd , 78 * you can change the NANDBLK_NAME or NANDCHR_NAME to NULL. 79 */ 80 nandParam->flash_mtd = (struct MtdDev *)nandMtd; 81 nandParam->flash_ops = GetDevNandOps(); 82 nandParam->char_ops = GetMtdCharFops(); 83 nandParam->blockname = NANDBLK_NAME; 84 nandParam->charname = NANDCHR_NAME; 85 nandParam->partition_head = g_nandPartitionHead; 86 nandParam->block_size = nandMtd->eraseSize; 87} 88 89static VOID MtdDeinitNandParam(VOID) 90{ 91 if (YaffsLockDeinit != NULL) { 92 YaffsLockDeinit(); 93 } 94} 95 96static partition_param *MtdInitNandParam(partition_param *nandParam) 97{ 98 struct MtdDev *nandMtd = GetMtd("nand"); 99 if (nandMtd == NULL) { 100 return NULL; 101 } 102 if (nandParam == NULL) { 103 if (YaffsLockInit != NULL) { 104 YaffsLockInit(); 105 } 106 nandParam = (partition_param *)zalloc(sizeof(partition_param)); 107 if (nandParam == NULL) { 108 MtdDeinitNandParam(); 109 return NULL; 110 } 111 g_nandPartitionHead = (mtd_partition *)zalloc(sizeof(mtd_partition)); 112 if (g_nandPartitionHead == NULL) { 113 MtdDeinitNandParam(); 114 free(nandParam); 115 return NULL; 116 } 117 118 MtdNandParamAssign(nandParam, nandMtd); 119 } 120 121 return nandParam; 122} 123 124static VOID MtdNorParamAssign(partition_param *spinorParam, const struct MtdDev *spinorMtd) 125{ 126 LOS_ListInit(&g_spinorPartitionHead->node_info); 127 /* 128 * If the user do not want to use block mtd or char mtd , 129 * you can change the SPIBLK_NAME or SPICHR_NAME to NULL. 130 */ 131 spinorParam->flash_mtd = (struct MtdDev *)spinorMtd; 132 spinorParam->flash_ops = GetDevSpinorOps(); 133 spinorParam->char_ops = GetMtdCharFops(); 134 spinorParam->blockname = SPIBLK_NAME; 135 spinorParam->charname = SPICHR_NAME; 136 spinorParam->partition_head = g_spinorPartitionHead; 137 spinorParam->block_size = spinorMtd->eraseSize; 138} 139 140static VOID MtdDeinitSpinorParam(VOID) 141{ 142 if (Jffs2LockDeinit != NULL) { 143 Jffs2LockDeinit(); 144 } 145} 146 147static partition_param *MtdInitSpinorParam(partition_param *spinorParam) 148{ 149 struct MtdDev *spinorMtd = GetMtd("spinor"); 150 if (spinorMtd == NULL) { 151 return NULL; 152 } 153 if (spinorParam == NULL) { 154 if (Jffs2LockInit != NULL) { 155 if (Jffs2LockInit() != 0) { /* create jffs2 lock failed */ 156 return NULL; 157 } 158 } 159 spinorParam = (partition_param *)zalloc(sizeof(partition_param)); 160 if (spinorParam == NULL) { 161 PRINT_ERR("%s, partition_param malloc failed\n", __FUNCTION__); 162 MtdDeinitSpinorParam(); 163 return NULL; 164 } 165 g_spinorPartitionHead = (mtd_partition *)zalloc(sizeof(mtd_partition)); 166 if (g_spinorPartitionHead == NULL) { 167 PRINT_ERR("%s, mtd_partition malloc failed\n", __FUNCTION__); 168 MtdDeinitSpinorParam(); 169 free(spinorParam); 170 return NULL; 171 } 172 173 MtdNorParamAssign(spinorParam, spinorMtd); 174 } 175 176 return spinorParam; 177} 178 179/* According the flash-type to init the param of the partition. */ 180static INT32 MtdInitFsparParam(const CHAR *type, partition_param **fsparParam) 181{ 182 if (strcmp(type, "nand") == 0) { 183 g_nandPartParam = MtdInitNandParam(g_nandPartParam); 184 *fsparParam = g_nandPartParam; 185 } else if (strcmp(type, "spinor") == 0 || strcmp(type, "cfi-flash") == 0) { 186 g_spinorPartParam = MtdInitSpinorParam(g_spinorPartParam); 187 *fsparParam = g_spinorPartParam; 188 } else { 189 return -EINVAL; 190 } 191 192 if ((*fsparParam == NULL) || ((VOID *)((*fsparParam)->flash_mtd) == NULL)) { 193 return -ENODEV; 194 } 195 196 return ENOERR; 197} 198 199/* According the flash-type to deinit the param of the partition. */ 200static INT32 MtdDeinitFsparParam(const CHAR *type) 201{ 202 if (strcmp(type, "nand") == 0) { 203 MtdDeinitNandParam(); 204 g_nandPartParam = NULL; 205 } else if (strcmp(type, "spinor") == 0 || strcmp(type, "cfi-flash") == 0) { 206 MtdDeinitSpinorParam(); 207 g_spinorPartParam = NULL; 208 } else { 209 return -EINVAL; 210 } 211 212 return ENOERR; 213} 214 215static INT32 AddParamCheck(UINT32 startAddr, 216 const partition_param *param, 217 UINT32 partitionNum, 218 UINT32 length) 219{ 220 UINT32 startBlk, endBlk; 221 mtd_partition *node = NULL; 222 if ((param->blockname == NULL) && (param->charname == NULL)) { 223 return -EINVAL; 224 } 225 226 if ((length == 0) || (length < param->block_size) || 227 (((UINT64)(startAddr) + length) > param->flash_mtd->size)) { 228 return -EINVAL; 229 } 230 231 ALIGN_ASSIGN(length, startAddr, startBlk, endBlk, param->block_size); 232 233 if (startBlk > endBlk) { 234 return -EINVAL; 235 } 236 LOS_DL_LIST_FOR_EACH_ENTRY(node, ¶m->partition_head->node_info, mtd_partition, node_info) { 237 if ((node->start_block != 0) && (node->patitionnum == partitionNum)) { 238 return -EINVAL; 239 } 240 if ((startBlk > node->end_block) || (endBlk < node->start_block)) { 241 continue; 242 } 243 return -EINVAL; 244 } 245 246 return ENOERR; 247} 248 249static INT32 BlockDriverRegisterOperate(mtd_partition *newNode, 250 const partition_param *param, 251 UINT32 partitionNum) 252{ 253 INT32 ret; 254 size_t driverNameSize; 255 256 if (param->blockname != NULL) { 257 driverNameSize = strlen(param->blockname) + DRIVER_NAME_ADD_SIZE; 258 newNode->blockdriver_name = (CHAR *)malloc(driverNameSize); 259 if (newNode->blockdriver_name == NULL) { 260 return -ENOMEM; 261 } 262 263 ret = snprintf_s(newNode->blockdriver_name, driverNameSize, 264 driverNameSize - 1, "%s%u", param->blockname, partitionNum); 265 if (ret < 0) { 266 free(newNode->blockdriver_name); 267 newNode->blockdriver_name = NULL; 268 return -ENAMETOOLONG; 269 } 270 271 ret = register_blockdriver(newNode->blockdriver_name, param->flash_ops, 272 RWE_RW_RW, newNode); 273 if (ret) { 274 free(newNode->blockdriver_name); 275 newNode->blockdriver_name = NULL; 276 PRINT_ERR("register blkdev partition error\n"); 277 return ret; 278 } 279 } else { 280 newNode->blockdriver_name = NULL; 281 } 282 return ENOERR; 283} 284 285static INT32 CharDriverRegisterOperate(mtd_partition *newNode, 286 const partition_param *param, 287 UINT32 partitionNum) 288{ 289 INT32 ret; 290 size_t driverNameSize; 291 292 if (param->charname != NULL) { 293 driverNameSize = strlen(param->charname) + DRIVER_NAME_ADD_SIZE; 294 newNode->chardriver_name = (CHAR *)malloc(driverNameSize); 295 if (newNode->chardriver_name == NULL) { 296 return -ENOMEM; 297 } 298 299 ret = snprintf_s(newNode->chardriver_name, driverNameSize, 300 driverNameSize - 1, "%s%u", param->charname, partitionNum); 301 if (ret < 0) { 302 free(newNode->chardriver_name); 303 newNode->chardriver_name = NULL; 304 return -ENAMETOOLONG; 305 } 306 307 ret = register_driver(newNode->chardriver_name, param->char_ops, RWE_RW_RW, newNode); 308 if (ret) { 309 PRINT_ERR("register chardev partition error\n"); 310 free(newNode->chardriver_name); 311 newNode->chardriver_name = NULL; 312 return ret; 313 } 314 } else { 315 newNode->chardriver_name = NULL; 316 } 317 return ENOERR; 318} 319 320static INT32 BlockDriverUnregister(mtd_partition *node) 321{ 322 INT32 ret; 323 324 if (node->blockdriver_name != NULL) { 325 ret = unregister_blockdriver(node->blockdriver_name); 326 if (ret == -EBUSY) { 327 PRINT_ERR("unregister blkdev partition error:%d\n", ret); 328 return ret; 329 } 330 free(node->blockdriver_name); 331 node->blockdriver_name = NULL; 332 } 333 return ENOERR; 334} 335 336static INT32 CharDriverUnregister(mtd_partition *node) 337{ 338 INT32 ret; 339 340 if (node->chardriver_name != NULL) { 341 ret = unregister_driver(node->chardriver_name); 342 if (ret == -EBUSY) { 343 PRINT_ERR("unregister chardev partition error:%d\n", ret); 344 return ret; 345 } 346 free(node->chardriver_name); 347 node->chardriver_name = NULL; 348 } 349 350 return ENOERR; 351} 352 353/* 354 * Attention: both startAddr and length should be aligned with block size. 355 * If not, the actual start address and length won't be what you expected. 356 */ 357INT32 add_mtd_partition(const CHAR *type, UINT32 startAddr, 358 UINT32 length, UINT32 partitionNum) 359{ 360 INT32 ret; 361 mtd_partition *newNode = NULL; 362 partition_param *param = NULL; 363 364 if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) || (type == NULL)) { 365 return -EINVAL; 366 } 367 368 ret = pthread_mutex_lock(&g_mtdPartitionLock); 369 if (ret != ENOERR) { 370 PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret); 371 } 372 373 ret = MtdInitFsparParam(type, ¶m); 374 if (ret != ENOERR) { 375 goto ERROR_OUT; 376 } 377 378 ret = AddParamCheck(startAddr, param, partitionNum, length); 379 if (ret != ENOERR) { 380 goto ERROR_OUT; 381 } 382 383 newNode = (mtd_partition *)zalloc(sizeof(mtd_partition)); 384 if (newNode == NULL) { 385 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock); 386 return -ENOMEM; 387 } 388 389 PAR_ASSIGNMENT(newNode, length, startAddr, partitionNum, param->flash_mtd, param->block_size); 390 391 ret = BlockDriverRegisterOperate(newNode, param, partitionNum); 392 if (ret) { 393 goto ERROR_OUT1; 394 } 395 396 ret = CharDriverRegisterOperate(newNode, param, partitionNum); 397 if (ret) { 398 goto ERROR_OUT2; 399 } 400 401 LOS_ListTailInsert(¶m->partition_head->node_info, &newNode->node_info); 402 (VOID)LOS_MuxInit(&newNode->lock, NULL); 403 404 ret = pthread_mutex_unlock(&g_mtdPartitionLock); 405 if (ret != ENOERR) { 406 PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret); 407 } 408 409 return ENOERR; 410ERROR_OUT2: 411 (VOID)BlockDriverUnregister(newNode); 412ERROR_OUT1: 413 free(newNode); 414ERROR_OUT: 415 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock); 416 return ret; 417} 418 419static INT32 DeleteParamCheck(UINT32 partitionNum, 420 const CHAR *type, 421 partition_param **param) 422{ 423 if (strcmp(type, "nand") == 0) { 424 *param = g_nandPartParam; 425 } else if (strcmp(type, "spinor") == 0 || strcmp(type, "cfi-flash") == 0) { 426 *param = g_spinorPartParam; 427 } else { 428 PRINT_ERR("type error \n"); 429 return -EINVAL; 430 } 431 432 if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) || 433 ((*param) == NULL) || ((*param)->flash_mtd == NULL)) { 434 return -EINVAL; 435 } 436 return ENOERR; 437} 438 439static INT32 DeletePartitionUnregister(mtd_partition *node) 440{ 441 INT32 ret; 442 443 ret = BlockDriverUnregister(node); 444 if (ret == -EBUSY) { 445 return ret; 446 } 447 448 ret = CharDriverUnregister(node); 449 if (ret == -EBUSY) { 450 return ret; 451 } 452 453 return ENOERR; 454} 455 456static INT32 OsNodeGet(mtd_partition **node, UINT32 partitionNum, const partition_param *param) 457{ 458 LOS_DL_LIST_FOR_EACH_ENTRY(*node, ¶m->partition_head->node_info, mtd_partition, node_info) { 459 if ((*node)->patitionnum == partitionNum) { 460 break; 461 } 462 } 463 if ((*node == NULL) || ((*node)->patitionnum != partitionNum) || 464 ((*node)->mountpoint_name != NULL)) { 465 return -EINVAL; 466 } 467 468 return ENOERR; 469} 470 471static INT32 OsResourceRelease(mtd_partition *node, const CHAR *type, partition_param *param) 472{ 473 (VOID)LOS_MuxDestroy(&node->lock); 474 LOS_ListDelete(&node->node_info); 475 (VOID)memset_s(node, sizeof(mtd_partition), 0, sizeof(mtd_partition)); 476 free(node); 477 (VOID)FreeMtd(param->flash_mtd); 478 if (LOS_ListEmpty(¶m->partition_head->node_info)) { 479 free(param->partition_head); 480 param->partition_head = NULL; 481 free(param); 482 483 if (MtdDeinitFsparParam(type) != ENOERR) { 484 return -EINVAL; 485 } 486 } 487 return ENOERR; 488} 489 490INT32 delete_mtd_partition(UINT32 partitionNum, const CHAR *type) 491{ 492 INT32 ret; 493 mtd_partition *node = NULL; 494 partition_param *param = NULL; 495 496 if (type == NULL) { 497 return -EINVAL; 498 } 499 500 ret = pthread_mutex_lock(&g_mtdPartitionLock); 501 if (ret != ENOERR) { 502 PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret); 503 } 504 505 ret = DeleteParamCheck(partitionNum, type, ¶m); 506 if (ret) { 507 PRINT_ERR("delete_mtd_partition param invalid\n"); 508 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock); 509 return ret; 510 } 511 512 ret = OsNodeGet(&node, partitionNum, param); 513 if (ret) { 514 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock); 515 return ret; 516 } 517 518 ret = DeletePartitionUnregister(node); 519 if (ret) { 520 PRINT_ERR("DeletePartitionUnregister error:%d\n", ret); 521 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock); 522 return ret; 523 } 524 525 ret = OsResourceRelease(node, type, param); 526 if (ret) { 527 PRINT_ERR("DeletePartitionUnregister error:%d\n", ret); 528 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock); 529 return ret; 530 } 531 532 ret = pthread_mutex_unlock(&g_mtdPartitionLock); 533 if (ret != ENOERR) { 534 PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret); 535 } 536 return ENOERR; 537} 538 539