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 #ifdef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
43 #include "cfiflash.h"
44 #endif
45
46
47 #define DRIVER_NAME_ADD_SIZE 3
48 pthread_mutex_t g_mtdPartitionLock = PTHREAD_MUTEX_INITIALIZER;
49
50 static VOID YaffsLockInit(VOID) __attribute__((weakref("yaffsfs_OSInitialisation")));
51 static VOID YaffsLockDeinit(VOID) __attribute__((weakref("yaffsfs_OsDestroy")));
52 static INT32 Jffs2LockInit(VOID) __attribute__((weakref("Jffs2MutexCreate")));
53 static VOID Jffs2LockDeinit(VOID) __attribute__((weakref("Jffs2MutexDelete")));
54
55 partition_param *g_nandPartParam = NULL;
56 partition_param *g_spinorPartParam = NULL;
57 mtd_partition *g_spinorPartitionHead = NULL;
58 mtd_partition *g_nandPartitionHead = NULL;
59
60 #define RWE_RW_RW 0755
61
GetNandPartParam(VOID)62 partition_param *GetNandPartParam(VOID)
63 {
64 return g_nandPartParam;
65 }
66
GetSpinorPartParam(VOID)67 partition_param *GetSpinorPartParam(VOID)
68 {
69 return g_spinorPartParam;
70 }
71
GetSpinorPartitionHead(VOID)72 mtd_partition *GetSpinorPartitionHead(VOID)
73 {
74 return g_spinorPartitionHead;
75 }
76
77
MtdNandParamAssign(partition_param * nandParam,const struct MtdDev * nandMtd)78 static VOID MtdNandParamAssign(partition_param *nandParam, const struct MtdDev *nandMtd)
79 {
80 LOS_ListInit(&g_nandPartitionHead->node_info);
81 /*
82 * If the user do not want to use block mtd or char mtd ,
83 * you can change the NANDBLK_NAME or NANDCHR_NAME to NULL.
84 */
85 nandParam->flash_mtd = (struct MtdDev *)nandMtd;
86 nandParam->flash_ops = GetDevNandOps();
87 nandParam->char_ops = GetMtdCharFops();
88 nandParam->blockname = NANDBLK_NAME;
89 nandParam->charname = NANDCHR_NAME;
90 nandParam->partition_head = g_nandPartitionHead;
91 nandParam->block_size = nandMtd->eraseSize;
92 }
93
MtdDeinitNandParam(VOID)94 static VOID MtdDeinitNandParam(VOID)
95 {
96 if (YaffsLockDeinit != NULL) {
97 YaffsLockDeinit();
98 }
99 }
100
MtdInitNandParam(partition_param * nandParam)101 static partition_param *MtdInitNandParam(partition_param *nandParam)
102 {
103 struct MtdDev *nandMtd = GetMtd("nand");
104 if (nandMtd == NULL) {
105 return NULL;
106 }
107 if (nandParam == NULL) {
108 if (YaffsLockInit != NULL) {
109 YaffsLockInit();
110 }
111 nandParam = (partition_param *)zalloc(sizeof(partition_param));
112 if (nandParam == NULL) {
113 MtdDeinitNandParam();
114 return NULL;
115 }
116 g_nandPartitionHead = (mtd_partition *)zalloc(sizeof(mtd_partition));
117 if (g_nandPartitionHead == NULL) {
118 MtdDeinitNandParam();
119 free(nandParam);
120 return NULL;
121 }
122
123 MtdNandParamAssign(nandParam, nandMtd);
124 }
125
126 return nandParam;
127 }
128
MtdNorParamAssign(partition_param * spinorParam,const struct MtdDev * spinorMtd)129 static VOID MtdNorParamAssign(partition_param *spinorParam, const struct MtdDev *spinorMtd)
130 {
131 LOS_ListInit(&g_spinorPartitionHead->node_info);
132 /*
133 * If the user do not want to use block mtd or char mtd ,
134 * you can change the SPIBLK_NAME or SPICHR_NAME to NULL.
135 */
136 spinorParam->flash_mtd = (struct MtdDev *)spinorMtd;
137 #ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
138 spinorParam->flash_ops = GetDevSpinorOps();
139 spinorParam->char_ops = GetMtdCharFops();
140 spinorParam->blockname = SPIBLK_NAME;
141 spinorParam->charname = SPICHR_NAME;
142 #else
143 spinorParam->flash_ops = GetCfiBlkOps();
144 spinorParam->char_ops = NULL;
145 spinorParam->blockname = CFI_DRIVER;
146 spinorParam->charname = NULL;
147 #endif
148 spinorParam->partition_head = g_spinorPartitionHead;
149 spinorParam->block_size = spinorMtd->eraseSize;
150 }
151
MtdDeinitSpinorParam(VOID)152 static VOID MtdDeinitSpinorParam(VOID)
153 {
154 if (Jffs2LockDeinit != NULL) {
155 Jffs2LockDeinit();
156 }
157 }
158
MtdInitSpinorParam(partition_param * spinorParam)159 static partition_param *MtdInitSpinorParam(partition_param *spinorParam)
160 {
161 #ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
162 struct MtdDev *spinorMtd = GetMtd("spinor");
163 #else
164 struct MtdDev *spinorMtd = GetCfiMtdDev();
165 #endif
166 if (spinorMtd == NULL) {
167 return NULL;
168 }
169 if (spinorParam == NULL) {
170 if (Jffs2LockInit != NULL) {
171 if (Jffs2LockInit() != 0) { /* create jffs2 lock failed */
172 return NULL;
173 }
174 }
175 spinorParam = (partition_param *)zalloc(sizeof(partition_param));
176 if (spinorParam == NULL) {
177 PRINT_ERR("%s, partition_param malloc failed\n", __FUNCTION__);
178 MtdDeinitSpinorParam();
179 return NULL;
180 }
181 g_spinorPartitionHead = (mtd_partition *)zalloc(sizeof(mtd_partition));
182 if (g_spinorPartitionHead == NULL) {
183 PRINT_ERR("%s, mtd_partition malloc failed\n", __FUNCTION__);
184 MtdDeinitSpinorParam();
185 free(spinorParam);
186 return NULL;
187 }
188
189 MtdNorParamAssign(spinorParam, spinorMtd);
190 }
191
192 return spinorParam;
193 }
194
195 /* According the flash-type to init the param of the partition. */
MtdInitFsparParam(const CHAR * type,partition_param ** fsparParam)196 static INT32 MtdInitFsparParam(const CHAR *type, partition_param **fsparParam)
197 {
198 if (strcmp(type, "nand") == 0) {
199 g_nandPartParam = MtdInitNandParam(g_nandPartParam);
200 *fsparParam = g_nandPartParam;
201 } else if (strcmp(type, "spinor") == 0 || strcmp(type, "cfi-flash") == 0) {
202 g_spinorPartParam = MtdInitSpinorParam(g_spinorPartParam);
203 *fsparParam = g_spinorPartParam;
204 } else {
205 return -EINVAL;
206 }
207
208 if ((*fsparParam == NULL) || ((VOID *)((*fsparParam)->flash_mtd) == NULL)) {
209 return -ENODEV;
210 }
211
212 return ENOERR;
213 }
214
215 /* According the flash-type to deinit the param of the partition. */
MtdDeinitFsparParam(const CHAR * type)216 static INT32 MtdDeinitFsparParam(const CHAR *type)
217 {
218 if (strcmp(type, "nand") == 0) {
219 MtdDeinitNandParam();
220 g_nandPartParam = NULL;
221 } else if (strcmp(type, "spinor") == 0 || strcmp(type, "cfi-flash") == 0) {
222 MtdDeinitSpinorParam();
223 g_spinorPartParam = NULL;
224 } else {
225 return -EINVAL;
226 }
227
228 return ENOERR;
229 }
230
AddParamCheck(UINT32 startAddr,const partition_param * param,UINT32 partitionNum,UINT32 length)231 static INT32 AddParamCheck(UINT32 startAddr,
232 const partition_param *param,
233 UINT32 partitionNum,
234 UINT32 length)
235 {
236 UINT32 startBlk, endBlk;
237 mtd_partition *node = NULL;
238 if ((param->blockname == NULL) && (param->charname == NULL)) {
239 return -EINVAL;
240 }
241
242 if ((length == 0) || (length < param->block_size) ||
243 (((UINT64)(startAddr) + length) > param->flash_mtd->size)) {
244 return -EINVAL;
245 }
246
247 ALIGN_ASSIGN(length, startAddr, startBlk, endBlk, param->block_size);
248
249 if (startBlk > endBlk) {
250 return -EINVAL;
251 }
252 LOS_DL_LIST_FOR_EACH_ENTRY(node, ¶m->partition_head->node_info, mtd_partition, node_info) {
253 if ((node->start_block != 0) && (node->patitionnum == partitionNum)) {
254 return -EINVAL;
255 }
256 if ((startBlk > node->end_block) || (endBlk < node->start_block)) {
257 continue;
258 }
259 return -EINVAL;
260 }
261
262 return ENOERR;
263 }
264
BlockDriverRegisterOperate(mtd_partition * newNode,const partition_param * param,UINT32 partitionNum)265 static INT32 BlockDriverRegisterOperate(mtd_partition *newNode,
266 const partition_param *param,
267 UINT32 partitionNum)
268 {
269 INT32 ret;
270 size_t driverNameSize;
271
272 if (param->blockname != NULL) {
273 driverNameSize = strlen(param->blockname) + DRIVER_NAME_ADD_SIZE;
274 newNode->blockdriver_name = (CHAR *)malloc(driverNameSize);
275 if (newNode->blockdriver_name == NULL) {
276 return -ENOMEM;
277 }
278
279 ret = snprintf_s(newNode->blockdriver_name, driverNameSize,
280 driverNameSize - 1, "%s%u", param->blockname, partitionNum);
281 if (ret < 0) {
282 free(newNode->blockdriver_name);
283 newNode->blockdriver_name = NULL;
284 return -ENAMETOOLONG;
285 }
286
287 ret = register_blockdriver(newNode->blockdriver_name, param->flash_ops,
288 RWE_RW_RW, newNode);
289 if (ret) {
290 free(newNode->blockdriver_name);
291 newNode->blockdriver_name = NULL;
292 PRINT_ERR("register blkdev partition error\n");
293 return ret;
294 }
295 } else {
296 newNode->blockdriver_name = NULL;
297 }
298 return ENOERR;
299 }
300
CharDriverRegisterOperate(mtd_partition * newNode,const partition_param * param,UINT32 partitionNum)301 static INT32 CharDriverRegisterOperate(mtd_partition *newNode,
302 const partition_param *param,
303 UINT32 partitionNum)
304 {
305 INT32 ret;
306 size_t driverNameSize;
307
308 if (param->charname != NULL) {
309 driverNameSize = strlen(param->charname) + DRIVER_NAME_ADD_SIZE;
310 newNode->chardriver_name = (CHAR *)malloc(driverNameSize);
311 if (newNode->chardriver_name == NULL) {
312 return -ENOMEM;
313 }
314
315 ret = snprintf_s(newNode->chardriver_name, driverNameSize,
316 driverNameSize - 1, "%s%u", param->charname, partitionNum);
317 if (ret < 0) {
318 free(newNode->chardriver_name);
319 newNode->chardriver_name = NULL;
320 return -ENAMETOOLONG;
321 }
322
323 ret = register_driver(newNode->chardriver_name, param->char_ops, RWE_RW_RW, newNode);
324 if (ret) {
325 PRINT_ERR("register chardev partition error\n");
326 free(newNode->chardriver_name);
327 newNode->chardriver_name = NULL;
328 return ret;
329 }
330 } else {
331 newNode->chardriver_name = NULL;
332 }
333 return ENOERR;
334 }
335
BlockDriverUnregister(mtd_partition * node)336 static INT32 BlockDriverUnregister(mtd_partition *node)
337 {
338 INT32 ret;
339
340 if (node->blockdriver_name != NULL) {
341 ret = unregister_blockdriver(node->blockdriver_name);
342 if (ret == -EBUSY) {
343 PRINT_ERR("unregister blkdev partition error:%d\n", ret);
344 return ret;
345 }
346 free(node->blockdriver_name);
347 node->blockdriver_name = NULL;
348 }
349 return ENOERR;
350 }
351
CharDriverUnregister(mtd_partition * node)352 static INT32 CharDriverUnregister(mtd_partition *node)
353 {
354 INT32 ret;
355
356 if (node->chardriver_name != NULL) {
357 ret = unregister_driver(node->chardriver_name);
358 if (ret == -EBUSY) {
359 PRINT_ERR("unregister chardev partition error:%d\n", ret);
360 return ret;
361 }
362 free(node->chardriver_name);
363 node->chardriver_name = NULL;
364 }
365
366 return ENOERR;
367 }
368
369 /*
370 * Attention: both startAddr and length should be aligned with block size.
371 * If not, the actual start address and length won't be what you expected.
372 */
add_mtd_partition(const CHAR * type,UINT32 startAddr,UINT32 length,UINT32 partitionNum)373 INT32 add_mtd_partition(const CHAR *type, UINT32 startAddr,
374 UINT32 length, UINT32 partitionNum)
375 {
376 INT32 ret;
377 mtd_partition *newNode = NULL;
378 partition_param *param = NULL;
379
380 if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) || (type == NULL)) {
381 return -EINVAL;
382 }
383
384 ret = pthread_mutex_lock(&g_mtdPartitionLock);
385 if (ret != ENOERR) {
386 PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
387 }
388
389 ret = MtdInitFsparParam(type, ¶m);
390 if (ret != ENOERR) {
391 goto ERROR_OUT;
392 }
393
394 ret = AddParamCheck(startAddr, param, partitionNum, length);
395 if (ret != ENOERR) {
396 goto ERROR_OUT;
397 }
398
399 newNode = (mtd_partition *)zalloc(sizeof(mtd_partition));
400 if (newNode == NULL) {
401 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
402 return -ENOMEM;
403 }
404
405 PAR_ASSIGNMENT(newNode, length, startAddr, partitionNum, param->flash_mtd, param->block_size);
406
407 ret = BlockDriverRegisterOperate(newNode, param, partitionNum);
408 if (ret) {
409 goto ERROR_OUT1;
410 }
411
412 ret = CharDriverRegisterOperate(newNode, param, partitionNum);
413 if (ret) {
414 goto ERROR_OUT2;
415 }
416
417 LOS_ListTailInsert(¶m->partition_head->node_info, &newNode->node_info);
418 (VOID)LOS_MuxInit(&newNode->lock, NULL);
419
420 ret = pthread_mutex_unlock(&g_mtdPartitionLock);
421 if (ret != ENOERR) {
422 PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
423 }
424
425 return ENOERR;
426 ERROR_OUT2:
427 (VOID)BlockDriverUnregister(newNode);
428 ERROR_OUT1:
429 free(newNode);
430 ERROR_OUT:
431 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
432 return ret;
433 }
434
DeleteParamCheck(UINT32 partitionNum,const CHAR * type,partition_param ** param)435 static INT32 DeleteParamCheck(UINT32 partitionNum,
436 const CHAR *type,
437 partition_param **param)
438 {
439 if (strcmp(type, "nand") == 0) {
440 *param = g_nandPartParam;
441 } else if (strcmp(type, "spinor") == 0 || strcmp(type, "cfi-flash") == 0) {
442 *param = g_spinorPartParam;
443 } else {
444 PRINT_ERR("type error \n");
445 return -EINVAL;
446 }
447
448 if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) ||
449 ((*param) == NULL) || ((*param)->flash_mtd == NULL)) {
450 return -EINVAL;
451 }
452 return ENOERR;
453 }
454
DeletePartitionUnregister(mtd_partition * node)455 static INT32 DeletePartitionUnregister(mtd_partition *node)
456 {
457 INT32 ret;
458
459 ret = BlockDriverUnregister(node);
460 if (ret == -EBUSY) {
461 return ret;
462 }
463
464 ret = CharDriverUnregister(node);
465 if (ret == -EBUSY) {
466 return ret;
467 }
468
469 return ENOERR;
470 }
471
OsNodeGet(mtd_partition ** node,UINT32 partitionNum,const partition_param * param)472 static INT32 OsNodeGet(mtd_partition **node, UINT32 partitionNum, const partition_param *param)
473 {
474 LOS_DL_LIST_FOR_EACH_ENTRY(*node, ¶m->partition_head->node_info, mtd_partition, node_info) {
475 if ((*node)->patitionnum == partitionNum) {
476 break;
477 }
478 }
479 if ((*node == NULL) || ((*node)->patitionnum != partitionNum) ||
480 ((*node)->mountpoint_name != NULL)) {
481 return -EINVAL;
482 }
483
484 return ENOERR;
485 }
486
OsResourceRelease(mtd_partition * node,const CHAR * type,partition_param * param)487 static INT32 OsResourceRelease(mtd_partition *node, const CHAR *type, partition_param *param)
488 {
489 (VOID)LOS_MuxDestroy(&node->lock);
490 LOS_ListDelete(&node->node_info);
491 (VOID)memset_s(node, sizeof(mtd_partition), 0, sizeof(mtd_partition));
492 free(node);
493 (VOID)FreeMtd(param->flash_mtd);
494 if (LOS_ListEmpty(¶m->partition_head->node_info)) {
495 free(param->partition_head);
496 param->partition_head = NULL;
497 free(param);
498
499 if (MtdDeinitFsparParam(type) != ENOERR) {
500 return -EINVAL;
501 }
502 }
503 return ENOERR;
504 }
505
delete_mtd_partition(UINT32 partitionNum,const CHAR * type)506 INT32 delete_mtd_partition(UINT32 partitionNum, const CHAR *type)
507 {
508 INT32 ret;
509 mtd_partition *node = NULL;
510 partition_param *param = NULL;
511
512 if (type == NULL) {
513 return -EINVAL;
514 }
515
516 ret = pthread_mutex_lock(&g_mtdPartitionLock);
517 if (ret != ENOERR) {
518 PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
519 }
520
521 ret = DeleteParamCheck(partitionNum, type, ¶m);
522 if (ret) {
523 PRINT_ERR("delete_mtd_partition param invalid\n");
524 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
525 return ret;
526 }
527
528 ret = OsNodeGet(&node, partitionNum, param);
529 if (ret) {
530 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
531 return ret;
532 }
533
534 ret = DeletePartitionUnregister(node);
535 if (ret) {
536 PRINT_ERR("DeletePartitionUnregister error:%d\n", ret);
537 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
538 return ret;
539 }
540
541 ret = OsResourceRelease(node, type, param);
542 if (ret) {
543 PRINT_ERR("DeletePartitionUnregister error:%d\n", ret);
544 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
545 return ret;
546 }
547
548 ret = pthread_mutex_unlock(&g_mtdPartitionLock);
549 if (ret != ENOERR) {
550 PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
551 }
552 return ENOERR;
553 }
554
555