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
43 pthread_mutex_t g_mtdPartitionLock = PTHREAD_MUTEX_INITIALIZER;
44
45 static VOID YaffsLockInit(VOID) __attribute__((weakref("yaffsfs_OSInitialisation")));
46 static VOID YaffsLockDeinit(VOID) __attribute__((weakref("yaffsfs_OsDestroy")));
47 static INT32 Jffs2LockInit(VOID) __attribute__((weakref("Jffs2MutexCreate")));
48 static VOID Jffs2LockDeinit(VOID) __attribute__((weakref("Jffs2MutexDelete")));
49
50 partition_param *g_nandPartParam = NULL;
51 partition_param *g_spinorPartParam = NULL;
52 mtd_partition *g_spinorPartitionHead = NULL;
53 mtd_partition *g_nandPartitionHead = NULL;
54
55 #define RWE_RW_RW 0755
56
GetNandPartParamnull57 partition_param *GetNandPartParam(VOID)
58 {
59 return g_nandPartParam;
60 }
61
GetSpinorPartParamnull62 partition_param *GetSpinorPartParam(VOID)
63 {
64 return g_spinorPartParam;
65 }
66
GetSpinorPartitionHeadnull67 mtd_partition *GetSpinorPartitionHead(VOID)
68 {
69 return g_spinorPartitionHead;
70 }
71
72
MtdNandParamAssign(partition_param *nandParam, const struct MtdDev *nandMtd)73 static 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
MtdDeinitNandParamnull89 static VOID MtdDeinitNandParam(VOID)
90 {
91 if (YaffsLockDeinit != NULL) {
92 YaffsLockDeinit();
93 }
94 }
95
MtdInitNandParam(partition_param *nandParam)96 static 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
MtdNorParamAssign(partition_param *spinorParam, const struct MtdDev *spinorMtd)124 static 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
MtdDeinitSpinorParamnull140 static VOID MtdDeinitSpinorParam(VOID)
141 {
142 if (Jffs2LockDeinit != NULL) {
143 Jffs2LockDeinit();
144 }
145 }
146
MtdInitSpinorParam(partition_param *spinorParam)147 static 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. */
MtdInitFsparParam(const CHAR *type, partition_param **fsparParam)180 static 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. */
MtdDeinitFsparParam(const CHAR *type)200 static 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
AddParamCheck(UINT32 startAddr, const partition_param *param, UINT32 partitionNum, UINT32 length)215 static 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
BlockDriverRegisterOperate(mtd_partition *newNode, const partition_param *param, UINT32 partitionNum)249 static 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
CharDriverRegisterOperate(mtd_partition *newNode, const partition_param *param, UINT32 partitionNum)285 static 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
BlockDriverUnregister(mtd_partition *node)320 static 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
CharDriverUnregister(mtd_partition *node)336 static 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 */
add_mtd_partition(const CHAR *type, UINT32 startAddr, UINT32 length, UINT32 partitionNum)357 INT32 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;
410 ERROR_OUT2:
411 (VOID)BlockDriverUnregister(newNode);
412 ERROR_OUT1:
413 free(newNode);
414 ERROR_OUT:
415 (VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
416 return ret;
417 }
418
DeleteParamCheck(UINT32 partitionNum, const CHAR *type, partition_param **param)419 static 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
DeletePartitionUnregister(mtd_partition *node)439 static 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
OsNodeGet(mtd_partition **node, UINT32 partitionNum, const partition_param *param)456 static 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
OsResourceRelease(mtd_partition *node, const CHAR *type, partition_param *param)471 static 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
delete_mtd_partition(UINT32 partitionNum, const CHAR *type)490 INT32 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