• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param->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, &param);
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(&param->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, &param->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(&param->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, &param);
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