提交 a8e9169e 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

根文件系统rootfs 部分注释

搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
上级 9f85adba
[鸿蒙内核源码注释中文版 【 Gitee仓 ](https://gitee.com/weharmony/kernel_liteos_a_note) | [ CSDN仓 ](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [ Github仓 ](https://github.com/kuangyufei/kernel_liteos_a_note) | [ Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 给 HarmonyOS 源码加上中文注解,详细阐述架构设计和代码实现细节, 快速精读鸿蒙内核源码, 掌握整个鸿蒙内核运行机制,四大码仓每日同步更新.
[鸿蒙源码分析系列篇 【 CSDN ](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA ](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages) 从 HarmonyOS 架构层视角整理成文, 并首创用生活场景讲故事的方式试图去解构内核,一窥究竟。
# **[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note): 鸿蒙内核源码注释中文版**
[![star](https://gitee.com/weharmony/kernel_liteos_a_note/badge/star.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note)[![fork](https://gitee.com/weharmony/kernel_liteos_a_note/badge/fork.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note)
每个码农,职业生涯,都应精读一遍内核源码. 鸿蒙内核源码就是很好的精读项目.一旦熟悉内核代码级实现,将迅速拔高对计算机整体理解,从此高屋建瓴看问题.
## **做了些什么呢**
**[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 是在鸿蒙官方开源项目 **[OpenHarmony/kernel\_liteos\_a](https://gitee.com/openharmony/kernel_liteos_a)** 基础上给源码加上中文注解的版本,目前几大核心模块加注已基本完成,正持续加注完善中...
- ### **为何想给鸿蒙源码加上中文注释**
源于注者大学时阅读linux 2.6 内核痛苦经历,一直有个心愿,想让更多计算机尤其是内核感兴趣的减少阅读时间,加速对计算机系统级的理解,不至于过早的放弃.但因过程种种,一直没有成行,基本要放弃这件事了. 但9月10日鸿蒙正式开源,重新激活了注者多年的心愿,就有那么点一发不可收拾了 :|P
- ### **致敬鸿蒙内核开发者**
感谢开放原子开源基金会,鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此.越深入精读内核源码,越能感受到设计者的精巧用心,创新突破. 向开发者致敬. 可以毫不夸张的说 **[OpenHarmony/kernel\_liteos\_a](https://gitee.com/openharmony/kernel_liteos_a)** 可作为大学C语言,数据结构,操作系统,汇编语言 四门课程的教学项目.如此宝库,不深入研究实在是太可惜了.
### **在加注的源码中有哪些特殊的记号**
搜索 **[@note_pic]()** 可查看绘制的全部字符图
搜索 **[@note_why]()** 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 **[@note_thinking]()** 是注者的思考和吐槽鸿蒙源码的地方
若有好的建议请邮箱**kuangyufei@126.com**或私信联系.
- ### **理解内核的三个层级**
笔者认为理解内核需分三个层级:
第一: **普通概念映射级** 这一级不涉及专业知识,用大众所熟知的公共认知就能听明白是个什么概念,也就是说用一个普通人都懂的概念去诠释或者映射一个他们从没听过的概念.说别人能听得懂的话这很重要!!! 一个没学过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? NO!,笔者在系列篇中试图用 **[鸿蒙源码分析系列篇|张大爷系列故事【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)** 去构建这一层级的认知,希望能卷入更多的人来关注基础软件,尤其是那些有钱的投资人加大对国家基础软件的投入.
第二: **专业概念抽象级** 这一级是抽象出一个专业的逻辑概念,让学过点计算机知识的人能听得懂,可以不用去了解具体的细节点, 比如虚拟内存,老百姓是听不懂的,学过计算机的人都懂,具体怎么实现的很多人又都不懂了,但这并不妨碍成为一个优秀的上层应用程序员,笔者试图用 **[鸿蒙源码分析系列篇 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)** 去构建这一层级的认知,希望能卷入更多对内核感兴趣的应用软件人才流入基础软件生态, 应用软件咱们是无敌宇宙,但基础软件却很薄弱.
第三: **具体微观代码级** 这一级是具体到每一行代码的实现,到了用代码指令级的地步, **[鸿蒙内核源码注释中文版 kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 试图解构这一层级的认知,英文是天生适合设计成编程语言的人类语言,计算机的01码映射到人类世界的26个字母,诞生了太多的伟大奇迹.但我们的母语注定了很大部分人存在着语言层级的映射,希望注释中文版能让更多爱好者参与进来一起研究,拔高咱基础软件的地位.
鸿蒙是面向未来设计的系统,高瞻远瞩,格局远大,设计精良, 知识点巨多, 把研究过程心得写成鸿蒙源码分析系列篇,如此 源码中文注释+系列篇文章 将加速理解鸿蒙内核实现过程.
系列篇文章 进入 >\> [鸿蒙系统源码分析(总目录) 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)查看,两大站点持续更新,感谢CSDN和OSCHINA对博客的推荐支持.
注释中文版 进入 >\> [鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读,四大仓库每日同步更新...
- ### **加注释方式是怎样的?**
因鸿蒙内核6W+代码量,本身只有很少的注释, 中文注解以不对原有代码侵入为前提,源码中所有英文部分都是原有鸿蒙注释,所有中文部分都是笔者的注释,尽量不去增加代码的行数,不破坏文件的结构,笔者试图把每个知识点当场讲透彻,注释多类似以下的方式, 如图举例: 这是申请互斥锁的主体函数,不可谓不重要,但官方注释仅有一行.
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020102821375267.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5neXVmZWk=,size_16,color_FFFFFF,t_70#pic_center)
另外用字符画了一些图方便理解,直接嵌入到头文件中,比如虚拟内存的全景图,因没有这些图是很难理解内存是如何管理的,后续还会陆续加入更多的图方便理解.
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201028154344813.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5neXVmZWk=,size_16,color_FFFFFF,t_70#pic_center)
- ### **仰望星空还是埋头走路**
精读内核源码当然是件很困难的事,时间上要以月为单位,但正因为很难才值得去做! 内心不渴望的永远不可能靠近自己.笔者一直坚信兴趣是最好的老师,加注也是在做自己感兴趣的事.如果能让更多人参与到内核的研究,减少学习的成本,哪怕就节省一天的时间,这么多人能节省多少时间, 这是件多好玩,多有意义的事情啊. 时代需要仰望星空的人,但也需要埋头走路的人, 从鸿蒙一行行的代码中笔者能深深体会到各中艰辛和坚持,及鸿蒙生态对未来的价值,只因心中有目标,就不怕道阻且长.
- ### **新增的zzz目录是干什么的?**
中文加注版比官方版无新增文件,只多了一个zzz的目录,里面放了一些笔者使用的文件,它与内核代码无关,大家可以忽略它,取名zzz是为了排在最后,减少对原有代码目录级的侵入,zzz的想法源于微信中名称为AAA的那批牛人,你的微信里应该也有他们熟悉的身影吧 :|P
- ### **既然选择了远方,就不要怕天高路远,行动起来!**
---
系列篇文章 进入 >\> [鸿蒙系统源码分析(总目录) 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) | [OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)查看
注释中文版 进入 >\> [鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读
内容仅代表个人观点,会反复修正,出精品注解,写精品文章,一律原创,转载需注明出处,不修改内容,不乱插广告,错漏之处欢迎指正笔者第一时间加以完善。
[鸿蒙内核源码注释中文版 【 Gitee仓 ](https://gitee.com/weharmony/kernel_liteos_a_note) | [ CSDN仓 ](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [ Github仓 ](https://github.com/kuangyufei/kernel_liteos_a_note) | [ Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 给 HarmonyOS 源码加上中文注解,详细阐述架构设计和代码实现细节, 快速精读鸿蒙内核源码, 掌握整个鸿蒙内核运行机制,四大码仓每日同步更新.
[鸿蒙源码分析系列篇 【 CSDN ](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA ](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages) 从 HarmonyOS 架构层视角整理成文, 并首创用生活场景讲故事的方式试图去解构内核,一窥究竟。
# **[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note): 鸿蒙内核源码注释中文版**
[![star](https://gitee.com/weharmony/kernel_liteos_a_note/badge/star.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note)[![fork](https://gitee.com/weharmony/kernel_liteos_a_note/badge/fork.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note)
每个码农,职业生涯,都应精读一遍内核源码. 鸿蒙内核源码就是很好的精读项目.一旦熟悉内核代码级实现,将迅速拔高对计算机整体理解,从此高屋建瓴看问题.
## **做了些什么呢**
**[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 是在鸿蒙官方开源项目 **[OpenHarmony/kernel\_liteos\_a](https://gitee.com/openharmony/kernel_liteos_a)** 基础上给源码加上中文注解的版本,目前几大核心模块加注已基本完成,正持续加注完善中...
- ### **为何想给鸿蒙源码加上中文注释**
源于注者大学时阅读linux 2.6 内核痛苦经历,一直有个心愿,想让更多计算机尤其是内核感兴趣的减少阅读时间,加速对计算机系统级的理解,不至于过早的放弃.但因过程种种,一直没有成行,基本要放弃这件事了. 但9月10日鸿蒙正式开源,重新激活了注者多年的心愿,就有那么点一发不可收拾了 :|P
- ### **致敬鸿蒙内核开发者**
感谢开放原子开源基金会,鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此.越深入精读内核源码,越能感受到设计者的精巧用心,创新突破. 向开发者致敬. 可以毫不夸张的说 **[OpenHarmony/kernel\_liteos\_a](https://gitee.com/openharmony/kernel_liteos_a)** 可作为大学C语言,数据结构,操作系统,汇编语言 四门课程的教学项目.如此宝库,不深入研究实在是太可惜了.
### **在加注的源码中有哪些特殊的记号**
搜索 **[@note_pic]()** 可查看绘制的全部字符图
搜索 **[@note_why]()** 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 **[@note_thinking]()** 是注者的思考和吐槽鸿蒙源码的地方
- ### **理解内核的三个层级**
笔者认为理解内核需分三个层级:
第一: **普通概念映射级** 这一级不涉及专业知识,用大众所熟知的公共认知就能听明白是个什么概念,也就是说用一个普通人都懂的概念去诠释或者映射一个他们从没听过的概念.说别人能听得懂的话这很重要!!! 一个没学过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? NO!,笔者在系列篇中试图用 **[鸿蒙源码分析系列篇|张大爷系列故事【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)** 去构建这一层级的认知,希望能卷入更多的人来关注基础软件,尤其是那些有钱的投资人加大对国家基础软件的投入.
第二: **专业概念抽象级** 这一级是抽象出一个专业的逻辑概念,让学过点计算机知识的人能听得懂,可以不用去了解具体的细节点, 比如虚拟内存,老百姓是听不懂的,学过计算机的人都懂,具体怎么实现的很多人又都不懂了,但这并不妨碍成为一个优秀的上层应用程序员,笔者试图用 **[鸿蒙源码分析系列篇 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)** 去构建这一层级的认知,希望能卷入更多对内核感兴趣的应用软件人才流入基础软件生态, 应用软件咱们是无敌宇宙,但基础软件却很薄弱.
第三: **具体微观代码级** 这一级是具体到每一行代码的实现,到了用代码指令级的地步, **[鸿蒙内核源码注释中文版 kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 试图解构这一层级的认知,英文是天生适合设计成编程语言的人类语言,计算机的01码映射到人类世界的26个字母,诞生了太多的伟大奇迹.但我们的母语注定了很大部分人存在着语言层级的映射,希望注释中文版能让更多爱好者参与进来一起研究,拔高咱基础软件的地位.
鸿蒙是面向未来设计的系统,高瞻远瞩,格局远大,设计精良, 知识点巨多, 把研究过程心得写成鸿蒙源码分析系列篇,如此 源码中文注释+系列篇文章 将加速理解鸿蒙内核实现过程.
系列篇文章 进入 >\> [鸿蒙系统源码分析(总目录) 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)查看,两大站点持续更新,感谢CSDN和OSCHINA对博客的推荐支持.
注释中文版 进入 >\> [鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读,四大仓库每日同步更新...
- ### **加注释方式是怎样的?**
因鸿蒙内核6W+代码量,本身只有很少的注释, 中文注解以不对原有代码侵入为前提,源码中所有英文部分都是原有鸿蒙注释,所有中文部分都是笔者的注释,尽量不去增加代码的行数,不破坏文件的结构,笔者试图把每个知识点当场讲透彻,注释多类似以下的方式, 如图举例: 这是申请互斥锁的主体函数,不可谓不重要,但官方注释仅有一行.
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020102821375267.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5neXVmZWk=,size_16,color_FFFFFF,t_70#pic_center)
另外用字符画了一些图方便理解,直接嵌入到头文件中,比如虚拟内存的全景图,因没有这些图是很难理解内存是如何管理的,后续还会陆续加入更多的图方便理解.
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201028154344813.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5neXVmZWk=,size_16,color_FFFFFF,t_70#pic_center)
- ### **仰望星空还是埋头走路**
精读内核源码当然是件很困难的事,时间上要以月为单位,但正因为很难才值得去做! 内心不渴望的永远不可能靠近自己.笔者一直坚信兴趣是最好的老师,加注也是在做自己感兴趣的事.如果能让更多人参与到内核的研究,减少学习的成本,哪怕就节省一天的时间,这么多人能节省多少时间, 这是件多好玩,多有意义的事情啊. 时代需要仰望星空的人,但也需要埋头走路的人, 从鸿蒙一行行的代码中笔者能深深体会到各中艰辛和坚持,及鸿蒙生态对未来的价值,只因心中有目标,就不怕道阻且长.
- ### **新增的zzz目录是干什么的?**
中文加注版比官方版无新增文件,只多了一个zzz的目录,里面放了一些笔者使用的文件,它与内核代码无关,大家可以忽略它,取名zzz是为了排在最后,减少对原有代码目录级的侵入,zzz的想法源于微信中名称为AAA的那批牛人,你的微信里应该也有他们熟悉的身影吧 :|P
- ### **参与贡献**
1. Fork 本仓库 >> 新建 Feat_xxx 分支 >> 提交代码注解 >> 新建 Pull Request
2. [新建 Issue](https://gitee.com/weharmony/kernel_liteos_a_note/issues)
- ### **联系方式**
kuangyufei@126.com
---
系列篇文章 进入 >\> [鸿蒙系统源码分析(总目录) 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) | [OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)查看
注释中文版 进入 >\> [鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读
# ![](https://oscimg.oschina.net/oscnet/up-c1f5f5e88b38fcb25f274a2062384b0c61e.png)
\ No newline at end of file
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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.
*/
/**
* @defgroup disk Disk
* @ingroup filesystem
*/
#ifndef _DISK_H
#define _DISK_H
#include "los_base.h"
#ifdef LOSCFG_FS_FAT_CACHE
#include "bcache.h"
#else
#include "inode/inode.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define SYS_MAX_DISK 5
#define MAX_DIVIDE_PART_PER_DISK 16
#define MAX_PRIMARY_PART_PER_DISK 4
#define SYS_MAX_PART (SYS_MAX_DISK * MAX_DIVIDE_PART_PER_DISK)
#define DISK_NAME 255
#define DISK_MAX_SECTOR_SIZE 512
#define PAR_OFFSET 446 /* MBR: Partition table offset (2) */
#define BS_SIG55AA 510 /* Signature word (2) */
#define BS_FILSYSTEMTYPE32 82 /* File system type (1) */
#define BS_JMPBOOT 0 /* x86 jump instruction (3-byte) */
#define BS_FILSYSTYPE 0x36 /* File system type (2) */
#define BS_SIG55AA_VALUE 0xAA55
#define PAR_TYPE_OFFSET 4
#define PAR_START_OFFSET 8
#define PAR_COUNT_OFFSET 12
#define PAR_TABLE_SIZE 16
#define EXTENDED_PAR 0x0F
#define EXTENDED_8G 0x05
#define EMMC 0xEC
#define OTHERS 0x01 /* sdcard or umass */
#define BS_FS_TYPE_MASK 0xFFFFFF
#define BS_FS_TYPE_VALUE 0x544146
#define BS_FS_TYPE_FAT 0x0B
#define BS_FS_TYPE_NTFS 0x07
#define FIRST_BYTE 1
#define SECOND_BYTE 2
#define THIRD_BYTE 3
#define FOURTH_BYTE 4
#define BIT_FOR_BYTE 8
#define LD_WORD_DISK(ptr) (UINT16)(((UINT16)*((UINT8 *)(ptr) + FIRST_BYTE) << (BIT_FOR_BYTE * FIRST_BYTE)) | \
(UINT16)*(UINT8 *)(ptr))
#define LD_DWORD_DISK(ptr) (UINT32)(((UINT32)*((UINT8 *)(ptr) + THIRD_BYTE) << (BIT_FOR_BYTE * THIRD_BYTE)) | \
((UINT32)*((UINT8 *)(ptr) + SECOND_BYTE) << (BIT_FOR_BYTE * SECOND_BYTE)) | \
((UINT16)*((UINT8 *)(ptr) + FIRST_BYTE) << (BIT_FOR_BYTE * FIRST_BYTE)) | \
(*(UINT8 *)(ptr)))
#define LD_QWORD_DISK(ptr) ((UINT64)(((UINT64)LD_DWORD_DISK(&(ptr)[FOURTH_BYTE]) << (BIT_FOR_BYTE * FOURTH_BYTE)) | \
LD_DWORD_DISK(ptr)))
/* Check VBR string, including FAT, NTFS */
#define VERIFY_FS(ptr) (((LD_DWORD_DISK(&(ptr)[BS_FILSYSTEMTYPE32]) & BS_FS_TYPE_MASK) == BS_FS_TYPE_VALUE) || \
!strncmp(&(ptr)[BS_FILSYSTYPE], "FAT", strlen("FAT")) || \
!strncmp(&(ptr)[BS_JMPBOOT], "\xEB\x52\x90" "NTFS ", \
strlen("\xEB\x52\x90" "NTFS ")))
#define PARTION_MODE_BTYE (PAR_OFFSET + PAR_TYPE_OFFSET) /* 0xEE: GPT(GUID), else: MBR */
#define PARTION_MODE_GPT 0xEE /* 0xEE: GPT(GUID), else: MBR */
#define SIGNATURE_OFFSET 0 /* The offset of GPT partition header signature */
#define SIGNATURE_LEN 8 /* The length of GPT signature */
#define HEADER_SIZE_OFFSET 12 /* The offset of GPT header size */
#define TABLE_SIZE_OFFSET 84 /* The offset of GPT table size */
#define TABLE_NUM_OFFSET 80 /* The number of GPT table */
#define TABLE_START_SECTOR 2
#define TABLE_MAX_NUM 128
#define TABLE_SIZE 128
#define GPT_PAR_START_OFFSET 32
#define GPT_PAR_END_OFFSET 40
#define PAR_ENTRY_NUM_PER_SECTOR 4
#define HEADER_SIZE_MASK 0xFFFFFFFF
#define HEADER_SIZE 0x5C
#define HARD_DISK_GUID_OFFSET 56
#define HARD_DISK_GUID_FOR_ESP 0x0020004900460045
#define HARD_DISK_GUID_FOR_MSP 0x007200630069004D
#define PAR_VALID_OFFSET0 0
#define PAR_VALID_OFFSET1 4
#define PAR_VALID_OFFSET2 8
#define PAR_VALID_OFFSET3 12
#define VERIFY_GPT(ptr) ((!strncmp(&(ptr)[SIGNATURE_OFFSET], "EFI PART", SIGNATURE_LEN)) && \
((LD_DWORD_DISK(&(ptr)[HEADER_SIZE_OFFSET]) & HEADER_SIZE_MASK) == HEADER_SIZE))
#define VERITY_PAR_VALID(ptr) ((LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET0]) + \
LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET1]) + \
LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET2]) + \
LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET3])) != 0)
/* ESP MSP */
#define VERITY_AVAILABLE_PAR(ptr) ((LD_QWORD_DISK(&(ptr)[HARD_DISK_GUID_OFFSET]) != HARD_DISK_GUID_FOR_ESP) && \
(LD_QWORD_DISK(&(ptr)[HARD_DISK_GUID_OFFSET]) != HARD_DISK_GUID_FOR_MSP))
/* Command code for disk_ioctrl function */
/* Generic command (Used by FatFs) */
#define DISK_CTRL_SYNC 0 /* Complete pending write process */
#define DISK_GET_SECTOR_COUNT 1 /* Get media size */
#define DISK_GET_SECTOR_SIZE 2 /* Get sector size */
#define DISK_GET_BLOCK_SIZE 3 /* Get erase block size */
#define DISK_CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used */
/* Generic command (Not used by FatFs) */
#define DISK_CTRL_POWER 5 /* Get/Set power status */
#define DISK_CTRL_LOCK 6 /* Lock/Unlock media removal */
#define DISK_CTRL_EJECT 7 /* Eject media */
#define DISK_CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define DISK_MMC_GET_TYPE 10 /* Get card type */
#define DISK_MMC_GET_CSD 11 /* Get CSD */
#define DISK_MMC_GET_CID 12 /* Get CID */
#define DISK_MMC_GET_OCR 13 /* Get OCR */
#define DISK_MMC_GET_SDSTAT 14 /* Get SD status */
/* ATA/CF specific ioctl command */
#define DISK_ATA_GET_REV 20 /* Get F/W revision */
#define DISK_ATA_GET_MODEL 21 /* Get model name */
#define DISK_ATA_GET_SN 22 /* Get serial number */
typedef enum _disk_status_ {//磁盘的状态
STAT_UNUSED, //未使用
STAT_INUSED, //使用中
STAT_UNREADY //未准备,可理解为未格式化
} disk_status_e;
typedef struct _los_disk_ { //磁盘描述符
UINT32 disk_id : 8; /* physics disk number */ //标识磁盘ID
UINT32 disk_status : 2; /* status of disk */ //磁盘的状态 disk_status_e
UINT32 part_count : 8; /* current partition count */ //分了多少个区(los_part)
UINT32 reserved : 14; //保留,注意 disk_id|disk_status|part_count|reserved 共用一个UINT32
struct inode *dev; /* device */
#ifdef LOSCFG_FS_FAT_CACHE //磁盘缓存,在所有分区中共享
OsBcache *bcache; /* cache of the disk, shared in all partitions */
#endif
UINT32 sector_size; /* disk sector size */ //扇区大小
UINT64 sector_start; /* disk start sector */ //开始扇区
UINT64 sector_count; /* disk sector number *///扇区数量
UINT8 type; //flash的类型 例如:EMMC
CHAR *disk_name; //设备名称
LOS_DL_LIST head; /* link head of all the partitions */ //双向链表上挂所有分区(los_part->list)
struct pthread_mutex disk_mutex;
} los_disk;
typedef struct _los_part_ {//分区描述符
UINT32 disk_id : 8; /* physics disk number */ //标识磁盘ID
UINT32 part_id : 8; /* partition number in the system */ //标识整个系统的分区数量
UINT32 part_no_disk : 8; /* partition number in the disk */ //标识所属磁盘的分区数量
UINT32 part_no_mbr : 5; /* partition number in the mbr */ //硬盘主引导记录(即Master Boot Record,一般简称为MBR),主分区数量
UINT32 reserved : 3; ////保留,注意 disk_id|part_id|part_no_disk|part_no_mbr|reserved 共用一个UINT32
UINT8 filesystem_type; /* filesystem used in the partition */ //文件系统类型
UINT8 type; //flash的类型 例如:EMMC
struct inode *dev; /* dev devices used in the partition */ //分区所使用的dev设备
CHAR *part_name; //区名称
UINT64 sector_start; /* //开始扇区编号
* offset of a partition to the primary devices
* (multi-mbr partitions are seen as same parition)
*/
UINT64 sector_count; /* //扇区数量
* sector numbers of a partition. If there is no addpartition operation,
* then all the mbr devices equal to the primary device count.
*/
LOS_DL_LIST list; /* linklist of partition */ //通过它挂到los_disk->head上
} los_part;
struct partition_info {
UINT8 type;
UINT64 sector_start;
UINT64 sector_count;
};
struct disk_divide_info {
UINT64 sector_count;
UINT32 sector_size;
UINT32 part_count;
/*
* The primary partition place should be reversed and set to 0 in case all the partitions are
* logical partition (maximum 16 currently). So the maximum part number should be 4 + 16.
*/
struct partition_info part[MAX_DIVIDE_PART_PER_DISK + MAX_PRIMARY_PART_PER_DISK];
};
/**
* @ingroup disk
* @brief Disk driver initialization.
*
* @par Description:
* Initializate a disk dirver, and set the block cache.
*
* @attention
* <ul>
* <li>The parameter diskName must point a valid string, which end with the terminating null byte.</li>
* <li>The total length of parameter diskName must be less than the value defined by PATH_MAX.</li>
* <li>The parameter bops must pointed the right functions, otherwise the system
* will crash when the disk is being operated.</li>
* <li>The parameter info can be null or point to struct disk_divide_info. when info is null,
* the disk will be divided base the information of MBR, otherwise,
* the disk will be divided base the information of parameter info.</li>
* </ul>
*
* @param diskName [IN] Type #const CHAR * disk driver name.
* @param bops [IN] Type #const struct block_operations * block driver control sturcture.
* @param priv [IN] Type #VOID * private data of inode.
* @param diskID [IN] Type #INT32 disk id number, less than SYS_MAX_DISK.
* @param info [IN] Type #VOID * disk driver partition information.
*
* @retval #0 Initialization success.
* @retval #-1 Initialization failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_deinit
*
*/
INT32 los_disk_init(const CHAR *diskName, const struct block_operations *bops,
VOID *priv, INT32 diskID, VOID *info);
/**
* @ingroup disk
* @brief Destroy a disk driver.
*
* @par Description:
* Destroy a disk driver, free the dependent resource.
*
* @attention
* <ul>
* None
* </ul>
*
* @param diskID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
*
* @retval #0 Destroy success.
* @retval #-1 Destroy failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_init
*
*/
INT32 los_disk_deinit(INT32 diskID);
/**
* @ingroup disk
* @brief Read data from disk driver.
*
* @par Description:
* Read data from disk driver.
*
* @attention
* <ul>
* <li>The sector size of the disk to be read should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to a valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param buf [OUT] Type #VOID * memory which used to store read data.
* @param sector [IN] Type #UINT64 expected start sector number to read.
* @param count [IN] Type #UINT32 expected sector count to read.
*
* @retval #0 Read success.
* @retval #-1 Read failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_write
*
*/
INT32 los_disk_read(INT32 drvID, VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Write data to a disk driver.
*
* @par Description:
* Write data to a disk driver.
*
* @attention
* <ul>
* <li>The sector size of the disk to be read should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to a valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param buf [IN] Type #const VOID * memory which used to storage write data.
* @param sector [IN] Type #UINT64 expected start sector number to read.
* @param count [IN] Type #UINT32 experted sector count of write.
*
* @retval #0 Write success.
* @retval #-1 Write failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_read
*
*/
INT32 los_disk_write(INT32 drvID, const VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Get information of disk driver.
*
* @par Description:
* Get information of disk driver.
*
* @attention
* <ul>
* None
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param cmd [IN] Type #INT32 command to issu, currently support GET_SECTOR_COUNT, GET_SECTOR_SIZE,
* GET_BLOCK_SIZE, CTRL_SYNC.
* @param buf [OUT] Type #VOID * memory to storage the information, the size must enough for data type(UINT64)
* when cmd type is DISK_GET_SECTOR_COUNT, others is size_t.
*
* @retval #0 Get information success.
* @retval #-1 Get information failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_disk_ioctl(INT32 drvID, INT32 cmd, VOID *buf);
/**
* @ingroup disk
* @brief Sync blib cache.
*
* @par Description:
* Sync blib cache, write the valid data to disk driver.
*
* @attention
* <ul>
* None
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
*
* @retval #0 Sync success.
* @retval #INT32 Sync failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_disk_sync(INT32 drvID);
/**
* @ingroup disk
* @brief Set blib cache for the disk driver.
*
* @par Description:
* Set blib cache for the disk driver, users can set the number of sectors of per block,
* and the number of blocks.
*
* @attention
* <ul>
* None
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param sectorPerBlock [IN] Type #UINT32 sector number of per block, only can be 32 * (1, 2, ..., 8).
* @param blockNum [IN] Type #UINT32 block number of cache.
*
* @retval #0 Set success.
* @retval #INT32 Set failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_disk_set_bcache(INT32 drvID, UINT32 sectorPerBlock, UINT32 blockNum);
/**
* @ingroup disk
* @brief Read data from chosen partition.
*
* @par Description:
* Read data from chosen partition.
*
* @attention
* <ul>
* <li>The sector size of the disk to be read should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param pt [IN] Type #INT32 partition number, less than the value defined by SYS_MAX_PART.
* @param buf [OUT] Type #VOID * memory which used to store the data to be read.
* @param sector [IN] Type #UINT64 start sector number of chosen partition.
* @param count [IN] Type #UINT32 the expected sector count for reading.
*
* @retval #0 Read success.
* @retval #-1 Read failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_part_read
*
*/
INT32 los_part_read(INT32 pt, VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Write data to chosen partition.
*
* @par Description:
* Write data to chosen partition.
*
* @attention
* <ul>
* <li>The sector size of the disk to be write should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param pt [IN] Type #INT32 partition number,less than the value defined by SYS_MAX_PART.
* @param buf [IN] Type #VOID * memory which used to storage the written data.
* @param sector [IN] Type #UINT64 start sector number of chosen partition.
* @param count [IN] Type #UINT32 the expected sector count for write.
*
* @retval #0 Write success.
* @retval #-1 Write failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_part_read
*
*/
INT32 los_part_write(INT32 pt, VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Get information of chosen partition.
*
* @par Description:
* By passed command to get information of chosen partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param pt [IN] Type #INT32 partition number,less than the value defined by SYS_MAX_PART.
* @param cmd [IN] Type #INT32 command to issu, currently support GET_SECTOR_COUNT, GET_SECTOR_SIZE,
* GET_BLOCK_SIZE, CTRL_SYNC.
* @param buf [OUT] Type #VOID * memory to store the information, the size must enough for data type (UINT64)
* when cmd type is DISK_GET_SECTOR_COUNT, others is size_t.
*
* @retval #0 Get information success.
* @retval #-1 Get information failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_part_ioctl(INT32 pt, INT32 cmd, VOID *buf);
/**
* @ingroup disk
* @brief Decide the chosen partition is exist or not.
*
* @par Description:
* Decide the chosen partition is exist or not.
*
* @attention
* <ul>
* <li>The parameter dev is a full path, which begin with '/' and end with '/0'.</li>
* </ul>
*
* @param dev [IN] Type #const CHAR * partition driver name.
* @param mode [IN] Type #mode_t access modd.
*
* @retval #0 The chosen partition is exist.
* @retval #-1 The chosen partition is not exist.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_part_access(const CHAR *dev, mode_t mode);
/**
* @ingroup disk
* @brief Find disk partition.
*
* @par Description:
* By driver partition inode to find disk partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param blkDriver [IN] Type #struct inode * partition driver inode.
*
* @retval #NULL Can't find chosen disk partition.
* @retval #los_part * This is partition structure pointer of chosen disk partition.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
los_part *los_part_find(struct inode *blkDriver);
/**
* @ingroup disk
* @brief Find disk driver.
*
* @par Description:
* By disk driver id number to find disk dirver.
*
* @attention
* <ul>
* None
* </ul>
*
* @param id [IN] Type #INT32 disk id number,less than the value defined by SYS_MAX_DISK.
*
* @retval #NULL Can't find chosen disk driver.
* @retval #los_disk * This is disk structure pointer of chosen disk driver.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
los_disk *get_disk(INT32 id);
/**
* @ingroup disk
* @brief Find disk partition.
*
* @par Description:
* By driver partition id number to find disk partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param id [IN] Type #INT32 partition id number,less than the value defined by SYS_MAX_PART.
*
* @retval #NULL Can't find chosen disk partition.
* @retval #los_part * This is partition structure pointer of chosen disk partition.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
los_part *get_part(INT32 id);
/**
* @ingroup disk
* @brief Print partition information.
*
* @par Description:
* Print partition information.
*
* @attention
* <ul>
* None
* </ul>
*
* @param part [IN] Type #los_part * partition control structure pointer
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
VOID show_part(los_part *part);
/**
* @ingroup disk
* @brief Add a new mmc partition.
*
* @par Description:
* Add a new mmc partition, users can set the start sector and size of the new partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param info [IN] Type #struct disk_divide_info * Disk driver information structure pointer.
* @param sectorStart [IN] Type #size_t Start sector number of the new partition.
* @param sectorCount [IN] Type #size_t Sector count of the new partition.
*
* @retval #0 Add partition success.
* @retval #-1 Add partition failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 add_mmc_partition(struct disk_divide_info *info, size_t sectorStart, size_t sectorCount);
/**
* @ingroup disk
* @brief alloc a new UNUSED disk id.
*
* @par Description:
* Get a free disk id for new device.
*
* @attention
* <ul>
* <li>The parameter diskName must point a valid string, which end with the null byte ('\0') </li>
* <li>The total length of parameter diskName must be less than the value defined by DISK_NAME </li>
* </ul>
*
* @param diskName [IN] Type #const CHAR * device name.
*
* @retval #INT32 available disk id
* @retval #-1 alloc disk id failed
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_get_diskid_byname
*
*/
INT32 los_alloc_diskid_byname(const CHAR *diskName);
/**
* @ingroup disk
* @brief get the INUSED disk id.
*
* @par Description:
* Get the correponding INUSED disk id by diskName.
*
* @attention
* <ul>
* <li>The parameter diskName must point a valid string, which end with the null byte ('\0') </li>
* <li>The total length of parameter diskName must be less than the value defined by DISK_NAME </li>
* </ul>
*
* @param diskName [IN] Type #const CHAR * device name.
*
* @retval #INT32 available disk id
* @retval #-1 get disk id failed
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_alloc_diskid_byname
*
*/
INT32 los_get_diskid_byname(const CHAR *diskName);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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.
*/
/**
* @defgroup disk Disk
* @ingroup filesystem
*/
#ifndef _DISK_H
#define _DISK_H
#include "los_base.h"
#ifdef LOSCFG_FS_FAT_CACHE
#include "bcache.h"
#else
#include "inode/inode.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
/***********************************************
https://blog.csdn.net/buzaikoulan/article/details/44405915
MBR 全称为Master Boot Record,即硬盘的主引导记录,硬盘分区有三种,主磁盘分区、扩展磁盘分区、逻辑分区
主分区:也叫引导分区,硬盘的启动分区,最多可能创建4个
扩展磁盘分区:除了主分区外,剩余的磁盘空间就是扩展分区了,扩展分区可以没有,最多1个。
逻辑分区:在扩展分区上面,可以创建多个逻辑分区。逻辑分区相当于一块存储截止,和操作系统还有别的逻辑分区、主分区没有什么关系,是“独立的”。
硬盘的容量=主分区的容量+扩展分区的容量
扩展分区的容量=各个逻辑分区的容量之和
通俗的讲主分区是硬盘的主人,而扩展分区是这个硬盘上的仆人,主分区和扩展分区为主从关系。
给新硬盘上建立分区时都要遵循以下的顺序:建立主分区→建立扩展分区→建立逻辑分区→激活主分区→格式化所有分区
--------------------------
与MBR对应的是GPT,是对超大容量磁盘的一种分区格式
GPT,即Globally Unique Identifier Partition Table Format,全局唯一标识符的分区表的格式。
这种分区模式相比MBR有着非常多的优势。
首先,它至少可以分出128个分区,完全不需要扩展分区和逻辑分区来帮忙就可以分出任何想要的分区来。
其次,GPT最大支持18EB的硬盘,几乎就相当于没有限制。
***********************************************/
#define SYS_MAX_DISK 5 //最大支持磁盘数量
#define MAX_DIVIDE_PART_PER_DISK 16 //磁盘最大支持逻辑分区数
#define MAX_PRIMARY_PART_PER_DISK 4 //磁盘最大支持主分区数
#define SYS_MAX_PART (SYS_MAX_DISK * MAX_DIVIDE_PART_PER_DISK) //系统最大支持分区数
#define DISK_NAME 255 //磁盘名称
#define DISK_MAX_SECTOR_SIZE 512 //扇区大小,字节
#define PAR_OFFSET 446 /* MBR: Partition table offset (2) */
#define BS_SIG55AA 510 /* Signature word (2) */
#define BS_FILSYSTEMTYPE32 82 /* File system type (1) */
#define BS_JMPBOOT 0 /* x86 jump instruction (3-byte) */
#define BS_FILSYSTYPE 0x36 /* File system type (2) */
#define BS_SIG55AA_VALUE 0xAA55
#define PAR_TYPE_OFFSET 4
#define PAR_START_OFFSET 8
#define PAR_COUNT_OFFSET 12
#define PAR_TABLE_SIZE 16
#define EXTENDED_PAR 0x0F //扩展分区
#define EXTENDED_8G 0x05 //
#define EMMC 0xEC //eMMC=NAND闪存+闪存控制芯片+标准接口封装
#define OTHERS 0x01 /* sdcard or umass */
#define BS_FS_TYPE_MASK 0xFFFFFF
#define BS_FS_TYPE_VALUE 0x544146
#define BS_FS_TYPE_FAT 0x0B
#define BS_FS_TYPE_NTFS 0x07
#define FIRST_BYTE 1
#define SECOND_BYTE 2
#define THIRD_BYTE 3
#define FOURTH_BYTE 4
#define BIT_FOR_BYTE 8
#define LD_WORD_DISK(ptr) (UINT16)(((UINT16)*((UINT8 *)(ptr) + FIRST_BYTE) << (BIT_FOR_BYTE * FIRST_BYTE)) | \
(UINT16)*(UINT8 *)(ptr))
#define LD_DWORD_DISK(ptr) (UINT32)(((UINT32)*((UINT8 *)(ptr) + THIRD_BYTE) << (BIT_FOR_BYTE * THIRD_BYTE)) | \
((UINT32)*((UINT8 *)(ptr) + SECOND_BYTE) << (BIT_FOR_BYTE * SECOND_BYTE)) | \
((UINT16)*((UINT8 *)(ptr) + FIRST_BYTE) << (BIT_FOR_BYTE * FIRST_BYTE)) | \
(*(UINT8 *)(ptr)))
#define LD_QWORD_DISK(ptr) ((UINT64)(((UINT64)LD_DWORD_DISK(&(ptr)[FOURTH_BYTE]) << (BIT_FOR_BYTE * FOURTH_BYTE)) | \
LD_DWORD_DISK(ptr)))
/* Check VBR string, including FAT, NTFS */
#define VERIFY_FS(ptr) (((LD_DWORD_DISK(&(ptr)[BS_FILSYSTEMTYPE32]) & BS_FS_TYPE_MASK) == BS_FS_TYPE_VALUE) || \
!strncmp(&(ptr)[BS_FILSYSTYPE], "FAT", strlen("FAT")) || \
!strncmp(&(ptr)[BS_JMPBOOT], "\xEB\x52\x90" "NTFS ", \
strlen("\xEB\x52\x90" "NTFS ")))
#define PARTION_MODE_BTYE (PAR_OFFSET + PAR_TYPE_OFFSET) /* 0xEE: GPT(GUID), else: MBR */
#define PARTION_MODE_GPT 0xEE /* 0xEE: GPT(GUID), else: MBR */
#define SIGNATURE_OFFSET 0 /* The offset of GPT partition header signature */
#define SIGNATURE_LEN 8 /* The length of GPT signature */
#define HEADER_SIZE_OFFSET 12 /* The offset of GPT header size */
#define TABLE_SIZE_OFFSET 84 /* The offset of GPT table size */
#define TABLE_NUM_OFFSET 80 /* The number of GPT table */
#define TABLE_START_SECTOR 2
#define TABLE_MAX_NUM 128
#define TABLE_SIZE 128
#define GPT_PAR_START_OFFSET 32
#define GPT_PAR_END_OFFSET 40
#define PAR_ENTRY_NUM_PER_SECTOR 4
#define HEADER_SIZE_MASK 0xFFFFFFFF
#define HEADER_SIZE 0x5C
#define HARD_DISK_GUID_OFFSET 56
#define HARD_DISK_GUID_FOR_ESP 0x0020004900460045
#define HARD_DISK_GUID_FOR_MSP 0x007200630069004D
#define PAR_VALID_OFFSET0 0
#define PAR_VALID_OFFSET1 4
#define PAR_VALID_OFFSET2 8
#define PAR_VALID_OFFSET3 12
#define VERIFY_GPT(ptr) ((!strncmp(&(ptr)[SIGNATURE_OFFSET], "EFI PART", SIGNATURE_LEN)) && \
((LD_DWORD_DISK(&(ptr)[HEADER_SIZE_OFFSET]) & HEADER_SIZE_MASK) == HEADER_SIZE))
#define VERITY_PAR_VALID(ptr) ((LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET0]) + \
LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET1]) + \
LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET2]) + \
LD_DWORD_DISK(&(ptr)[PAR_VALID_OFFSET3])) != 0)
/* ESP MSP */
#define VERITY_AVAILABLE_PAR(ptr) ((LD_QWORD_DISK(&(ptr)[HARD_DISK_GUID_OFFSET]) != HARD_DISK_GUID_FOR_ESP) && \
(LD_QWORD_DISK(&(ptr)[HARD_DISK_GUID_OFFSET]) != HARD_DISK_GUID_FOR_MSP))
/* Command code for disk_ioctrl function */
/* Generic command (Used by FatFs) */
#define DISK_CTRL_SYNC 0 /* Complete pending write process */
#define DISK_GET_SECTOR_COUNT 1 /* Get media size */
#define DISK_GET_SECTOR_SIZE 2 /* Get sector size */
#define DISK_GET_BLOCK_SIZE 3 /* Get erase block size */
#define DISK_CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used */
/* Generic command (Not used by FatFs) */
#define DISK_CTRL_POWER 5 /* Get/Set power status */
#define DISK_CTRL_LOCK 6 /* Lock/Unlock media removal */
#define DISK_CTRL_EJECT 7 /* Eject media */
#define DISK_CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define DISK_MMC_GET_TYPE 10 /* Get card type */
#define DISK_MMC_GET_CSD 11 /* Get CSD */
#define DISK_MMC_GET_CID 12 /* Get CID */
#define DISK_MMC_GET_OCR 13 /* Get OCR */
#define DISK_MMC_GET_SDSTAT 14 /* Get SD status */
/* ATA/CF specific ioctl command */
#define DISK_ATA_GET_REV 20 /* Get F/W revision */
#define DISK_ATA_GET_MODEL 21 /* Get model name */
#define DISK_ATA_GET_SN 22 /* Get serial number */
typedef enum _disk_status_ {//磁盘的状态
STAT_UNUSED, //未使用
STAT_INUSED, //使用中
STAT_UNREADY //未准备,可理解为未格式化
} disk_status_e;
typedef struct _los_disk_ { //磁盘描述符
UINT32 disk_id : 8; /* physics disk number */ //标识磁盘ID
UINT32 disk_status : 2; /* status of disk */ //磁盘的状态 disk_status_e
UINT32 part_count : 8; /* current partition count */ //分了多少个区(los_part)
UINT32 reserved : 14; //保留,注意 disk_id|disk_status|part_count|reserved 共用一个UINT32
struct inode *dev; /* device */
#ifdef LOSCFG_FS_FAT_CACHE //磁盘缓存,在所有分区中共享
OsBcache *bcache; /* cache of the disk, shared in all partitions */
#endif
UINT32 sector_size; /* disk sector size */ //扇区大小
UINT64 sector_start; /* disk start sector */ //开始扇区
UINT64 sector_count; /* disk sector number *///扇区数量
UINT8 type; //flash的类型 例如:EMMC
CHAR *disk_name; //设备名称
LOS_DL_LIST head; /* link head of all the partitions */ //双向链表上挂所有分区(los_part->list)
struct pthread_mutex disk_mutex;
} los_disk;
typedef struct _los_part_ {//分区描述符
UINT32 disk_id : 8; /* physics disk number */ //标识磁盘ID
UINT32 part_id : 8; /* partition number in the system */ //标识整个系统的分区数量
UINT32 part_no_disk : 8; /* partition number in the disk */ //标识所属磁盘的分区数量
UINT32 part_no_mbr : 5; /* partition number in the mbr */ //硬盘主引导记录(即Master Boot Record,一般简称为MBR),主分区数量
UINT32 reserved : 3; ////保留,注意 disk_id|part_id|part_no_disk|part_no_mbr|reserved 共用一个UINT32
UINT8 filesystem_type; /* filesystem used in the partition */ //文件系统类型
UINT8 type; //flash的类型 例如:EMMC
struct inode *dev; /* dev devices used in the partition */ //分区所使用的dev设备
CHAR *part_name; //区名称
UINT64 sector_start; /* //开始扇区编号
* offset of a partition to the primary devices
* (multi-mbr partitions are seen as same parition)
*/
UINT64 sector_count; /* //扇区数量
* sector numbers of a partition. If there is no addpartition operation,
* then all the mbr devices equal to the primary device count.
*/
LOS_DL_LIST list; /* linklist of partition */ //通过它挂到los_disk->head上
} los_part;
struct partition_info {//分区信息
UINT8 type; //分区类型,是主分区还是扩展分区
UINT64 sector_start;//开始扇区位置
UINT64 sector_count;//扇区大小
};
struct disk_divide_info {//磁盘分区描述符,
UINT64 sector_count; //扇区数量
UINT32 sector_size; //扇区大小,一般是512字节
UINT32 part_count; //分区数量 需 < MAX_DIVIDE_PART_PER_DISK + MAX_PRIMARY_PART_PER_DISK
/*
* The primary partition place should be reversed and set to 0 in case all the partitions are
* logical partition (maximum 16 currently). So the maximum part number should be 4 + 16.
*/ //如果所有分区都是逻辑分区(目前最多16个),则主分区位置应颠倒并设置为0。所以最大分区号应该是4+16。
struct partition_info part[MAX_DIVIDE_PART_PER_DISK + MAX_PRIMARY_PART_PER_DISK];//分区数组,记录每个分区的详细情况
};
/**
* @ingroup disk
* @brief Disk driver initialization.
*
* @par Description:
* Initializate a disk dirver, and set the block cache.
*
* @attention
* <ul>
* <li>The parameter diskName must point a valid string, which end with the terminating null byte.</li>
* <li>The total length of parameter diskName must be less than the value defined by PATH_MAX.</li>
* <li>The parameter bops must pointed the right functions, otherwise the system
* will crash when the disk is being operated.</li>
* <li>The parameter info can be null or point to struct disk_divide_info. when info is null,
* the disk will be divided base the information of MBR, otherwise,
* the disk will be divided base the information of parameter info.</li>
* </ul>
*
* @param diskName [IN] Type #const CHAR * disk driver name.
* @param bops [IN] Type #const struct block_operations * block driver control sturcture.
* @param priv [IN] Type #VOID * private data of inode.
* @param diskID [IN] Type #INT32 disk id number, less than SYS_MAX_DISK.
* @param info [IN] Type #VOID * disk driver partition information.
*
* @retval #0 Initialization success.
* @retval #-1 Initialization failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_deinit
*
*/
INT32 los_disk_init(const CHAR *diskName, const struct block_operations *bops,
VOID *priv, INT32 diskID, VOID *info);
/**
* @ingroup disk
* @brief Destroy a disk driver.
*
* @par Description:
* Destroy a disk driver, free the dependent resource.
*
* @attention
* <ul>
* None
* </ul>
*
* @param diskID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
*
* @retval #0 Destroy success.
* @retval #-1 Destroy failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_init
*
*/
INT32 los_disk_deinit(INT32 diskID);
/**
* @ingroup disk
* @brief Read data from disk driver.
*
* @par Description:
* Read data from disk driver.
*
* @attention
* <ul>
* <li>The sector size of the disk to be read should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to a valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param buf [OUT] Type #VOID * memory which used to store read data.
* @param sector [IN] Type #UINT64 expected start sector number to read.
* @param count [IN] Type #UINT32 expected sector count to read.
*
* @retval #0 Read success.
* @retval #-1 Read failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_write
*
*/
INT32 los_disk_read(INT32 drvID, VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Write data to a disk driver.
*
* @par Description:
* Write data to a disk driver.
*
* @attention
* <ul>
* <li>The sector size of the disk to be read should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to a valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param buf [IN] Type #const VOID * memory which used to storage write data.
* @param sector [IN] Type #UINT64 expected start sector number to read.
* @param count [IN] Type #UINT32 experted sector count of write.
*
* @retval #0 Write success.
* @retval #-1 Write failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_disk_read
*
*/
INT32 los_disk_write(INT32 drvID, const VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Get information of disk driver.
*
* @par Description:
* Get information of disk driver.
*
* @attention
* <ul>
* None
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param cmd [IN] Type #INT32 command to issu, currently support GET_SECTOR_COUNT, GET_SECTOR_SIZE,
* GET_BLOCK_SIZE, CTRL_SYNC.
* @param buf [OUT] Type #VOID * memory to storage the information, the size must enough for data type(UINT64)
* when cmd type is DISK_GET_SECTOR_COUNT, others is size_t.
*
* @retval #0 Get information success.
* @retval #-1 Get information failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_disk_ioctl(INT32 drvID, INT32 cmd, VOID *buf);
/**
* @ingroup disk
* @brief Sync blib cache.
*
* @par Description:
* Sync blib cache, write the valid data to disk driver.
*
* @attention
* <ul>
* None
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
*
* @retval #0 Sync success.
* @retval #INT32 Sync failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_disk_sync(INT32 drvID);
/**
* @ingroup disk
* @brief Set blib cache for the disk driver.
*
* @par Description:
* Set blib cache for the disk driver, users can set the number of sectors of per block,
* and the number of blocks.
*
* @attention
* <ul>
* None
* </ul>
*
* @param drvID [IN] Type #INT32 disk driver id number, less than the value defined by SYS_MAX_DISK.
* @param sectorPerBlock [IN] Type #UINT32 sector number of per block, only can be 32 * (1, 2, ..., 8).
* @param blockNum [IN] Type #UINT32 block number of cache.
*
* @retval #0 Set success.
* @retval #INT32 Set failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_disk_set_bcache(INT32 drvID, UINT32 sectorPerBlock, UINT32 blockNum);
/**
* @ingroup disk
* @brief Read data from chosen partition.
*
* @par Description:
* Read data from chosen partition.
*
* @attention
* <ul>
* <li>The sector size of the disk to be read should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param pt [IN] Type #INT32 partition number, less than the value defined by SYS_MAX_PART.
* @param buf [OUT] Type #VOID * memory which used to store the data to be read.
* @param sector [IN] Type #UINT64 start sector number of chosen partition.
* @param count [IN] Type #UINT32 the expected sector count for reading.
*
* @retval #0 Read success.
* @retval #-1 Read failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_part_read
*
*/
INT32 los_part_read(INT32 pt, VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Write data to chosen partition.
*
* @par Description:
* Write data to chosen partition.
*
* @attention
* <ul>
* <li>The sector size of the disk to be write should be acquired by los_part_ioctl before calling this function.</li>
* <li>The parameter buf must point to valid memory and the buf size is count * sector_size.</li>
* </ul>
*
* @param pt [IN] Type #INT32 partition number,less than the value defined by SYS_MAX_PART.
* @param buf [IN] Type #VOID * memory which used to storage the written data.
* @param sector [IN] Type #UINT64 start sector number of chosen partition.
* @param count [IN] Type #UINT32 the expected sector count for write.
*
* @retval #0 Write success.
* @retval #-1 Write failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_part_read
*
*/
INT32 los_part_write(INT32 pt, VOID *buf, UINT64 sector, UINT32 count);
/**
* @ingroup disk
* @brief Get information of chosen partition.
*
* @par Description:
* By passed command to get information of chosen partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param pt [IN] Type #INT32 partition number,less than the value defined by SYS_MAX_PART.
* @param cmd [IN] Type #INT32 command to issu, currently support GET_SECTOR_COUNT, GET_SECTOR_SIZE,
* GET_BLOCK_SIZE, CTRL_SYNC.
* @param buf [OUT] Type #VOID * memory to store the information, the size must enough for data type (UINT64)
* when cmd type is DISK_GET_SECTOR_COUNT, others is size_t.
*
* @retval #0 Get information success.
* @retval #-1 Get information failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_part_ioctl(INT32 pt, INT32 cmd, VOID *buf);
/**
* @ingroup disk
* @brief Decide the chosen partition is exist or not.
*
* @par Description:
* Decide the chosen partition is exist or not.
*
* @attention
* <ul>
* <li>The parameter dev is a full path, which begin with '/' and end with '/0'.</li>
* </ul>
*
* @param dev [IN] Type #const CHAR * partition driver name.
* @param mode [IN] Type #mode_t access modd.
*
* @retval #0 The chosen partition is exist.
* @retval #-1 The chosen partition is not exist.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 los_part_access(const CHAR *dev, mode_t mode);
/**
* @ingroup disk
* @brief Find disk partition.
*
* @par Description:
* By driver partition inode to find disk partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param blkDriver [IN] Type #struct inode * partition driver inode.
*
* @retval #NULL Can't find chosen disk partition.
* @retval #los_part * This is partition structure pointer of chosen disk partition.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
los_part *los_part_find(struct inode *blkDriver);
/**
* @ingroup disk
* @brief Find disk driver.
*
* @par Description:
* By disk driver id number to find disk dirver.
*
* @attention
* <ul>
* None
* </ul>
*
* @param id [IN] Type #INT32 disk id number,less than the value defined by SYS_MAX_DISK.
*
* @retval #NULL Can't find chosen disk driver.
* @retval #los_disk * This is disk structure pointer of chosen disk driver.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
los_disk *get_disk(INT32 id);
/**
* @ingroup disk
* @brief Find disk partition.
*
* @par Description:
* By driver partition id number to find disk partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param id [IN] Type #INT32 partition id number,less than the value defined by SYS_MAX_PART.
*
* @retval #NULL Can't find chosen disk partition.
* @retval #los_part * This is partition structure pointer of chosen disk partition.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
los_part *get_part(INT32 id);
/**
* @ingroup disk
* @brief Print partition information.
*
* @par Description:
* Print partition information.
*
* @attention
* <ul>
* None
* </ul>
*
* @param part [IN] Type #los_part * partition control structure pointer
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
VOID show_part(los_part *part);
/**
* @ingroup disk
* @brief Add a new mmc partition.
*
* @par Description:
* Add a new mmc partition, users can set the start sector and size of the new partition.
*
* @attention
* <ul>
* None
* </ul>
*
* @param info [IN] Type #struct disk_divide_info * Disk driver information structure pointer.
* @param sectorStart [IN] Type #size_t Start sector number of the new partition.
* @param sectorCount [IN] Type #size_t Sector count of the new partition.
*
* @retval #0 Add partition success.
* @retval #-1 Add partition failed.
*
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see None
*
*/
INT32 add_mmc_partition(struct disk_divide_info *info, size_t sectorStart, size_t sectorCount);
/**
* @ingroup disk
* @brief alloc a new UNUSED disk id.
*
* @par Description:
* Get a free disk id for new device.
*
* @attention
* <ul>
* <li>The parameter diskName must point a valid string, which end with the null byte ('\0') </li>
* <li>The total length of parameter diskName must be less than the value defined by DISK_NAME </li>
* </ul>
*
* @param diskName [IN] Type #const CHAR * device name.
*
* @retval #INT32 available disk id
* @retval #-1 alloc disk id failed
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_get_diskid_byname
*
*/
INT32 los_alloc_diskid_byname(const CHAR *diskName);
/**
* @ingroup disk
* @brief get the INUSED disk id.
*
* @par Description:
* Get the correponding INUSED disk id by diskName.
*
* @attention
* <ul>
* <li>The parameter diskName must point a valid string, which end with the null byte ('\0') </li>
* <li>The total length of parameter diskName must be less than the value defined by DISK_NAME </li>
* </ul>
*
* @param diskName [IN] Type #const CHAR * device name.
*
* @retval #INT32 available disk id
* @retval #-1 get disk id failed
* @par Dependency:
* <ul><li>disk.h</li></ul>
* @see los_alloc_diskid_byname
*
*/
INT32 los_get_diskid_byname(const CHAR *diskName);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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 "disk.h"
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "sys/mount.h"
#include "pthread.h"
#include "linux/spinlock.h"
#include "inode/inode.h"
#ifdef LOSCFG_DRIVERS_MMC
#include "mmc/block.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
los_disk g_sysDisk[SYS_MAX_DISK];//支持挂载的磁盘总数量 5个
los_part g_sysPart[SYS_MAX_PART];//支持磁盘的分区总数量 5*16,每个磁盘最大分16个区
UINT32 g_uwFatSectorsPerBlock = CONFIG_FS_FAT_SECTOR_PER_BLOCK; //每块支持扇区数 默认64个扇区
UINT32 g_uwFatBlockNums = CONFIG_FS_FAT_BLOCK_NUMS; //块数量 默认28
spinlock_t g_diskSpinlock; //磁盘自锁锁
spinlock_t g_diskFatBlockSpinlock;
UINT32 g_usbMode = 0;
#define MEM_ADDR_ALIGN_BYTE 64
#define RWE_RW_RW 0755
#define DISK_LOCK(mux) do { \
if (pthread_mutex_lock(mux) != 0) { \
PRINT_ERR("%s %d, mutex lock failed\n", __FUNCTION__, __LINE__); \
} \
} while (0)
#define DISK_UNLOCK(mux) do { \
if (pthread_mutex_unlock(mux) != 0) { \
PRINT_ERR("%s %d, mutex unlock failed\n", __FUNCTION__, __LINE__); \
} \
} while (0)
typedef VOID *(*StorageHookFunction)(VOID *);
static UINT32 OsReHookFuncAddDiskRef(StorageHookFunction handler,
VOID *param) __attribute__((weakref("osReHookFuncAdd")));
static UINT32 OsReHookFuncDelDiskRef(StorageHookFunction handler) __attribute__((weakref("osReHookFuncDel")));
#ifdef LOSCFG_FS_FAT_CACHE
UINT32 GetFatBlockNums(VOID)
{
return g_uwFatBlockNums;
}
VOID SetFatBlockNums(UINT32 blockNums)
{
g_uwFatBlockNums = blockNums;
}
UINT32 GetFatSectorsPerBlock(VOID)
{
return g_uwFatSectorsPerBlock;
}
VOID SetFatSectorsPerBlock(UINT32 sectorsPerBlock)
{
if (((sectorsPerBlock % UNSIGNED_INTEGER_BITS) == 0) &&
((sectorsPerBlock >> UNINT_LOG2_SHIFT) <= BCACHE_BLOCK_FLAGS)) {
g_uwFatSectorsPerBlock = sectorsPerBlock;
}
}
#endif
INT32 los_alloc_diskid_byname(const CHAR *diskName)
{
INT32 diskID;
los_disk *disk = NULL;
UINT32 intSave;
size_t nameLen;
if (diskName == NULL) {
PRINT_ERR("The paramter disk_name is NULL");
return VFS_ERROR;
}
nameLen = strlen(diskName);
if (nameLen > DISK_NAME) {
PRINT_ERR("diskName is too long!\n");
return VFS_ERROR;
}
spin_lock_irqsave(&g_diskSpinlock, intSave);
for (diskID = 0; diskID < SYS_MAX_DISK; diskID++) {
disk = get_disk(diskID);
if ((disk != NULL) && (disk->disk_status == STAT_UNUSED)) {
disk->disk_status = STAT_UNREADY;
break;
}
}
spin_unlock_irqrestore(&g_diskSpinlock, intSave);
if ((disk == NULL) || (diskID == SYS_MAX_DISK)) {
PRINT_ERR("los_alloc_diskid_byname failed %d!\n", diskID);
return VFS_ERROR;
}
if (disk->disk_name != NULL) {
LOS_MemFree(m_aucSysMem0, disk->disk_name);
disk->disk_name = NULL;
}
disk->disk_name = LOS_MemAlloc(m_aucSysMem0, (nameLen + 1));
if (disk->disk_name == NULL) {
PRINT_ERR("los_alloc_diskid_byname alloc disk name failed\n");
return VFS_ERROR;
}
if (strncpy_s(disk->disk_name, (nameLen + 1), diskName, nameLen) != EOK) {
PRINT_ERR("The strncpy_s failed.\n");
return VFS_ERROR;
}
disk->disk_name[nameLen] = '\0';
return diskID;
}
INT32 los_get_diskid_byname(const CHAR *diskName)
{
INT32 diskID;
los_disk *disk = NULL;
size_t diskNameLen;
if (diskName == NULL) {
PRINT_ERR("The paramter diskName is NULL");
return VFS_ERROR;
}
diskNameLen = strlen(diskName);
if (diskNameLen > DISK_NAME) {
PRINT_ERR("diskName is too long!\n");
return VFS_ERROR;
}
for (diskID = 0; diskID < SYS_MAX_DISK; diskID++) {
disk = get_disk(diskID);
if ((disk != NULL) && (disk->disk_name != NULL) && (disk->disk_status == STAT_INUSED)) {
if (strlen(disk->disk_name) != diskNameLen) {
continue;
}
if (strcmp(diskName, disk->disk_name) == 0) {
break;
}
}
}
if ((disk == NULL) || (diskID == SYS_MAX_DISK)) {
PRINT_ERR("los_get_diskid_byname failed!\n");
return VFS_ERROR;
}
return diskID;
}
VOID OsSetUsbStatus(UINT32 diskID)
{
if (diskID < SYS_MAX_DISK) {
g_usbMode |= (1u << diskID) & UINT_MAX;
}
}
VOID OsClearUsbStatus(UINT32 diskID)
{
if (diskID < SYS_MAX_DISK) {
g_usbMode &= ~((1u << diskID) & UINT_MAX);
}
}
#ifdef LOSCFG_FS_FAT_CACHE
static BOOL GetDiskUsbStatus(UINT32 diskID)
{
return (g_usbMode & (1u << diskID)) ? TRUE : FALSE;
}
#endif
//获取某个磁盘的描述符
los_disk *get_disk(INT32 id)
{
if ((id >= 0) && (id < SYS_MAX_DISK)) {
return &g_sysDisk[id];
}
return NULL;
}
//获取某个分区的描述符
los_part *get_part(INT32 id)
{
if ((id >= 0) && (id < SYS_MAX_PART)) {
return &g_sysPart[id];
}
return NULL;
}
static UINT64 GetFirstPartStart(const los_part *part)
{
los_part *firstPart = NULL;
los_disk *disk = get_disk((INT32)part->disk_id);
firstPart = (disk == NULL) ? NULL : LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
return (firstPart == NULL) ? 0 : firstPart->sector_start;
}
//磁盘增加一个分区
static VOID DiskPartAddToDisk(los_disk *disk, los_part *part)
{
part->disk_id = disk->disk_id;//分区描述符记录磁盘ID
part->part_no_disk = disk->part_count;//分区数量
LOS_ListTailInsert(&disk->head, &part->list);//将分区结点挂入磁盘分区双链表
disk->part_count++;//磁盘分区数量增加
}
//从磁盘上删除分区
static VOID DiskPartDelFromDisk(los_disk *disk, los_part *part)
{
LOS_ListDelete(&part->list);//摘掉分区节点
disk->part_count--;//分区数减少
}
//分配一个磁盘分区
static los_part *DiskPartAllocate(struct inode *dev, UINT64 start, UINT64 count)
{
UINT32 i;
los_part *part = get_part(0); /* traversing from the beginning of the array */
for (i = 0; i < SYS_MAX_PART; i++) {//从数组开始遍历
if (part->dev == NULL) {
part->part_id = i;
part->part_no_mbr = 0;
part->dev = dev;
part->sector_start = start;
part->sector_count = count;
part->part_name = NULL;
LOS_ListInit(&part->list);
return part;
}
part++;
}
return NULL;
}
//清空分区信息
static VOID DiskPartRelease(los_part *part)
{
part->dev = NULL;
part->part_no_disk = 0;
part->part_no_mbr = 0;
if (part->part_name != NULL) {
free(part->part_name);
part->part_name = NULL;
}
}
/*
* name is a combination of disk_name, 'p' and part_count, such as "/dev/mmcblk0p0"
* disk_name : DISK_NAME + 1
* 'p' : 1
* part_count: 1
*/
#define DEV_NAME_BUFF_SIZE (DISK_NAME + 3)//为何加3, 就是上面的disk_name+p+part_count
//磁盘增加一个分区
static INT32 DiskAddPart(los_disk *disk, UINT64 sectorStart, UINT64 sectorCount)
{
CHAR devName[DEV_NAME_BUFF_SIZE];
struct inode *diskDev = NULL;
struct inode *partDev = NULL;
los_part *part = NULL;
INT32 ret;
struct inode_search_s desc;
if ((disk == NULL) || (disk->disk_status == STAT_UNUSED) ||
(disk->dev == NULL)) {
return VFS_ERROR;
}
//扇区判断,磁盘在创建伊始就扇区数量就固定了
if ((sectorCount > disk->sector_count) || ((disk->sector_count - sectorCount) < sectorStart)) {
PRINT_ERR("DiskAddPart failed: sector start is %llu, sector count is %llu\n", sectorStart, sectorCount);
return VFS_ERROR;
}
///devName = /dev/mmcblk0p2 代表的是 0号磁盘的2号分区
ret = snprintf_s(devName, sizeof(devName), sizeof(devName) - 1, "%s%c%u",
(disk->disk_name == NULL ? "null" : disk->disk_name), 'p', disk->part_count);
if (ret < 0) {
return VFS_ERROR;
}
diskDev = disk->dev;
if (register_blockdriver(devName, diskDev->u.i_bops, RWE_RW_RW, diskDev->i_private)) {//注册块驱动程序
PRINT_ERR("DiskAddPart : register %s fail!\n", devName);
return VFS_ERROR;
}
SETUP_SEARCH(&desc, devName, false);//
ret = inode_find(&desc);
if (ret < 0) {
PRINT_ERR("DiskAddPart : find %s fail!\n", devName);
return VFS_ERROR;
}
partDev = desc.node;
PRINTK("DiskAddPart : register %s ok!\n", devName);
part = DiskPartAllocate(partDev, sectorStart, sectorCount);
inode_release(partDev);
if (part == NULL) {
(VOID)unregister_blockdriver(devName);
return VFS_ERROR;
}
DiskPartAddToDisk(disk, part);
if (disk->type == EMMC) {
part->type = EMMC;
}
return (INT32)part->part_id;
}
static INT32 DiskDivide(los_disk *disk, struct disk_divide_info *info)
{
UINT32 i;
INT32 ret;
disk->type = info->part[0].type;
for (i = 0; i < info->part_count; i++) {
if (info->sector_count < info->part[i].sector_start) {
return VFS_ERROR;
}
if (info->part[i].sector_count > (info->sector_count - info->part[i].sector_start)) {
PRINT_ERR("Part[%u] sector_start:%llu, sector_count:%llu, exceed emmc sector_count:%llu.\n", i,
info->part[i].sector_start, info->part[i].sector_count,
(info->sector_count - info->part[i].sector_start));
info->part[i].sector_count = info->sector_count - info->part[i].sector_start;
PRINT_ERR("Part[%u] sector_count change to %llu.\n", i, info->part[i].sector_count);
ret = DiskAddPart(disk, info->part[i].sector_start, info->part[i].sector_count);
if (ret == VFS_ERROR) {
return VFS_ERROR;
}
break;
}
ret = DiskAddPart(disk, info->part[i].sector_start, info->part[i].sector_count);
if (ret == VFS_ERROR) {
return VFS_ERROR;
}
}
return ENOERR;
}
static CHAR GPTPartitionTypeRecognition(const CHAR *parBuf)
{
const CHAR *buf = parBuf;
const CHAR *fsType = "FAT";
const CHAR *str = "\xEB\x52\x90" "NTFS "; /* NTFS Boot entry point */
if (((LD_DWORD_DISK(&buf[BS_FILSYSTEMTYPE32]) & BS_FS_TYPE_MASK) == BS_FS_TYPE_VALUE) ||
(strncmp(&buf[BS_FILSYSTYPE], fsType, strlen(fsType)) == 0)) {
return BS_FS_TYPE_FAT;
} else if (strncmp(&buf[BS_JMPBOOT], str, strlen(str)) == 0) {
return BS_FS_TYPE_NTFS;
}
return ENOERR;
}
static INT32 DiskPartitionMemZalloc(size_t boundary, size_t size, CHAR **gptBuf, CHAR **partitionBuf)
{
CHAR *buffer1 = NULL;
CHAR *buffer2 = NULL;
buffer1 = (CHAR *)memalign(boundary, size);
if (buffer1 == NULL) {
PRINT_ERR("%s buffer1 malloc %lu failed! %d\n", __FUNCTION__, size, __LINE__);
return VFS_ERROR;
}
buffer2 = (CHAR *)memalign(boundary, size);
if (buffer2 == NULL) {
PRINT_ERR("%s buffer2 malloc %lu failed! %d\n", __FUNCTION__, size, __LINE__);
free(buffer1);
return VFS_ERROR;
}
(VOID)memset_s(buffer1, size, 0, size);
(VOID)memset_s(buffer2, size, 0, size);
*gptBuf = buffer1;
*partitionBuf = buffer2;
return ENOERR;
}
static INT32 GPTInfoGet(struct inode *blkDrv, CHAR *gptBuf)
{
INT32 ret;
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)gptBuf, 1, 1); /* Read the device first sector */
if (ret != 1) { /* Read failed */
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
return -EIO;
}
if (!VERIFY_GPT(gptBuf)) {
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
return VFS_ERROR;
}
return ENOERR;
}
static INT32 OsGPTPartitionRecognitionSub(struct disk_divide_info *info, const CHAR *partitionBuf,
UINT32 *partitionCount, UINT64 partitionStart, UINT64 partitionEnd)
{
CHAR partitionType;
if (VERIFY_FS(partitionBuf)) {
partitionType = GPTPartitionTypeRecognition(partitionBuf);
if (partitionType) {
if (*partitionCount >= MAX_DIVIDE_PART_PER_DISK) {
return VFS_ERROR;
}
info->part[*partitionCount].type = partitionType;
info->part[*partitionCount].sector_start = partitionStart;
info->part[*partitionCount].sector_count = (partitionEnd - partitionStart) + 1;
(*partitionCount)++;
} else {
PRINT_ERR("The partition type is not allowed to use!\n");
}
} else {
PRINT_ERR("Do not support the partition type!\n");
}
return ENOERR;
}
static INT32 OsGPTPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info,
const CHAR *gptBuf, CHAR *partitionBuf, UINT32 *partitionCount)
{
UINT32 j;
INT32 ret = VFS_ERROR;
UINT64 partitionStart, partitionEnd;
for (j = 0; j < PAR_ENTRY_NUM_PER_SECTOR; j++) {
if (!VERITY_AVAILABLE_PAR(&gptBuf[j * TABLE_SIZE])) {
PRINTK("The partition type is ESP or MSR!\n");
continue;
}
if (!VERITY_PAR_VALID(&gptBuf[j * TABLE_SIZE])) {
return VFS_ERROR;
}
partitionStart = LD_QWORD_DISK(&gptBuf[(j * TABLE_SIZE) + GPT_PAR_START_OFFSET]);
partitionEnd = LD_QWORD_DISK(&gptBuf[(j * TABLE_SIZE) + GPT_PAR_END_OFFSET]);
if ((partitionStart >= partitionEnd) || (partitionEnd > info->sector_count)) {
PRINT_ERR("GPT partition %u recognition failed : partitionStart = %llu, partitionEnd = %llu\n",
j, partitionStart, partitionEnd);
return VFS_ERROR;
}
(VOID)memset_s(partitionBuf, info->sector_size, 0, info->sector_size);
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)partitionBuf, partitionStart, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
return -EIO;
}
ret = OsGPTPartitionRecognitionSub(info, partitionBuf, partitionCount, partitionStart, partitionEnd);
if (ret != ENOERR) {
return VFS_ERROR;
}
}
return ret;
}
static INT32 DiskGPTPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info)
{
CHAR *gptBuf = NULL;
CHAR *partitionBuf = NULL;
UINT32 tableNum, i, index;
UINT32 partitionCount = 0;
INT32 ret;
ret = DiskPartitionMemZalloc(MEM_ADDR_ALIGN_BYTE, info->sector_size, &gptBuf, &partitionBuf);
if (ret != ENOERR) {
return VFS_ERROR;
}
ret = GPTInfoGet(blkDrv, gptBuf);
if (ret < 0) {
goto OUT_WITH_MEM;
}
tableNum = LD_DWORD_DISK(&gptBuf[TABLE_NUM_OFFSET]);
if (tableNum > TABLE_MAX_NUM) {
tableNum = TABLE_MAX_NUM;
}
index = (tableNum % PAR_ENTRY_NUM_PER_SECTOR) ? ((tableNum / PAR_ENTRY_NUM_PER_SECTOR) + 1) :
(tableNum / PAR_ENTRY_NUM_PER_SECTOR);
for (i = 0; i < index; i++) {
(VOID)memset_s(gptBuf, info->sector_size, 0, info->sector_size);
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)gptBuf, TABLE_START_SECTOR + i, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
ret = -EIO;
goto OUT_WITH_MEM;
}
ret = OsGPTPartitionRecognition(blkDrv, info, gptBuf, partitionBuf, &partitionCount);
if (ret < 0) {
if (ret == VFS_ERROR) {
ret = (INT32)partitionCount;
}
goto OUT_WITH_MEM;
}
}
ret = (INT32)partitionCount;
OUT_WITH_MEM:
free(gptBuf);
free(partitionBuf);
return ret;
}
static INT32 OsMBRInfoGet(struct inode *blkDrv, CHAR *mbrBuf)
{
INT32 ret;
/* read MBR, start from sector 0, length is 1 sector */
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)mbrBuf, 0, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("driver read return error: %d\n", ret);
return -EIO;
}
/* Check boot record signature. */
if (LD_WORD_DISK(&mbrBuf[BS_SIG55AA]) != BS_SIG55AA_VALUE) {
return VFS_ERROR;
}
return ENOERR;
}
static INT32 OsEBRInfoGet(struct inode *blkDrv, const struct disk_divide_info *info,
CHAR *ebrBuf, const CHAR *mbrBuf)
{
INT32 ret;
if (VERIFY_FS(mbrBuf)) {
if (info->sector_count <= LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET])) {
return VFS_ERROR;
}
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)ebrBuf,
LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET]), 1);
if ((ret != 1) || (!VERIFY_FS(ebrBuf))) { /* read failed */
PRINT_ERR("OsEBRInfoGet, verify_fs error, ret = %d\n", ret);
return -EIO;
}
}
return ENOERR;
}
static INT32 OsPrimaryPartitionRecognition(const CHAR *mbrBuf, struct disk_divide_info *info,
INT32 *extendedPos, INT32 *mbrCount)
{
INT32 i;
CHAR mbrPartitionType;
INT32 extendedFlag = 0;
INT32 count = 0;
for (i = 0; i < MAX_PRIMARY_PART_PER_DISK; i++) {
mbrPartitionType = mbrBuf[PAR_OFFSET + PAR_TYPE_OFFSET + (i * PAR_TABLE_SIZE)];
if (mbrPartitionType) {
info->part[i].type = mbrPartitionType;
info->part[i].sector_start = LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET + (i * PAR_TABLE_SIZE)]);
info->part[i].sector_count = LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_COUNT_OFFSET + (i * PAR_TABLE_SIZE)]);
if ((mbrPartitionType == EXTENDED_PAR) || (mbrPartitionType == EXTENDED_8G)) {
extendedFlag = 1;
*extendedPos = i;
continue;
}
count++;
}
}
*mbrCount = count;
return extendedFlag;
}
static INT32 OsLogicalPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info,
UINT32 extendedAddress, CHAR *ebrBuf, INT32 mbrCount)
{
INT32 ret;
UINT32 extendedOffset = 0;
CHAR ebrPartitionType;
INT32 ebrCount = 0;
do {
(VOID)memset_s(ebrBuf, info->sector_size, 0, info->sector_size);
if (((UINT64)(extendedAddress) + extendedOffset) >= info->sector_count) {
PRINT_ERR("extended partition is out of disk range: extendedAddress = %u, extendedOffset = %u\n",
extendedAddress, extendedOffset);
break;
}
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)ebrBuf,
extendedAddress + extendedOffset, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("driver read return error: %d, extendedAddress = %u, extendedOffset = %u\n", ret,
extendedAddress, extendedOffset);
return -EIO;
}
ebrPartitionType = ebrBuf[PAR_OFFSET + PAR_TYPE_OFFSET];
if (ebrPartitionType && ((mbrCount + ebrCount) < MAX_DIVIDE_PART_PER_DISK)) {
info->part[MAX_PRIMARY_PART_PER_DISK + ebrCount].type = ebrPartitionType;
info->part[MAX_PRIMARY_PART_PER_DISK + ebrCount].sector_start = extendedAddress + extendedOffset +
LD_DWORD_DISK(&ebrBuf[PAR_OFFSET +
PAR_START_OFFSET]);
info->part[MAX_PRIMARY_PART_PER_DISK + ebrCount].sector_count = LD_DWORD_DISK(&ebrBuf[PAR_OFFSET +
PAR_COUNT_OFFSET]);
ebrCount++;
}
extendedOffset = LD_DWORD_DISK(&ebrBuf[PAR_OFFSET + PAR_START_OFFSET + PAR_TABLE_SIZE]);
} while ((ebrBuf[PAR_OFFSET + PAR_TYPE_OFFSET + PAR_TABLE_SIZE] != 0) &&
((mbrCount + ebrCount) < MAX_DIVIDE_PART_PER_DISK));
return ebrCount;
}
static INT32 DiskPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info)
{
INT32 ret;
INT32 extendedFlag;
INT32 extendedPos = 0;
INT32 mbrCount = 0;
UINT32 extendedAddress;
CHAR *mbrBuf = NULL;
CHAR *ebrBuf = NULL;
if ((blkDrv == NULL) || (blkDrv->u.i_bops == NULL) || (blkDrv->u.i_bops->read == NULL)) {
return VFS_ERROR;
}
ret = DiskPartitionMemZalloc(MEM_ADDR_ALIGN_BYTE, info->sector_size, &mbrBuf, &ebrBuf);
if (ret != ENOERR) {
return ret;
}
ret = OsMBRInfoGet(blkDrv, mbrBuf);
if (ret < 0) {
goto OUT_WITH_MEM;
}
/* The partition type is GPT */
if (mbrBuf[PARTION_MODE_BTYE] == (CHAR)PARTION_MODE_GPT) {
ret = DiskGPTPartitionRecognition(blkDrv, info);
goto OUT_WITH_MEM;
}
ret = OsEBRInfoGet(blkDrv, info, ebrBuf, mbrBuf);
if (ret < 0) {
ret = 0; /* no mbr */
goto OUT_WITH_MEM;
}
extendedFlag = OsPrimaryPartitionRecognition(mbrBuf, info, &extendedPos, &mbrCount);
if (extendedFlag) {
extendedAddress = LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET + (extendedPos * PAR_TABLE_SIZE)]);
ret = OsLogicalPartitionRecognition(blkDrv, info, extendedAddress, ebrBuf, mbrCount);
if (ret <= 0) {
goto OUT_WITH_MEM;
}
}
ret += mbrCount;
OUT_WITH_MEM:
free(ebrBuf);
free(mbrBuf);
return ret;
}
INT32 DiskPartitionRegister(los_disk *disk)
{
INT32 count;
UINT32 i, partSize;
los_part *part = NULL;
struct disk_divide_info parInfo;
/* Fill disk_divide_info structure to set partition's infomation. */
(VOID)memset_s(parInfo.part, sizeof(parInfo.part), 0, sizeof(parInfo.part));
partSize = sizeof(parInfo.part) / sizeof(parInfo.part[0]);
parInfo.sector_size = disk->sector_size;
parInfo.sector_count = disk->sector_count;
count = DiskPartitionRecognition(disk->dev, &parInfo);
if (count < 0) {
return VFS_ERROR;
}
parInfo.part_count = count;
if (count == 0) {
part = get_part(DiskAddPart(disk, 0, disk->sector_count));
if (part == NULL) {
return VFS_ERROR;
}
part->part_no_mbr = 0;
PRINTK("No MBR detected.\n");
return ENOERR;
}
for (i = 0; i < partSize; i++) {
/* Read the disk_divide_info structure to get partition's infomation. */
if ((parInfo.part[i].type != 0) && (parInfo.part[i].type != EXTENDED_PAR) &&
(parInfo.part[i].type != EXTENDED_8G)) {
part = get_part(DiskAddPart(disk, parInfo.part[i].sector_start, parInfo.part[i].sector_count));
if (part == NULL) {
return VFS_ERROR;
}
part->part_no_mbr = i + 1;
part->filesystem_type = parInfo.part[i].type;
}
}
return ENOERR;
}
INT32 los_disk_read(INT32 drvID, VOID *buf, UINT64 sector, UINT32 count)
{
#ifdef LOSCFG_FS_FAT_CACHE
UINT32 len;
#endif
INT32 result = VFS_ERROR;
los_disk *disk = get_disk(drvID);
if ((buf == NULL) || (count == 0)) { /* buff equal to NULL or count equal to 0 */
return result;
}
if (disk == NULL) {
return result;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
if ((count > disk->sector_count) || ((disk->sector_count - count) < sector)) {
goto ERROR_HANDLE;
}
#ifdef LOSCFG_FS_FAT_CACHE
if (disk->bcache != NULL) {
if (((UINT64)(disk->bcache->sectorSize) * count) > UINT_MAX) {
goto ERROR_HANDLE;
}
len = disk->bcache->sectorSize * count;
result = BlockCacheRead(disk->bcache, (UINT8 *)buf, &len, sector);
if (result != ENOERR) {
PRINT_ERR("los_disk_read read err = %d, sector = %llu, len = %u\n", result, sector, len);
}
} else {
#endif
if ((disk->dev != NULL) && (disk->dev->u.i_bops != NULL) && (disk->dev->u.i_bops->read != NULL)) {
result = disk->dev->u.i_bops->read(disk->dev, (UINT8 *)buf, sector, count);
if (result == (INT32)count) {
result = ENOERR;
}
}
#ifdef LOSCFG_FS_FAT_CACHE
}
#endif
if (result != ENOERR) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_disk_write(INT32 drvID, const VOID *buf, UINT64 sector, UINT32 count)
{
#ifdef LOSCFG_FS_FAT_CACHE
UINT32 len;
#endif
INT32 result = VFS_ERROR;
los_disk *disk = get_disk(drvID);
if (disk == NULL) {
return result;
}
if ((buf == NULL) || (count == 0)) { /* buff equal to NULL or count equal to 0 */
return result;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
if ((count > disk->sector_count) || ((disk->sector_count - count) < sector)) {
goto ERROR_HANDLE;
}
#ifdef LOSCFG_FS_FAT_CACHE
if (disk->bcache != NULL) {
if (((UINT64)(disk->bcache->sectorSize) * count) > UINT_MAX) {
goto ERROR_HANDLE;
}
len = disk->bcache->sectorSize * count;
result = BlockCacheWrite(disk->bcache, (const UINT8 *)buf, &len, sector);
if (result != ENOERR) {
PRINT_ERR("los_disk_write write err = %d, sector = %llu, len = %u\n", result, sector, len);
}
} else {
#endif
if ((disk->dev != NULL) && (disk->dev->u.i_bops != NULL) && (disk->dev->u.i_bops->write != NULL)) {
result = disk->dev->u.i_bops->write(disk->dev, (UINT8 *)buf, sector, count);
if (result == (INT32)count) {
result = ENOERR;
}
}
#ifdef LOSCFG_FS_FAT_CACHE
}
#endif
if (result != ENOERR) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_disk_ioctl(INT32 drvID, INT32 cmd, VOID *buf)
{
struct geometry info;
los_disk *disk = get_disk(drvID);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((disk->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_CTRL_SYNC) {
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
}
if (buf == NULL) {
goto ERROR_HANDLE;
}
(VOID)memset_s(&info, sizeof(info), 0, sizeof(info));
if ((disk->dev->u.i_bops == NULL) || (disk->dev->u.i_bops->geometry == NULL) ||
(disk->dev->u.i_bops->geometry(disk->dev, &info) != 0)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_GET_SECTOR_COUNT) {
*(UINT64 *)buf = info.geo_nsectors;
if (info.geo_nsectors == 0) {
goto ERROR_HANDLE;
}
} else if (cmd == DISK_GET_SECTOR_SIZE) {
*(size_t *)buf = info.geo_sectorsize;
} else if (cmd == DISK_GET_BLOCK_SIZE) { /* Get erase block size in unit of sectors (UINT32) */
/* Block Num SDHC == 512, SD can be set to 512 or other */
*(size_t *)buf = DISK_MAX_SECTOR_SIZE / info.geo_sectorsize;
} else {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_part_read(INT32 pt, VOID *buf, UINT64 sector, UINT32 count)
{
const los_part *part = get_part(pt);
los_disk *disk = NULL;
INT32 ret;
if (part == NULL) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((part->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (count > part->sector_count) {
PRINT_ERR("los_part_read failed, invaild count, count = %u\n", count);
goto ERROR_HANDLE;
}
/* Read from absolute sector. */
if (part->type == EMMC) {
if ((disk->sector_count - part->sector_start) > sector) {
sector += part->sector_start;
} else {
PRINT_ERR("los_part_read failed, invaild sector, sector = %llu\n", sector);
goto ERROR_HANDLE;
}
}
if ((sector >= GetFirstPartStart(part)) &&
(((sector + count) > (part->sector_start + part->sector_count)) || (sector < part->sector_start))) {
PRINT_ERR("los_part_read error, sector = %llu, count = %u, part->sector_start = %llu, "
"part->sector_count = %llu\n", sector, count, part->sector_start, part->sector_count);
goto ERROR_HANDLE;
}
ret = los_disk_read((INT32)part->disk_id, buf, sector, count);
if (ret < 0) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_part_write(INT32 pt, VOID *buf, UINT64 sector, UINT32 count)
{
const los_part *part = get_part(pt);
los_disk *disk = NULL;
INT32 ret;
if (part == NULL) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((part->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (count > part->sector_count) {
PRINT_ERR("los_part_write failed, invaild count, count = %u\n", count);
goto ERROR_HANDLE;
}
/* Write to absolute sector. */
if (part->type == EMMC) {
if ((disk->sector_count - part->sector_start) > sector) {
sector += part->sector_start;
} else {
PRINT_ERR("los_part_write failed, invaild sector, sector = %llu\n", sector);
goto ERROR_HANDLE;
}
}
if ((sector >= GetFirstPartStart(part)) &&
(((sector + count) > (part->sector_start + part->sector_count)) || (sector < part->sector_start))) {
PRINT_ERR("los_part_write, sector = %llu, count = %u, part->sector_start = %llu, "
"part->sector_count = %llu\n", sector, count, part->sector_start, part->sector_count);
goto ERROR_HANDLE;
}
ret = los_disk_write((INT32)part->disk_id, (const VOID *)buf, sector, count);
if (ret < 0) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
#define GET_ERASE_BLOCK_SIZE 0x2
INT32 los_part_ioctl(INT32 pt, INT32 cmd, VOID *buf)
{
struct geometry info;
los_part *part = get_part(pt);
los_disk *disk = NULL;
if (part == NULL) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((part->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_CTRL_SYNC) {
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
}
if (buf == NULL) {
goto ERROR_HANDLE;
}
(VOID)memset_s(&info, sizeof(info), 0, sizeof(info));
if ((part->dev->u.i_bops == NULL) || (part->dev->u.i_bops->geometry == NULL) ||
(part->dev->u.i_bops->geometry(part->dev, &info) != 0)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_GET_SECTOR_COUNT) {
*(UINT64 *)buf = part->sector_count;
if (*(UINT64 *)buf == 0) {
goto ERROR_HANDLE;
}
} else if (cmd == DISK_GET_SECTOR_SIZE) {
*(size_t *)buf = info.geo_sectorsize;
} else if (cmd == DISK_GET_BLOCK_SIZE) { /* Get erase block size in unit of sectors (UINT32) */
if ((part->dev->u.i_bops->ioctl == NULL) ||
(part->dev->u.i_bops->ioctl(part->dev, GET_ERASE_BLOCK_SIZE, (UINTPTR)buf) != 0)) {
goto ERROR_HANDLE;
}
} else {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
#ifdef LOSCFG_FS_FAT_CACHE
static VOID DiskCacheThreadInit(UINT32 diskID, OsBcache *bc)
{
bc->prereadFun = NULL;
if (GetDiskUsbStatus(diskID) == FALSE) {
if (BcacheAsyncPrereadInit(bc) == LOS_OK) {
bc->prereadFun = ResumeAsyncPreread;
}
#ifdef LOSCFG_FS_FAT_CACHE_SYNC_THREAD
BcacheSyncThreadInit(bc, diskID);
#endif
}
if (OsReHookFuncAddDiskRef != NULL) {
(VOID)OsReHookFuncAddDiskRef((StorageHookFunction)OsSdSync, (VOID *)0);
(VOID)OsReHookFuncAddDiskRef((StorageHookFunction)OsSdSync, (VOID *)1);
}
}
static OsBcache *DiskCacheInit(UINT32 diskID, const struct geometry *diskInfo, struct inode *blkDriver)
{
#define SECTOR_SIZE 512
OsBcache *bc = NULL;
UINT32 sectorPerBlock = diskInfo->geo_sectorsize / SECTOR_SIZE;
if (sectorPerBlock != 0) {
sectorPerBlock = g_uwFatSectorsPerBlock / sectorPerBlock;
if (sectorPerBlock != 0) {
bc = BlockCacheInit(blkDriver, diskInfo->geo_sectorsize, sectorPerBlock,
g_uwFatBlockNums, diskInfo->geo_nsectors / sectorPerBlock);
}
}
if (bc == NULL) {
PRINT_ERR("disk_init : disk have not init bcache cache!\n");
return NULL;
}
DiskCacheThreadInit(diskID, bc);
return bc;
}
static VOID DiskCacheDeinit(los_disk *disk)
{
UINT32 diskID = disk->disk_id;
if (GetDiskUsbStatus(diskID) == FALSE) {
if (BcacheAsyncPrereadDeinit(disk->bcache) != LOS_OK) {
PRINT_ERR("Blib async preread deinit failed in %s, %d\n", __FUNCTION__, __LINE__);
}
#ifdef LOSCFG_FS_FAT_CACHE_SYNC_THREAD
BcacheSyncThreadDeinit(disk->bcache);
#endif
}
BlockCacheDeinit(disk->bcache);
disk->bcache = NULL;
if (OsReHookFuncDelDiskRef != NULL) {
(VOID)OsReHookFuncDelDiskRef((StorageHookFunction)OsSdSync);
}
}
#endif
static VOID DiskStructInit(const CHAR *diskName, INT32 diskID, const struct geometry *diskInfo,
struct inode *blkDriver, los_disk *disk)
{
size_t nameLen;
disk->disk_id = diskID;
disk->dev = blkDriver;
disk->sector_start = 0;
disk->sector_size = diskInfo->geo_sectorsize;
disk->sector_count = diskInfo->geo_nsectors;
nameLen = strlen(diskName); /* caller los_disk_init has chek name */
if (disk->disk_name != NULL) {
LOS_MemFree(m_aucSysMem0, disk->disk_name);
disk->disk_name = NULL;
}
disk->disk_name = LOS_MemAlloc(m_aucSysMem0, (nameLen + 1));
if (disk->disk_name == NULL) {
PRINT_ERR("DiskStructInit alloc memory failed.\n");
return;
}
if (strncpy_s(disk->disk_name, (nameLen + 1), diskName, nameLen) != EOK) {
PRINT_ERR("DiskStructInit strncpy_s failed.\n");
return;
}
disk->disk_name[nameLen] = '\0';
LOS_ListInit(&disk->head);
}
static INT32 DiskDivideAndPartitionRegister(struct disk_divide_info *info, los_disk *disk)
{
INT32 ret;
if (info != NULL) {
ret = DiskDivide(disk, info);
if (ret != ENOERR) {
PRINT_ERR("DiskDivide failed, ret = %d\n", ret);
return ret;
}
} else {
ret = DiskPartitionRegister(disk);
if (ret != ENOERR) {
PRINT_ERR("DiskPartitionRegister failed, ret = %d\n", ret);
return ret;
}
}
return ENOERR;
}
static INT32 DiskDeinit(los_disk *disk)
{
los_part *part = NULL;
char *diskName = NULL;
CHAR devName[DEV_NAME_BUFF_SIZE];
INT32 ret;
if (LOS_ListEmpty(&disk->head) == FALSE) {
part = LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
while (&part->list != &disk->head) {
diskName = (disk->disk_name == NULL) ? "null" : disk->disk_name;
ret = snprintf_s(devName, sizeof(devName), sizeof(devName) - 1, "%s%c%d",
diskName, 'p', disk->part_count - 1);
if (ret < 0) {
return -ENAMETOOLONG;
}
DiskPartDelFromDisk(disk, part);
(VOID)unregister_blockdriver(devName);
DiskPartRelease(part);
part = LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
}
}
DISK_LOCK(&disk->disk_mutex);
#ifdef LOSCFG_FS_FAT_CACHE
DiskCacheDeinit(disk);
#endif
disk->dev = NULL;
DISK_UNLOCK(&disk->disk_mutex);
(VOID)unregister_blockdriver(disk->disk_name);
if (disk->disk_name != NULL) {
LOS_MemFree(m_aucSysMem0, disk->disk_name);
disk->disk_name = NULL;
}
ret = pthread_mutex_destroy(&disk->disk_mutex);
if (ret != 0) {
PRINT_ERR("%s %d, mutex destroy failed, ret = %d\n", __FUNCTION__, __LINE__, ret);
return -EFAULT;
}
disk->disk_status = STAT_UNUSED;
return ENOERR;
}
static VOID OsDiskInitSub(const CHAR *diskName, INT32 diskID, los_disk *disk,
struct geometry *diskInfo, struct inode *blkDriver)
{
pthread_mutexattr_t attr;
#ifdef LOSCFG_FS_FAT_CACHE
OsBcache *bc = DiskCacheInit((UINT32)diskID, diskInfo, blkDriver);
disk->bcache = bc;
#endif
(VOID)pthread_mutexattr_init(&attr);//posix 互斥量属性初始化
attr.type = PTHREAD_MUTEX_RECURSIVE;//使用递归型互斥,鸿蒙内核为降低死锁概率 默认就是递归方式
(VOID)pthread_mutex_init(&disk->disk_mutex, &attr);//初始化磁盘的互斥量
DiskStructInit(diskName, diskID, diskInfo, blkDriver, disk);//初始化磁盘描述符los_disk
}
/***************************************************************
磁盘初始化 , diskName 必须是 /dev/***
当块设备注册到系统。它被文件系统用来执行文件系统处理。它可以处理struct inode
inode:索引节点对象,存放关于具体文件的一般信息,每个索引节点对象都有一个索引节点号
这个节点号唯一地标识文件系统中的文件
geometry block_operations: 见于../../../../../third_party/NuttX/include/nuttx/fs/fs.h
***************************************************************/
INT32 los_disk_init(const CHAR *diskName, const struct block_operations *bops,
VOID *priv, INT32 diskID, VOID *info)
{
struct geometry diskInfo; //此结构提供有关块驱动程序状态的信息
struct inode *blkDriver = NULL;
los_disk *disk = get_disk(diskID);
struct inode_search_s desc;//见于 ../../../../../third_party/NuttX/fs/inode/inode.h
INT32 ret;
if ((diskName == NULL) || (disk == NULL) || //磁盘不能是未准备好状态
(disk->disk_status != STAT_UNREADY) || (strlen(diskName) > DISK_NAME)) {
return VFS_ERROR;
}
//详见 \third_party\NuttX\fs\driver\fs_registerblockdriver.c
if (register_blockdriver(diskName, bops, RWE_RW_RW, priv) != 0) {//1.在伪文件系统中注册块驱动程序,注册之后可以对其进行操作
PRINT_ERR("disk_init : register %s fail!\n", diskName);
return VFS_ERROR;
}
SETUP_SEARCH(&desc, diskName, false);//是个赋值宏操作 desc.path = diskName;
ret = inode_find(&desc);//2.更新desc.node
if (ret < 0) {
PRINT_ERR("disk_init : find %s fail!\n", diskName);
ret = ENOENT;
goto DISK_FIND_ERROR;
}
blkDriver = desc.node;//
if ((blkDriver->u.i_bops == NULL) || (blkDriver->u.i_bops->geometry == NULL) ||
(blkDriver->u.i_bops->geometry(blkDriver, &diskInfo) != 0)) {
goto DISK_BLKDRIVER_ERROR;
}
if (diskInfo.geo_sectorsize < DISK_MAX_SECTOR_SIZE) {
goto DISK_BLKDRIVER_ERROR;
}
PRINTK("disk_init : register %s ok!\n", diskName);
OsDiskInitSub(diskName, diskID, disk, &diskInfo, blkDriver);//3.初始化los_disk
inode_release(blkDriver);
if (DiskDivideAndPartitionRegister(info, disk) != ENOERR) {
(VOID)DiskDeinit(disk);
return VFS_ERROR;
}
disk->disk_status = STAT_INUSED;
if (info != NULL) {
disk->type = EMMC;
} else {
disk->type = OTHERS;
}
return ENOERR;
DISK_BLKDRIVER_ERROR:
PRINT_ERR("disk_init : register %s ok but get disk info fail!\n", diskName);
inode_release(blkDriver);
DISK_FIND_ERROR:
(VOID)unregister_blockdriver(diskName);
return VFS_ERROR;
}
//磁盘去初始化,和los_disk_init成对出现,类似于 C++ 的构造<->析构函数
INT32 los_disk_deinit(INT32 diskID)
{
los_disk *disk = get_disk(diskID);
if (disk == NULL) {
return -EINVAL;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
DISK_UNLOCK(&disk->disk_mutex);
return -EINVAL;
}
disk->disk_status = STAT_UNREADY;
DISK_UNLOCK(&disk->disk_mutex);
return DiskDeinit(disk);
}
INT32 los_disk_sync(INT32 drvID)
{
INT32 ret = ENOERR;
los_disk *disk = get_disk(drvID);
if (disk == NULL) {
return EINVAL;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
DISK_UNLOCK(&disk->disk_mutex);
return EINVAL;
}
#ifdef LOSCFG_FS_FAT_CACHE
if (disk->bcache != NULL) {
ret = BlockCacheSync(disk->bcache);
}
#endif
DISK_UNLOCK(&disk->disk_mutex);
return ret;
}
INT32 los_disk_set_bcache(INT32 drvID, UINT32 sectorPerBlock, UINT32 blockNum)
{
#ifdef LOSCFG_FS_FAT_CACHE
INT32 ret;
UINT32 intSave;
OsBcache *bc = NULL;
los_disk *disk = get_disk(drvID);
if ((disk == NULL) || (sectorPerBlock == 0)) {
return EINVAL;
}
/*
* Because we use UINT32 flag[BCACHE_BLOCK_FLAGS] in bcache for sectors bitmap tag, so it must
* be less than 32 * BCACHE_BLOCK_FLAGS.
*/
if (((sectorPerBlock % UNSIGNED_INTEGER_BITS) != 0) ||
((sectorPerBlock >> UNINT_LOG2_SHIFT) > BCACHE_BLOCK_FLAGS)) {
return EINVAL;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
if (disk->bcache != NULL) {
ret = BlockCacheSync(disk->bcache);
if (ret != ENOERR) {
DISK_UNLOCK(&disk->disk_mutex);
return ret;
}
}
spin_lock_irqsave(&g_diskFatBlockSpinlock, intSave);
DiskCacheDeinit(disk);
g_uwFatBlockNums = blockNum;
g_uwFatSectorsPerBlock = sectorPerBlock;
bc = BlockCacheInit(disk->dev, disk->sector_size, sectorPerBlock, blockNum, disk->sector_count / sectorPerBlock);
if ((bc == NULL) && (blockNum != 0)) {
spin_unlock_irqrestore(&g_diskFatBlockSpinlock, intSave);
DISK_UNLOCK(&disk->disk_mutex);
return ENOMEM;
}
if (bc != NULL) {
DiskCacheThreadInit((UINT32)drvID, bc);
}
disk->bcache = bc;
spin_unlock_irqrestore(&g_diskFatBlockSpinlock, intSave);
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return EINVAL;
#else
return VFS_ERROR;
#endif
}
static los_part *OsPartFind(los_disk *disk, const struct inode *blkDriver)
{
los_part *part = NULL;
DISK_LOCK(&disk->disk_mutex);
if ((disk->disk_status != STAT_INUSED) || (LOS_ListEmpty(&disk->head) == TRUE)) {
goto EXIT;
}
part = LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
if (disk->dev == blkDriver) {
goto EXIT;
}
while (&part->list != &disk->head) {
if (part->dev == blkDriver) {
goto EXIT;
}
part = LOS_DL_LIST_ENTRY(part->list.pstNext, los_part, list);
}
part = NULL;
EXIT:
DISK_UNLOCK(&disk->disk_mutex);
return part;
}
los_part *los_part_find(struct inode *blkDriver)
{
INT32 i;
los_disk *disk = NULL;
los_part *part = NULL;
if (blkDriver == NULL) {
return NULL;
}
for (i = 0; i < SYS_MAX_DISK; i++) {
disk = get_disk(i);
if (disk == NULL) {
continue;
}
part = OsPartFind(disk, blkDriver);
if (part != NULL) {
return part;
}
}
return NULL;
}
INT32 los_part_access(const CHAR *dev, mode_t mode)
{
los_part *part = NULL;
struct inode *node = NULL;
struct inode_search_s desc;
(VOID)mode;
SETUP_SEARCH(&desc, dev, false);
if (inode_find(&desc) < 0) {
return VFS_ERROR;
}
node = desc.node;
part = los_part_find(node);
inode_release(node);
if (part == NULL) {
return VFS_ERROR;
}
return ENOERR;
}
INT32 SetDiskPartName(los_part *part, const CHAR *src)
{
size_t len;
los_disk *disk = NULL;
if ((part == NULL) || (src == NULL)) {
return VFS_ERROR;
}
len = strlen(src);
if ((len == 0) || (len >= DISK_NAME)) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
part->part_name = (CHAR *)zalloc(len + 1);
if (part->part_name == NULL) {
PRINT_ERR("%s[%d] zalloc failure\n", __FUNCTION__, __LINE__);
goto ERROR_HANDLE;
}
(VOID)strcpy_s(part->part_name, len + 1, src);
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 add_mmc_partition(struct disk_divide_info *info, size_t sectorStart, size_t sectorCount)
{
UINT32 index, i;
if (info == NULL) {
return VFS_ERROR;
}
if ((info->part_count >= MAX_DIVIDE_PART_PER_DISK) || (sectorCount == 0)) {
return VFS_ERROR;
}
if ((sectorCount > info->sector_count) || ((info->sector_count - sectorCount) < sectorStart)) {
return VFS_ERROR;
}
index = info->part_count;
for (i = 0; i < index; i++) {
if (sectorStart < (info->part[i].sector_start + info->part[i].sector_count)) {
return VFS_ERROR;
}
}
info->part[index].sector_start = sectorStart;
info->part[index].sector_count = sectorCount;
info->part[index].type = EMMC;
info->part_count++;
return ENOERR;
}
VOID show_part(los_part *part)
{
if ((part == NULL) || (part->dev == NULL)) {
PRINT_ERR("part is NULL\n");
return;
}
PRINTK("\npart info :\n");
PRINTK("disk id : %u\n", part->disk_id);
PRINTK("part_id in system: %u\n", part->part_id);
PRINTK("part no in disk : %u\n", part->part_no_disk);
PRINTK("part no in mbr : %u\n", part->part_no_mbr);
PRINTK("part filesystem : %02X\n", part->filesystem_type);
PRINTK("part dev name : %s\n", part->dev->i_name);
PRINTK("part sec start : %llu\n", part->sector_start);
PRINTK("part sec count : %llu\n", part->sector_count);
}
INT32 EraseDiskByID(UINT32 diskID, size_t startSector, UINT32 sectors)
{
INT32 ret = VFS_ERROR;
#ifdef LOSCFG_DRIVERS_MMC
los_disk *disk = get_disk((INT32)diskID);
if (disk != NULL) {
ret = do_mmc_erase(diskID, startSector, sectors);
}
#endif
return ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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 "disk.h"
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "sys/mount.h"
#include "pthread.h"
#include "linux/spinlock.h"
#include "inode/inode.h"
#ifdef LOSCFG_DRIVERS_MMC
#include "mmc/block.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
los_disk g_sysDisk[SYS_MAX_DISK];//支持挂载的磁盘总数量 5个
los_part g_sysPart[SYS_MAX_PART];//支持磁盘的分区总数量 5*16,每个磁盘最大分16个区
UINT32 g_uwFatSectorsPerBlock = CONFIG_FS_FAT_SECTOR_PER_BLOCK; //每块支持扇区数 默认64个扇区
UINT32 g_uwFatBlockNums = CONFIG_FS_FAT_BLOCK_NUMS; //块数量 默认28
spinlock_t g_diskSpinlock; //磁盘自锁锁
spinlock_t g_diskFatBlockSpinlock;
UINT32 g_usbMode = 0;
#define MEM_ADDR_ALIGN_BYTE 64
#define RWE_RW_RW 0755
#define DISK_LOCK(mux) do { \
if (pthread_mutex_lock(mux) != 0) { \
PRINT_ERR("%s %d, mutex lock failed\n", __FUNCTION__, __LINE__); \
} \
} while (0)
#define DISK_UNLOCK(mux) do { \
if (pthread_mutex_unlock(mux) != 0) { \
PRINT_ERR("%s %d, mutex unlock failed\n", __FUNCTION__, __LINE__); \
} \
} while (0)
typedef VOID *(*StorageHookFunction)(VOID *);
static UINT32 OsReHookFuncAddDiskRef(StorageHookFunction handler,
VOID *param) __attribute__((weakref("osReHookFuncAdd")));
static UINT32 OsReHookFuncDelDiskRef(StorageHookFunction handler) __attribute__((weakref("osReHookFuncDel")));
#ifdef LOSCFG_FS_FAT_CACHE
UINT32 GetFatBlockNums(VOID)
{
return g_uwFatBlockNums;
}
VOID SetFatBlockNums(UINT32 blockNums)
{
g_uwFatBlockNums = blockNums;
}
UINT32 GetFatSectorsPerBlock(VOID)
{
return g_uwFatSectorsPerBlock;
}
VOID SetFatSectorsPerBlock(UINT32 sectorsPerBlock)
{
if (((sectorsPerBlock % UNSIGNED_INTEGER_BITS) == 0) &&
((sectorsPerBlock >> UNINT_LOG2_SHIFT) <= BCACHE_BLOCK_FLAGS)) {
g_uwFatSectorsPerBlock = sectorsPerBlock;
}
}
#endif
INT32 los_alloc_diskid_byname(const CHAR *diskName)
{
INT32 diskID;
los_disk *disk = NULL;
UINT32 intSave;
size_t nameLen;
if (diskName == NULL) {
PRINT_ERR("The paramter disk_name is NULL");
return VFS_ERROR;
}
nameLen = strlen(diskName);
if (nameLen > DISK_NAME) {
PRINT_ERR("diskName is too long!\n");
return VFS_ERROR;
}
spin_lock_irqsave(&g_diskSpinlock, intSave);
for (diskID = 0; diskID < SYS_MAX_DISK; diskID++) {
disk = get_disk(diskID);
if ((disk != NULL) && (disk->disk_status == STAT_UNUSED)) {
disk->disk_status = STAT_UNREADY;
break;
}
}
spin_unlock_irqrestore(&g_diskSpinlock, intSave);
if ((disk == NULL) || (diskID == SYS_MAX_DISK)) {
PRINT_ERR("los_alloc_diskid_byname failed %d!\n", diskID);
return VFS_ERROR;
}
if (disk->disk_name != NULL) {
LOS_MemFree(m_aucSysMem0, disk->disk_name);
disk->disk_name = NULL;
}
disk->disk_name = LOS_MemAlloc(m_aucSysMem0, (nameLen + 1));
if (disk->disk_name == NULL) {
PRINT_ERR("los_alloc_diskid_byname alloc disk name failed\n");
return VFS_ERROR;
}
if (strncpy_s(disk->disk_name, (nameLen + 1), diskName, nameLen) != EOK) {
PRINT_ERR("The strncpy_s failed.\n");
return VFS_ERROR;
}
disk->disk_name[nameLen] = '\0';
return diskID;
}
INT32 los_get_diskid_byname(const CHAR *diskName)
{
INT32 diskID;
los_disk *disk = NULL;
size_t diskNameLen;
if (diskName == NULL) {
PRINT_ERR("The paramter diskName is NULL");
return VFS_ERROR;
}
diskNameLen = strlen(diskName);
if (diskNameLen > DISK_NAME) {
PRINT_ERR("diskName is too long!\n");
return VFS_ERROR;
}
for (diskID = 0; diskID < SYS_MAX_DISK; diskID++) {
disk = get_disk(diskID);
if ((disk != NULL) && (disk->disk_name != NULL) && (disk->disk_status == STAT_INUSED)) {
if (strlen(disk->disk_name) != diskNameLen) {
continue;
}
if (strcmp(diskName, disk->disk_name) == 0) {
break;
}
}
}
if ((disk == NULL) || (diskID == SYS_MAX_DISK)) {
PRINT_ERR("los_get_diskid_byname failed!\n");
return VFS_ERROR;
}
return diskID;
}
VOID OsSetUsbStatus(UINT32 diskID)
{
if (diskID < SYS_MAX_DISK) {
g_usbMode |= (1u << diskID) & UINT_MAX;
}
}
VOID OsClearUsbStatus(UINT32 diskID)
{
if (diskID < SYS_MAX_DISK) {
g_usbMode &= ~((1u << diskID) & UINT_MAX);
}
}
#ifdef LOSCFG_FS_FAT_CACHE
static BOOL GetDiskUsbStatus(UINT32 diskID)
{
return (g_usbMode & (1u << diskID)) ? TRUE : FALSE;
}
#endif
//获取某个磁盘的描述符
los_disk *get_disk(INT32 id)
{
if ((id >= 0) && (id < SYS_MAX_DISK)) {
return &g_sysDisk[id];
}
return NULL;
}
//获取某个分区的描述符
los_part *get_part(INT32 id)
{
if ((id >= 0) && (id < SYS_MAX_PART)) {
return &g_sysPart[id];
}
return NULL;
}
static UINT64 GetFirstPartStart(const los_part *part)
{
los_part *firstPart = NULL;
los_disk *disk = get_disk((INT32)part->disk_id);
firstPart = (disk == NULL) ? NULL : LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
return (firstPart == NULL) ? 0 : firstPart->sector_start;
}
//磁盘增加一个分区
static VOID DiskPartAddToDisk(los_disk *disk, los_part *part)
{
part->disk_id = disk->disk_id;//分区描述符记录磁盘ID
part->part_no_disk = disk->part_count;//分区数量
LOS_ListTailInsert(&disk->head, &part->list);//将分区结点挂入磁盘分区双链表
disk->part_count++;//磁盘分区数量增加
}
//从磁盘上删除分区
static VOID DiskPartDelFromDisk(los_disk *disk, los_part *part)
{
LOS_ListDelete(&part->list);//摘掉分区节点
disk->part_count--;//分区数减少
}
//分配一个磁盘分区
static los_part *DiskPartAllocate(struct inode *dev, UINT64 start, UINT64 count)
{
UINT32 i;
los_part *part = get_part(0); /* traversing from the beginning of the array */
for (i = 0; i < SYS_MAX_PART; i++) {//从数组开始遍历
if (part->dev == NULL) {
part->part_id = i;
part->part_no_mbr = 0;
part->dev = dev;
part->sector_start = start;
part->sector_count = count;
part->part_name = NULL;
LOS_ListInit(&part->list);
return part;
}
part++;
}
return NULL;
}
//清空分区信息
static VOID DiskPartRelease(los_part *part)
{
part->dev = NULL;
part->part_no_disk = 0;
part->part_no_mbr = 0;
if (part->part_name != NULL) {
free(part->part_name);
part->part_name = NULL;
}
}
/*
* name is a combination of disk_name, 'p' and part_count, such as "/dev/mmcblk0p0"
* disk_name : DISK_NAME + 1
* 'p' : 1
* part_count: 1
*/
#define DEV_NAME_BUFF_SIZE (DISK_NAME + 3)//为何加3, 就是上面的disk_name+p+part_count
//磁盘增加一个分区
static INT32 DiskAddPart(los_disk *disk, UINT64 sectorStart, UINT64 sectorCount)
{
CHAR devName[DEV_NAME_BUFF_SIZE];
struct inode *diskDev = NULL;
struct inode *partDev = NULL;
los_part *part = NULL;
INT32 ret;
struct inode_search_s desc;
if ((disk == NULL) || (disk->disk_status == STAT_UNUSED) ||
(disk->dev == NULL)) {
return VFS_ERROR;
}
//扇区判断,磁盘在创建伊始就扇区数量就固定了
if ((sectorCount > disk->sector_count) || ((disk->sector_count - sectorCount) < sectorStart)) {
PRINT_ERR("DiskAddPart failed: sector start is %llu, sector count is %llu\n", sectorStart, sectorCount);
return VFS_ERROR;
}
///devName = /dev/mmcblk0p2 代表的是 0号磁盘的2号分区
ret = snprintf_s(devName, sizeof(devName), sizeof(devName) - 1, "%s%c%u",
(disk->disk_name == NULL ? "null" : disk->disk_name), 'p', disk->part_count);
if (ret < 0) {
return VFS_ERROR;
}
diskDev = disk->dev;
if (register_blockdriver(devName, diskDev->u.i_bops, RWE_RW_RW, diskDev->i_private)) {//注册块驱动程序
PRINT_ERR("DiskAddPart : register %s fail!\n", devName);
return VFS_ERROR;
}
SETUP_SEARCH(&desc, devName, false);//
ret = inode_find(&desc);
if (ret < 0) {
PRINT_ERR("DiskAddPart : find %s fail!\n", devName);
return VFS_ERROR;
}
partDev = desc.node;
PRINTK("DiskAddPart : register %s ok!\n", devName);
part = DiskPartAllocate(partDev, sectorStart, sectorCount);
inode_release(partDev);
if (part == NULL) {
(VOID)unregister_blockdriver(devName);
return VFS_ERROR;
}
DiskPartAddToDisk(disk, part);
if (disk->type == EMMC) {
part->type = EMMC;
}
return (INT32)part->part_id;
}
static INT32 DiskDivide(los_disk *disk, struct disk_divide_info *info)
{
UINT32 i;
INT32 ret;
disk->type = info->part[0].type;
for (i = 0; i < info->part_count; i++) {
if (info->sector_count < info->part[i].sector_start) {
return VFS_ERROR;
}
if (info->part[i].sector_count > (info->sector_count - info->part[i].sector_start)) {
PRINT_ERR("Part[%u] sector_start:%llu, sector_count:%llu, exceed emmc sector_count:%llu.\n", i,
info->part[i].sector_start, info->part[i].sector_count,
(info->sector_count - info->part[i].sector_start));
info->part[i].sector_count = info->sector_count - info->part[i].sector_start;
PRINT_ERR("Part[%u] sector_count change to %llu.\n", i, info->part[i].sector_count);
ret = DiskAddPart(disk, info->part[i].sector_start, info->part[i].sector_count);
if (ret == VFS_ERROR) {
return VFS_ERROR;
}
break;
}
ret = DiskAddPart(disk, info->part[i].sector_start, info->part[i].sector_count);
if (ret == VFS_ERROR) {
return VFS_ERROR;
}
}
return ENOERR;
}
static CHAR GPTPartitionTypeRecognition(const CHAR *parBuf)
{
const CHAR *buf = parBuf;
const CHAR *fsType = "FAT";
const CHAR *str = "\xEB\x52\x90" "NTFS "; /* NTFS Boot entry point */
if (((LD_DWORD_DISK(&buf[BS_FILSYSTEMTYPE32]) & BS_FS_TYPE_MASK) == BS_FS_TYPE_VALUE) ||
(strncmp(&buf[BS_FILSYSTYPE], fsType, strlen(fsType)) == 0)) {
return BS_FS_TYPE_FAT;
} else if (strncmp(&buf[BS_JMPBOOT], str, strlen(str)) == 0) {
return BS_FS_TYPE_NTFS;
}
return ENOERR;
}
static INT32 DiskPartitionMemZalloc(size_t boundary, size_t size, CHAR **gptBuf, CHAR **partitionBuf)
{
CHAR *buffer1 = NULL;
CHAR *buffer2 = NULL;
buffer1 = (CHAR *)memalign(boundary, size);
if (buffer1 == NULL) {
PRINT_ERR("%s buffer1 malloc %lu failed! %d\n", __FUNCTION__, size, __LINE__);
return VFS_ERROR;
}
buffer2 = (CHAR *)memalign(boundary, size);
if (buffer2 == NULL) {
PRINT_ERR("%s buffer2 malloc %lu failed! %d\n", __FUNCTION__, size, __LINE__);
free(buffer1);
return VFS_ERROR;
}
(VOID)memset_s(buffer1, size, 0, size);
(VOID)memset_s(buffer2, size, 0, size);
*gptBuf = buffer1;
*partitionBuf = buffer2;
return ENOERR;
}
static INT32 GPTInfoGet(struct inode *blkDrv, CHAR *gptBuf)
{
INT32 ret;
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)gptBuf, 1, 1); /* Read the device first sector */
if (ret != 1) { /* Read failed */
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
return -EIO;
}
if (!VERIFY_GPT(gptBuf)) {
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
return VFS_ERROR;
}
return ENOERR;
}
//GPT(Globally Unique Identifier Partition Table Format),全局唯一标识符的分区表的格式
static INT32 OsGPTPartitionRecognitionSub(struct disk_divide_info *info, const CHAR *partitionBuf,
UINT32 *partitionCount, UINT64 partitionStart, UINT64 partitionEnd)
{
CHAR partitionType;
if (VERIFY_FS(partitionBuf)) {
partitionType = GPTPartitionTypeRecognition(partitionBuf);
if (partitionType) {
if (*partitionCount >= MAX_DIVIDE_PART_PER_DISK) {
return VFS_ERROR;
}
info->part[*partitionCount].type = partitionType;
info->part[*partitionCount].sector_start = partitionStart;
info->part[*partitionCount].sector_count = (partitionEnd - partitionStart) + 1;
(*partitionCount)++;
} else {
PRINT_ERR("The partition type is not allowed to use!\n");
}
} else {
PRINT_ERR("Do not support the partition type!\n");
}
return ENOERR;
}
static INT32 OsGPTPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info,
const CHAR *gptBuf, CHAR *partitionBuf, UINT32 *partitionCount)
{
UINT32 j;
INT32 ret = VFS_ERROR;
UINT64 partitionStart, partitionEnd;
for (j = 0; j < PAR_ENTRY_NUM_PER_SECTOR; j++) {
if (!VERITY_AVAILABLE_PAR(&gptBuf[j * TABLE_SIZE])) {
PRINTK("The partition type is ESP or MSR!\n");
continue;
}
if (!VERITY_PAR_VALID(&gptBuf[j * TABLE_SIZE])) {
return VFS_ERROR;
}
partitionStart = LD_QWORD_DISK(&gptBuf[(j * TABLE_SIZE) + GPT_PAR_START_OFFSET]);
partitionEnd = LD_QWORD_DISK(&gptBuf[(j * TABLE_SIZE) + GPT_PAR_END_OFFSET]);
if ((partitionStart >= partitionEnd) || (partitionEnd > info->sector_count)) {
PRINT_ERR("GPT partition %u recognition failed : partitionStart = %llu, partitionEnd = %llu\n",
j, partitionStart, partitionEnd);
return VFS_ERROR;
}
(VOID)memset_s(partitionBuf, info->sector_size, 0, info->sector_size);
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)partitionBuf, partitionStart, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
return -EIO;
}
ret = OsGPTPartitionRecognitionSub(info, partitionBuf, partitionCount, partitionStart, partitionEnd);
if (ret != ENOERR) {
return VFS_ERROR;
}
}
return ret;
}
static INT32 DiskGPTPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info)
{
CHAR *gptBuf = NULL;
CHAR *partitionBuf = NULL;
UINT32 tableNum, i, index;
UINT32 partitionCount = 0;
INT32 ret;
ret = DiskPartitionMemZalloc(MEM_ADDR_ALIGN_BYTE, info->sector_size, &gptBuf, &partitionBuf);
if (ret != ENOERR) {
return VFS_ERROR;
}
ret = GPTInfoGet(blkDrv, gptBuf);
if (ret < 0) {
goto OUT_WITH_MEM;
}
tableNum = LD_DWORD_DISK(&gptBuf[TABLE_NUM_OFFSET]);
if (tableNum > TABLE_MAX_NUM) {
tableNum = TABLE_MAX_NUM;
}
index = (tableNum % PAR_ENTRY_NUM_PER_SECTOR) ? ((tableNum / PAR_ENTRY_NUM_PER_SECTOR) + 1) :
(tableNum / PAR_ENTRY_NUM_PER_SECTOR);
for (i = 0; i < index; i++) {
(VOID)memset_s(gptBuf, info->sector_size, 0, info->sector_size);
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)gptBuf, TABLE_START_SECTOR + i, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("%s %d\n", __FUNCTION__, __LINE__);
ret = -EIO;
goto OUT_WITH_MEM;
}
ret = OsGPTPartitionRecognition(blkDrv, info, gptBuf, partitionBuf, &partitionCount);
if (ret < 0) {
if (ret == VFS_ERROR) {
ret = (INT32)partitionCount;
}
goto OUT_WITH_MEM;
}
}
ret = (INT32)partitionCount;
OUT_WITH_MEM:
free(gptBuf);
free(partitionBuf);
return ret;
}
static INT32 OsMBRInfoGet(struct inode *blkDrv, CHAR *mbrBuf)
{
INT32 ret;
/* read MBR, start from sector 0, length is 1 sector */
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)mbrBuf, 0, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("driver read return error: %d\n", ret);
return -EIO;
}
/* Check boot record signature. */
if (LD_WORD_DISK(&mbrBuf[BS_SIG55AA]) != BS_SIG55AA_VALUE) {
return VFS_ERROR;
}
return ENOERR;
}
static INT32 OsEBRInfoGet(struct inode *blkDrv, const struct disk_divide_info *info,
CHAR *ebrBuf, const CHAR *mbrBuf)
{
INT32 ret;
if (VERIFY_FS(mbrBuf)) {
if (info->sector_count <= LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET])) {
return VFS_ERROR;
}
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)ebrBuf,
LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET]), 1);
if ((ret != 1) || (!VERIFY_FS(ebrBuf))) { /* read failed */
PRINT_ERR("OsEBRInfoGet, verify_fs error, ret = %d\n", ret);
return -EIO;
}
}
return ENOERR;
}
//给所有主分区的分区信息初始化
static INT32 OsPrimaryPartitionRecognition(const CHAR *mbrBuf, struct disk_divide_info *info,
INT32 *extendedPos, INT32 *mbrCount)
{
INT32 i;
CHAR mbrPartitionType;
INT32 extendedFlag = 0;
INT32 count = 0;
for (i = 0; i < MAX_PRIMARY_PART_PER_DISK; i++) {//遍历主分区
mbrPartitionType = mbrBuf[PAR_OFFSET + PAR_TYPE_OFFSET + (i * PAR_TABLE_SIZE)];
if (mbrPartitionType) {
info->part[i].type = mbrPartitionType;
info->part[i].sector_start = LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET + (i * PAR_TABLE_SIZE)]);
info->part[i].sector_count = LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_COUNT_OFFSET + (i * PAR_TABLE_SIZE)]);
if ((mbrPartitionType == EXTENDED_PAR) || (mbrPartitionType == EXTENDED_8G)) {
extendedFlag = 1;
*extendedPos = i;
continue;
}
count++;
}
}
*mbrCount = count;
return extendedFlag;
}
//给所有逻辑分区的分区信息初始化
static INT32 OsLogicalPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info,
UINT32 extendedAddress, CHAR *ebrBuf, INT32 mbrCount)
{
INT32 ret;
UINT32 extendedOffset = 0;
CHAR ebrPartitionType;
INT32 ebrCount = 0;
do {
(VOID)memset_s(ebrBuf, info->sector_size, 0, info->sector_size);
if (((UINT64)(extendedAddress) + extendedOffset) >= info->sector_count) {
PRINT_ERR("extended partition is out of disk range: extendedAddress = %u, extendedOffset = %u\n",
extendedAddress, extendedOffset);
break;
}
ret = blkDrv->u.i_bops->read(blkDrv, (UINT8 *)ebrBuf,
extendedAddress + extendedOffset, 1);
if (ret != 1) { /* read failed */
PRINT_ERR("driver read return error: %d, extendedAddress = %u, extendedOffset = %u\n", ret,
extendedAddress, extendedOffset);
return -EIO;
}
ebrPartitionType = ebrBuf[PAR_OFFSET + PAR_TYPE_OFFSET];
if (ebrPartitionType && ((mbrCount + ebrCount) < MAX_DIVIDE_PART_PER_DISK)) {
info->part[MAX_PRIMARY_PART_PER_DISK + ebrCount].type = ebrPartitionType;
info->part[MAX_PRIMARY_PART_PER_DISK + ebrCount].sector_start = extendedAddress + extendedOffset +
LD_DWORD_DISK(&ebrBuf[PAR_OFFSET +
PAR_START_OFFSET]);
info->part[MAX_PRIMARY_PART_PER_DISK + ebrCount].sector_count = LD_DWORD_DISK(&ebrBuf[PAR_OFFSET +
PAR_COUNT_OFFSET]);
ebrCount++;
}
extendedOffset = LD_DWORD_DISK(&ebrBuf[PAR_OFFSET + PAR_START_OFFSET + PAR_TABLE_SIZE]);
} while ((ebrBuf[PAR_OFFSET + PAR_TYPE_OFFSET + PAR_TABLE_SIZE] != 0) &&
((mbrCount + ebrCount) < MAX_DIVIDE_PART_PER_DISK));
return ebrCount;
}
static INT32 DiskPartitionRecognition(struct inode *blkDrv, struct disk_divide_info *info)
{
INT32 ret;
INT32 extendedFlag;
INT32 extendedPos = 0;
INT32 mbrCount = 0;
UINT32 extendedAddress;
CHAR *mbrBuf = NULL;
CHAR *ebrBuf = NULL;
if ((blkDrv == NULL) || (blkDrv->u.i_bops == NULL) || (blkDrv->u.i_bops->read == NULL)) {
return VFS_ERROR;
}
ret = DiskPartitionMemZalloc(MEM_ADDR_ALIGN_BYTE, info->sector_size, &mbrBuf, &ebrBuf);
if (ret != ENOERR) {
return ret;
}
ret = OsMBRInfoGet(blkDrv, mbrBuf);
if (ret < 0) {
goto OUT_WITH_MEM;
}
/* The partition type is GPT */
if (mbrBuf[PARTION_MODE_BTYE] == (CHAR)PARTION_MODE_GPT) {
ret = DiskGPTPartitionRecognition(blkDrv, info);
goto OUT_WITH_MEM;
}
ret = OsEBRInfoGet(blkDrv, info, ebrBuf, mbrBuf);
if (ret < 0) {
ret = 0; /* no mbr */
goto OUT_WITH_MEM;
}
extendedFlag = OsPrimaryPartitionRecognition(mbrBuf, info, &extendedPos, &mbrCount);
if (extendedFlag) {
extendedAddress = LD_DWORD_DISK(&mbrBuf[PAR_OFFSET + PAR_START_OFFSET + (extendedPos * PAR_TABLE_SIZE)]);
ret = OsLogicalPartitionRecognition(blkDrv, info, extendedAddress, ebrBuf, mbrCount);
if (ret <= 0) {
goto OUT_WITH_MEM;
}
}
ret += mbrCount;
OUT_WITH_MEM:
free(ebrBuf);
free(mbrBuf);
return ret;
}
INT32 DiskPartitionRegister(los_disk *disk)
{
INT32 count;
UINT32 i, partSize;
los_part *part = NULL;
struct disk_divide_info parInfo;
/* Fill disk_divide_info structure to set partition's infomation. */
(VOID)memset_s(parInfo.part, sizeof(parInfo.part), 0, sizeof(parInfo.part));
partSize = sizeof(parInfo.part) / sizeof(parInfo.part[0]);
parInfo.sector_size = disk->sector_size;
parInfo.sector_count = disk->sector_count;
count = DiskPartitionRecognition(disk->dev, &parInfo);
if (count < 0) {
return VFS_ERROR;
}
parInfo.part_count = count;
if (count == 0) {
part = get_part(DiskAddPart(disk, 0, disk->sector_count));
if (part == NULL) {
return VFS_ERROR;
}
part->part_no_mbr = 0;
PRINTK("No MBR detected.\n");
return ENOERR;
}
for (i = 0; i < partSize; i++) {
/* Read the disk_divide_info structure to get partition's infomation. */
if ((parInfo.part[i].type != 0) && (parInfo.part[i].type != EXTENDED_PAR) &&
(parInfo.part[i].type != EXTENDED_8G)) {
part = get_part(DiskAddPart(disk, parInfo.part[i].sector_start, parInfo.part[i].sector_count));
if (part == NULL) {
return VFS_ERROR;
}
part->part_no_mbr = i + 1;
part->filesystem_type = parInfo.part[i].type;
}
}
return ENOERR;
}
INT32 los_disk_read(INT32 drvID, VOID *buf, UINT64 sector, UINT32 count)
{
#ifdef LOSCFG_FS_FAT_CACHE
UINT32 len;
#endif
INT32 result = VFS_ERROR;
los_disk *disk = get_disk(drvID);
if ((buf == NULL) || (count == 0)) { /* buff equal to NULL or count equal to 0 */
return result;
}
if (disk == NULL) {
return result;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
if ((count > disk->sector_count) || ((disk->sector_count - count) < sector)) {
goto ERROR_HANDLE;
}
#ifdef LOSCFG_FS_FAT_CACHE
if (disk->bcache != NULL) {
if (((UINT64)(disk->bcache->sectorSize) * count) > UINT_MAX) {
goto ERROR_HANDLE;
}
len = disk->bcache->sectorSize * count;
result = BlockCacheRead(disk->bcache, (UINT8 *)buf, &len, sector);
if (result != ENOERR) {
PRINT_ERR("los_disk_read read err = %d, sector = %llu, len = %u\n", result, sector, len);
}
} else {
#endif
if ((disk->dev != NULL) && (disk->dev->u.i_bops != NULL) && (disk->dev->u.i_bops->read != NULL)) {
result = disk->dev->u.i_bops->read(disk->dev, (UINT8 *)buf, sector, count);
if (result == (INT32)count) {
result = ENOERR;
}
}
#ifdef LOSCFG_FS_FAT_CACHE
}
#endif
if (result != ENOERR) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_disk_write(INT32 drvID, const VOID *buf, UINT64 sector, UINT32 count)
{
#ifdef LOSCFG_FS_FAT_CACHE
UINT32 len;
#endif
INT32 result = VFS_ERROR;
los_disk *disk = get_disk(drvID);
if (disk == NULL) {
return result;
}
if ((buf == NULL) || (count == 0)) { /* buff equal to NULL or count equal to 0 */
return result;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
if ((count > disk->sector_count) || ((disk->sector_count - count) < sector)) {
goto ERROR_HANDLE;
}
#ifdef LOSCFG_FS_FAT_CACHE
if (disk->bcache != NULL) {
if (((UINT64)(disk->bcache->sectorSize) * count) > UINT_MAX) {
goto ERROR_HANDLE;
}
len = disk->bcache->sectorSize * count;
result = BlockCacheWrite(disk->bcache, (const UINT8 *)buf, &len, sector);
if (result != ENOERR) {
PRINT_ERR("los_disk_write write err = %d, sector = %llu, len = %u\n", result, sector, len);
}
} else {
#endif
if ((disk->dev != NULL) && (disk->dev->u.i_bops != NULL) && (disk->dev->u.i_bops->write != NULL)) {
result = disk->dev->u.i_bops->write(disk->dev, (UINT8 *)buf, sector, count);
if (result == (INT32)count) {
result = ENOERR;
}
}
#ifdef LOSCFG_FS_FAT_CACHE
}
#endif
if (result != ENOERR) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_disk_ioctl(INT32 drvID, INT32 cmd, VOID *buf)
{
struct geometry info;
los_disk *disk = get_disk(drvID);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((disk->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_CTRL_SYNC) {
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
}
if (buf == NULL) {
goto ERROR_HANDLE;
}
(VOID)memset_s(&info, sizeof(info), 0, sizeof(info));
if ((disk->dev->u.i_bops == NULL) || (disk->dev->u.i_bops->geometry == NULL) ||
(disk->dev->u.i_bops->geometry(disk->dev, &info) != 0)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_GET_SECTOR_COUNT) {
*(UINT64 *)buf = info.geo_nsectors;
if (info.geo_nsectors == 0) {
goto ERROR_HANDLE;
}
} else if (cmd == DISK_GET_SECTOR_SIZE) {
*(size_t *)buf = info.geo_sectorsize;
} else if (cmd == DISK_GET_BLOCK_SIZE) { /* Get erase block size in unit of sectors (UINT32) */
/* Block Num SDHC == 512, SD can be set to 512 or other */
*(size_t *)buf = DISK_MAX_SECTOR_SIZE / info.geo_sectorsize;
} else {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_part_read(INT32 pt, VOID *buf, UINT64 sector, UINT32 count)
{
const los_part *part = get_part(pt);
los_disk *disk = NULL;
INT32 ret;
if (part == NULL) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((part->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (count > part->sector_count) {
PRINT_ERR("los_part_read failed, invaild count, count = %u\n", count);
goto ERROR_HANDLE;
}
/* Read from absolute sector. */
if (part->type == EMMC) {
if ((disk->sector_count - part->sector_start) > sector) {
sector += part->sector_start;
} else {
PRINT_ERR("los_part_read failed, invaild sector, sector = %llu\n", sector);
goto ERROR_HANDLE;
}
}
if ((sector >= GetFirstPartStart(part)) &&
(((sector + count) > (part->sector_start + part->sector_count)) || (sector < part->sector_start))) {
PRINT_ERR("los_part_read error, sector = %llu, count = %u, part->sector_start = %llu, "
"part->sector_count = %llu\n", sector, count, part->sector_start, part->sector_count);
goto ERROR_HANDLE;
}
ret = los_disk_read((INT32)part->disk_id, buf, sector, count);
if (ret < 0) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
INT32 los_part_write(INT32 pt, VOID *buf, UINT64 sector, UINT32 count)
{
const los_part *part = get_part(pt);
los_disk *disk = NULL;
INT32 ret;
if (part == NULL) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((part->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (count > part->sector_count) {
PRINT_ERR("los_part_write failed, invaild count, count = %u\n", count);
goto ERROR_HANDLE;
}
/* Write to absolute sector. */
if (part->type == EMMC) {
if ((disk->sector_count - part->sector_start) > sector) {
sector += part->sector_start;
} else {
PRINT_ERR("los_part_write failed, invaild sector, sector = %llu\n", sector);
goto ERROR_HANDLE;
}
}
if ((sector >= GetFirstPartStart(part)) &&
(((sector + count) > (part->sector_start + part->sector_count)) || (sector < part->sector_start))) {
PRINT_ERR("los_part_write, sector = %llu, count = %u, part->sector_start = %llu, "
"part->sector_count = %llu\n", sector, count, part->sector_start, part->sector_count);
goto ERROR_HANDLE;
}
ret = los_disk_write((INT32)part->disk_id, (const VOID *)buf, sector, count);
if (ret < 0) {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
#define GET_ERASE_BLOCK_SIZE 0x2
INT32 los_part_ioctl(INT32 pt, INT32 cmd, VOID *buf)
{
struct geometry info;
los_part *part = get_part(pt);
los_disk *disk = NULL;
if (part == NULL) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if ((part->dev == NULL) || (disk->disk_status != STAT_INUSED)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_CTRL_SYNC) {
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
}
if (buf == NULL) {
goto ERROR_HANDLE;
}
(VOID)memset_s(&info, sizeof(info), 0, sizeof(info));
if ((part->dev->u.i_bops == NULL) || (part->dev->u.i_bops->geometry == NULL) ||
(part->dev->u.i_bops->geometry(part->dev, &info) != 0)) {
goto ERROR_HANDLE;
}
if (cmd == DISK_GET_SECTOR_COUNT) {
*(UINT64 *)buf = part->sector_count;
if (*(UINT64 *)buf == 0) {
goto ERROR_HANDLE;
}
} else if (cmd == DISK_GET_SECTOR_SIZE) {
*(size_t *)buf = info.geo_sectorsize;
} else if (cmd == DISK_GET_BLOCK_SIZE) { /* Get erase block size in unit of sectors (UINT32) */
if ((part->dev->u.i_bops->ioctl == NULL) ||
(part->dev->u.i_bops->ioctl(part->dev, GET_ERASE_BLOCK_SIZE, (UINTPTR)buf) != 0)) {
goto ERROR_HANDLE;
}
} else {
goto ERROR_HANDLE;
}
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
#ifdef LOSCFG_FS_FAT_CACHE
static VOID DiskCacheThreadInit(UINT32 diskID, OsBcache *bc)
{
bc->prereadFun = NULL;
if (GetDiskUsbStatus(diskID) == FALSE) {
if (BcacheAsyncPrereadInit(bc) == LOS_OK) {
bc->prereadFun = ResumeAsyncPreread;
}
#ifdef LOSCFG_FS_FAT_CACHE_SYNC_THREAD
BcacheSyncThreadInit(bc, diskID);
#endif
}
if (OsReHookFuncAddDiskRef != NULL) {
(VOID)OsReHookFuncAddDiskRef((StorageHookFunction)OsSdSync, (VOID *)0);
(VOID)OsReHookFuncAddDiskRef((StorageHookFunction)OsSdSync, (VOID *)1);
}
}
static OsBcache *DiskCacheInit(UINT32 diskID, const struct geometry *diskInfo, struct inode *blkDriver)
{
#define SECTOR_SIZE 512
OsBcache *bc = NULL;
UINT32 sectorPerBlock = diskInfo->geo_sectorsize / SECTOR_SIZE;
if (sectorPerBlock != 0) {
sectorPerBlock = g_uwFatSectorsPerBlock / sectorPerBlock;
if (sectorPerBlock != 0) {
bc = BlockCacheInit(blkDriver, diskInfo->geo_sectorsize, sectorPerBlock,
g_uwFatBlockNums, diskInfo->geo_nsectors / sectorPerBlock);
}
}
if (bc == NULL) {
PRINT_ERR("disk_init : disk have not init bcache cache!\n");
return NULL;
}
DiskCacheThreadInit(diskID, bc);
return bc;
}
static VOID DiskCacheDeinit(los_disk *disk)
{
UINT32 diskID = disk->disk_id;
if (GetDiskUsbStatus(diskID) == FALSE) {
if (BcacheAsyncPrereadDeinit(disk->bcache) != LOS_OK) {
PRINT_ERR("Blib async preread deinit failed in %s, %d\n", __FUNCTION__, __LINE__);
}
#ifdef LOSCFG_FS_FAT_CACHE_SYNC_THREAD
BcacheSyncThreadDeinit(disk->bcache);
#endif
}
BlockCacheDeinit(disk->bcache);
disk->bcache = NULL;
if (OsReHookFuncDelDiskRef != NULL) {
(VOID)OsReHookFuncDelDiskRef((StorageHookFunction)OsSdSync);
}
}
#endif
static VOID DiskStructInit(const CHAR *diskName, INT32 diskID, const struct geometry *diskInfo,
struct inode *blkDriver, los_disk *disk)
{
size_t nameLen;
disk->disk_id = diskID;
disk->dev = blkDriver;
disk->sector_start = 0;
disk->sector_size = diskInfo->geo_sectorsize;
disk->sector_count = diskInfo->geo_nsectors;
nameLen = strlen(diskName); /* caller los_disk_init has chek name */
if (disk->disk_name != NULL) {
LOS_MemFree(m_aucSysMem0, disk->disk_name);
disk->disk_name = NULL;
}
disk->disk_name = LOS_MemAlloc(m_aucSysMem0, (nameLen + 1));
if (disk->disk_name == NULL) {
PRINT_ERR("DiskStructInit alloc memory failed.\n");
return;
}
if (strncpy_s(disk->disk_name, (nameLen + 1), diskName, nameLen) != EOK) {
PRINT_ERR("DiskStructInit strncpy_s failed.\n");
return;
}
disk->disk_name[nameLen] = '\0';
LOS_ListInit(&disk->head);
}
static INT32 DiskDivideAndPartitionRegister(struct disk_divide_info *info, los_disk *disk)
{
INT32 ret;
if (info != NULL) {
ret = DiskDivide(disk, info);
if (ret != ENOERR) {
PRINT_ERR("DiskDivide failed, ret = %d\n", ret);
return ret;
}
} else {
ret = DiskPartitionRegister(disk);
if (ret != ENOERR) {
PRINT_ERR("DiskPartitionRegister failed, ret = %d\n", ret);
return ret;
}
}
return ENOERR;
}
static INT32 DiskDeinit(los_disk *disk)
{
los_part *part = NULL;
char *diskName = NULL;
CHAR devName[DEV_NAME_BUFF_SIZE];
INT32 ret;
if (LOS_ListEmpty(&disk->head) == FALSE) {
part = LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
while (&part->list != &disk->head) {
diskName = (disk->disk_name == NULL) ? "null" : disk->disk_name;
ret = snprintf_s(devName, sizeof(devName), sizeof(devName) - 1, "%s%c%d",
diskName, 'p', disk->part_count - 1);
if (ret < 0) {
return -ENAMETOOLONG;
}
DiskPartDelFromDisk(disk, part);
(VOID)unregister_blockdriver(devName);
DiskPartRelease(part);
part = LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
}
}
DISK_LOCK(&disk->disk_mutex);
#ifdef LOSCFG_FS_FAT_CACHE
DiskCacheDeinit(disk);
#endif
disk->dev = NULL;
DISK_UNLOCK(&disk->disk_mutex);
(VOID)unregister_blockdriver(disk->disk_name);
if (disk->disk_name != NULL) {
LOS_MemFree(m_aucSysMem0, disk->disk_name);
disk->disk_name = NULL;
}
ret = pthread_mutex_destroy(&disk->disk_mutex);
if (ret != 0) {
PRINT_ERR("%s %d, mutex destroy failed, ret = %d\n", __FUNCTION__, __LINE__, ret);
return -EFAULT;
}
disk->disk_status = STAT_UNUSED;
return ENOERR;
}
static VOID OsDiskInitSub(const CHAR *diskName, INT32 diskID, los_disk *disk,
struct geometry *diskInfo, struct inode *blkDriver)
{
pthread_mutexattr_t attr;
#ifdef LOSCFG_FS_FAT_CACHE
OsBcache *bc = DiskCacheInit((UINT32)diskID, diskInfo, blkDriver);
disk->bcache = bc;
#endif
(VOID)pthread_mutexattr_init(&attr);//posix 互斥量属性初始化
attr.type = PTHREAD_MUTEX_RECURSIVE;//使用递归型互斥,鸿蒙内核为降低死锁概率 默认就是递归方式
(VOID)pthread_mutex_init(&disk->disk_mutex, &attr);//初始化磁盘的互斥量
DiskStructInit(diskName, diskID, diskInfo, blkDriver, disk);//初始化磁盘描述符los_disk
}
/***************************************************************
磁盘初始化 , diskName 必须是 /dev/***
当块设备注册到系统。它被文件系统用来执行文件系统处理。它可以处理struct inode
inode:索引节点对象,存放关于具体文件的一般信息,每个索引节点对象都有一个索引节点号
这个节点号唯一地标识文件系统中的文件
geometry block_operations: 见于../../../../../third_party/NuttX/include/nuttx/fs/fs.h
***************************************************************/
INT32 los_disk_init(const CHAR *diskName, const struct block_operations *bops,
VOID *priv, INT32 diskID, VOID *info)
{
struct geometry diskInfo; //此结构提供有关块驱动程序状态的信息
struct inode *blkDriver = NULL;//块设备驱动
los_disk *disk = get_disk(diskID);
struct inode_search_s desc;//见于 ../../../../../third_party/NuttX/fs/inode/inode.h
INT32 ret;
if ((diskName == NULL) || (disk == NULL) || //磁盘不能是未准备好状态
(disk->disk_status != STAT_UNREADY) || (strlen(diskName) > DISK_NAME)) {
return VFS_ERROR;
}
//详见 \third_party\NuttX\fs\driver\fs_registerblockdriver.c
if (register_blockdriver(diskName, bops, RWE_RW_RW, priv) != 0) {//1.在伪文件系统中注册块驱动程序,注册之后可以对其进行操作
PRINT_ERR("disk_init : register %s fail!\n", diskName);
return VFS_ERROR;
}
SETUP_SEARCH(&desc, diskName, false);//是个赋值宏操作 desc.path = diskName;
ret = inode_find(&desc);//2.更新desc.node
if (ret < 0) {
PRINT_ERR("disk_init : find %s fail!\n", diskName);
ret = ENOENT;
goto DISK_FIND_ERROR;
}
blkDriver = desc.node;//
if ((blkDriver->u.i_bops == NULL) || (blkDriver->u.i_bops->geometry == NULL) ||
(blkDriver->u.i_bops->geometry(blkDriver, &diskInfo) != 0)) {
goto DISK_BLKDRIVER_ERROR;
}
if (diskInfo.geo_sectorsize < DISK_MAX_SECTOR_SIZE) {
goto DISK_BLKDRIVER_ERROR;
}
PRINTK("disk_init : register %s ok!\n", diskName);
OsDiskInitSub(diskName, diskID, disk, &diskInfo, blkDriver);//3.初始化los_disk
inode_release(blkDriver);
if (DiskDivideAndPartitionRegister(info, disk) != ENOERR) {
(VOID)DiskDeinit(disk);
return VFS_ERROR;
}
disk->disk_status = STAT_INUSED;
if (info != NULL) {
disk->type = EMMC;
} else {
disk->type = OTHERS;
}
return ENOERR;
DISK_BLKDRIVER_ERROR:
PRINT_ERR("disk_init : register %s ok but get disk info fail!\n", diskName);
inode_release(blkDriver);
DISK_FIND_ERROR:
(VOID)unregister_blockdriver(diskName);
return VFS_ERROR;
}
//磁盘去初始化,和los_disk_init成对出现,类似于 C++ 的构造<->析构函数
INT32 los_disk_deinit(INT32 diskID)
{
los_disk *disk = get_disk(diskID);
if (disk == NULL) {
return -EINVAL;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
DISK_UNLOCK(&disk->disk_mutex);
return -EINVAL;
}
disk->disk_status = STAT_UNREADY;
DISK_UNLOCK(&disk->disk_mutex);
return DiskDeinit(disk);
}
INT32 los_disk_sync(INT32 drvID)
{
INT32 ret = ENOERR;
los_disk *disk = get_disk(drvID);
if (disk == NULL) {
return EINVAL;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
DISK_UNLOCK(&disk->disk_mutex);
return EINVAL;
}
#ifdef LOSCFG_FS_FAT_CACHE
if (disk->bcache != NULL) {
ret = BlockCacheSync(disk->bcache);
}
#endif
DISK_UNLOCK(&disk->disk_mutex);
return ret;
}
INT32 los_disk_set_bcache(INT32 drvID, UINT32 sectorPerBlock, UINT32 blockNum)
{
#ifdef LOSCFG_FS_FAT_CACHE
INT32 ret;
UINT32 intSave;
OsBcache *bc = NULL;
los_disk *disk = get_disk(drvID);
if ((disk == NULL) || (sectorPerBlock == 0)) {
return EINVAL;
}
/*
* Because we use UINT32 flag[BCACHE_BLOCK_FLAGS] in bcache for sectors bitmap tag, so it must
* be less than 32 * BCACHE_BLOCK_FLAGS.
*/
if (((sectorPerBlock % UNSIGNED_INTEGER_BITS) != 0) ||
((sectorPerBlock >> UNINT_LOG2_SHIFT) > BCACHE_BLOCK_FLAGS)) {
return EINVAL;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
if (disk->bcache != NULL) {
ret = BlockCacheSync(disk->bcache);
if (ret != ENOERR) {
DISK_UNLOCK(&disk->disk_mutex);
return ret;
}
}
spin_lock_irqsave(&g_diskFatBlockSpinlock, intSave);
DiskCacheDeinit(disk);
g_uwFatBlockNums = blockNum;
g_uwFatSectorsPerBlock = sectorPerBlock;
bc = BlockCacheInit(disk->dev, disk->sector_size, sectorPerBlock, blockNum, disk->sector_count / sectorPerBlock);
if ((bc == NULL) && (blockNum != 0)) {
spin_unlock_irqrestore(&g_diskFatBlockSpinlock, intSave);
DISK_UNLOCK(&disk->disk_mutex);
return ENOMEM;
}
if (bc != NULL) {
DiskCacheThreadInit((UINT32)drvID, bc);
}
disk->bcache = bc;
spin_unlock_irqrestore(&g_diskFatBlockSpinlock, intSave);
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return EINVAL;
#else
return VFS_ERROR;
#endif
}
static los_part *OsPartFind(los_disk *disk, const struct inode *blkDriver)
{
los_part *part = NULL;
DISK_LOCK(&disk->disk_mutex);
if ((disk->disk_status != STAT_INUSED) || (LOS_ListEmpty(&disk->head) == TRUE)) {
goto EXIT;
}
part = LOS_DL_LIST_ENTRY(disk->head.pstNext, los_part, list);
if (disk->dev == blkDriver) {
goto EXIT;
}
while (&part->list != &disk->head) {
if (part->dev == blkDriver) {
goto EXIT;
}
part = LOS_DL_LIST_ENTRY(part->list.pstNext, los_part, list);
}
part = NULL;
EXIT:
DISK_UNLOCK(&disk->disk_mutex);
return part;
}
los_part *los_part_find(struct inode *blkDriver)
{
INT32 i;
los_disk *disk = NULL;
los_part *part = NULL;
if (blkDriver == NULL) {
return NULL;
}
for (i = 0; i < SYS_MAX_DISK; i++) {
disk = get_disk(i);
if (disk == NULL) {
continue;
}
part = OsPartFind(disk, blkDriver);
if (part != NULL) {
return part;
}
}
return NULL;
}
INT32 los_part_access(const CHAR *dev, mode_t mode)
{
los_part *part = NULL;
struct inode *node = NULL;
struct inode_search_s desc;
(VOID)mode;
SETUP_SEARCH(&desc, dev, false);
if (inode_find(&desc) < 0) {
return VFS_ERROR;
}
node = desc.node;
part = los_part_find(node);
inode_release(node);
if (part == NULL) {
return VFS_ERROR;
}
return ENOERR;
}
INT32 SetDiskPartName(los_part *part, const CHAR *src)
{
size_t len;
los_disk *disk = NULL;
if ((part == NULL) || (src == NULL)) {
return VFS_ERROR;
}
len = strlen(src);
if ((len == 0) || (len >= DISK_NAME)) {
return VFS_ERROR;
}
disk = get_disk((INT32)part->disk_id);
if (disk == NULL) {
return VFS_ERROR;
}
DISK_LOCK(&disk->disk_mutex);
if (disk->disk_status != STAT_INUSED) {
goto ERROR_HANDLE;
}
part->part_name = (CHAR *)zalloc(len + 1);
if (part->part_name == NULL) {
PRINT_ERR("%s[%d] zalloc failure\n", __FUNCTION__, __LINE__);
goto ERROR_HANDLE;
}
(VOID)strcpy_s(part->part_name, len + 1, src);
DISK_UNLOCK(&disk->disk_mutex);
return ENOERR;
ERROR_HANDLE:
DISK_UNLOCK(&disk->disk_mutex);
return VFS_ERROR;
}
//增加一个MMC分区
INT32 add_mmc_partition(struct disk_divide_info *info, size_t sectorStart, size_t sectorCount)
{
UINT32 index, i;
if (info == NULL) {
return VFS_ERROR;
}
if ((info->part_count >= MAX_DIVIDE_PART_PER_DISK) || (sectorCount == 0)) {
return VFS_ERROR;
}
if ((sectorCount > info->sector_count) || ((info->sector_count - sectorCount) < sectorStart)) {
return VFS_ERROR;
}
index = info->part_count;
for (i = 0; i < index; i++) {
if (sectorStart < (info->part[i].sector_start + info->part[i].sector_count)) {
return VFS_ERROR;
}
}
info->part[index].sector_start = sectorStart;
info->part[index].sector_count = sectorCount;
info->part[index].type = EMMC;
info->part_count++;
return ENOERR;
}
VOID show_part(los_part *part)
{
if ((part == NULL) || (part->dev == NULL)) {
PRINT_ERR("part is NULL\n");
return;
}
PRINTK("\npart info :\n");
PRINTK("disk id : %u\n", part->disk_id);
PRINTK("part_id in system: %u\n", part->part_id);
PRINTK("part no in disk : %u\n", part->part_no_disk);
PRINTK("part no in mbr : %u\n", part->part_no_mbr);
PRINTK("part filesystem : %02X\n", part->filesystem_type);
PRINTK("part dev name : %s\n", part->dev->i_name);
PRINTK("part sec start : %llu\n", part->sector_start);
PRINTK("part sec count : %llu\n", part->sector_count);
}
INT32 EraseDiskByID(UINT32 diskID, size_t startSector, UINT32 sectors)
{
INT32 ret = VFS_ERROR;
#ifdef LOSCFG_DRIVERS_MMC
los_disk *disk = get_disk((INT32)diskID);
if (disk != NULL) {
ret = do_mmc_erase(diskID, startSector, sectors);
}
#endif
return ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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 "mtd_partition.h"
#include "stdlib.h"
#include "stdio.h"
#include "pthread.h"
#include "mtd_list.h"
#include "los_config.h"
#include "los_mux.h"
#include "inode/inode.h"
#if defined(LOSCFG_FS_JFFS)
#include "mtd_common.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define DRIVER_NAME_ADD_SIZE 3
pthread_mutex_t g_mtdPartitionLock = PTHREAD_MUTEX_INITIALIZER;
//通常在NorFlash上会选取jffs及jffs2文件系统
static INT32 JffsLockInit(VOID) __attribute__((weakref("JffsMutexCreate")));//弱引用 JffsMutexCreate
static VOID JffsLockDeinit(VOID) __attribute__((weakref("JffsMutexDelete")));//弱引用 JffsMutexDelete
partition_param *g_spinorPartParam = NULL;
mtd_partition *g_spinorPartitionHead = NULL;
#define RWE_RW_RW 0755 //文件读/写/执权限,chmod 755
mtd_partition *GetSpinorPartitionHead(VOID)
{
return g_spinorPartitionHead;
}
//初始化 norflash 参数
static VOID MtdNorParamAssign(partition_param *spinorParam, const struct MtdDev *spinorMtd)
{
LOS_ListInit(&g_spinorPartitionHead->node_info);
/*
* If the user do not want to use block mtd or char mtd ,
* you can change the SPIBLK_NAME or SPICHR_NAME to NULL.
*/
spinorParam->flash_mtd = (struct MtdDev *)spinorMtd;
spinorParam->flash_ops = GetDevSpinorOps(); //获取块设备操作方法
spinorParam->char_ops = GetMtdCharFops(); //获取字符设备操作方法
spinorParam->blockname = SPIBLK_NAME;
spinorParam->charname = SPICHR_NAME;
spinorParam->partition_head = g_spinorPartitionHead;
spinorParam->block_size = spinorMtd->eraseSize;//4K, 读/写/擦除 的最小单位
}
//反初始化 norflash 参数
static VOID MtdDeinitSpinorParam(VOID)
{
if (JffsLockDeinit != NULL) {
JffsLockDeinit();
}
}
//初始化 nor flash 参数
static partition_param *MtdInitSpinorParam(partition_param *spinorParam)
{
struct MtdDev *spinorMtd = GetMtd("spinor");
if (spinorMtd == NULL) {
return NULL;
}
if (spinorParam == NULL) {
if (JffsLockInit != NULL) {
if (JffsLockInit() != 0) { /* create jffs2 lock failed */
return NULL;
}
}
spinorParam = (partition_param *)zalloc(sizeof(partition_param));
if (spinorParam == NULL) {
PRINT_ERR("%s, partition_param malloc failed\n", __FUNCTION__);
MtdDeinitSpinorParam();
return NULL;
}
g_spinorPartitionHead = (mtd_partition *)zalloc(sizeof(mtd_partition));
if (g_spinorPartitionHead == NULL) {
PRINT_ERR("%s, mtd_partition malloc failed\n", __FUNCTION__);
MtdDeinitSpinorParam();
free(spinorParam);
return NULL;
}
MtdNorParamAssign(spinorParam, spinorMtd);
}
return spinorParam;
}
/* According the flash-type to init the param of the partition. *///根据flash类型初始化分区的参数
static INT32 MtdInitFsparParam(const CHAR *type, partition_param **fsparParam)
{
if (strcmp(type, "spinor") == 0) {
g_spinorPartParam = MtdInitSpinorParam(g_spinorPartParam);
*fsparParam = g_spinorPartParam;
} else {
return -EINVAL;
}
if ((*fsparParam == NULL) || ((VOID *)((*fsparParam)->flash_mtd) == NULL)) {
return -ENODEV;
}
return ENOERR;
}
/* According the flash-type to deinit the param of the partition. */
static INT32 MtdDeinitFsparParam(const CHAR *type)
{
if (strcmp(type, "spinor") == 0) {
MtdDeinitSpinorParam();
g_spinorPartParam = NULL;
} else {
return -EINVAL;
}
return ENOERR;
}
static INT32 AddParamCheck(UINT32 startAddr,
const partition_param *param,
UINT32 partitionNum,
UINT32 length)
{
UINT32 startBlk, endBlk;
mtd_partition *node = NULL;
if ((param->blockname == NULL) && (param->charname == NULL)) {
return -EINVAL;
}
if ((length == 0) || (length < param->block_size) ||
(((UINT64)(startAddr) + length) > param->flash_mtd->size)) {
return -EINVAL;
}
ALIGN_ASSIGN(length, startAddr, startBlk, endBlk, param->block_size);
if (startBlk > endBlk) {
return -EINVAL;
}
LOS_DL_LIST_FOR_EACH_ENTRY(node, &param->partition_head->node_info, mtd_partition, node_info) {
if ((node->start_block != 0) && (node->patitionnum == partitionNum)) {
return -EINVAL;
}
if ((startBlk > node->end_block) || (endBlk < node->start_block)) {
continue;
}
return -EINVAL;
}
return ENOERR;
}
//注册块设备
static INT32 BlockDriverRegisterOperate(mtd_partition *newNode,
const partition_param *param,
UINT32 partitionNum)
{
INT32 ret;
size_t driverNameSize;
if (param->blockname != NULL) {
driverNameSize = strlen(param->blockname) + DRIVER_NAME_ADD_SIZE;
newNode->blockdriver_name = (CHAR *)malloc(driverNameSize);
if (newNode->blockdriver_name == NULL) {
return -ENOMEM;
}
ret = snprintf_s(newNode->blockdriver_name, driverNameSize,
driverNameSize - 1, "%s%u", param->blockname, partitionNum);
if (ret < 0) {
free(newNode->blockdriver_name);
newNode->blockdriver_name = NULL;
return -ENAMETOOLONG;
}
//在伪文件系统中注册块驱动程序,生成设备结点 inode
ret = register_blockdriver(newNode->blockdriver_name, param->flash_ops,
RWE_RW_RW, newNode);
if (ret) {
free(newNode->blockdriver_name);
newNode->blockdriver_name = NULL;
PRINT_ERR("register blkdev partion error\n");
return ret;
}
} else {
newNode->blockdriver_name = NULL;
}
return ENOERR;
}
//注册字符设备
static INT32 CharDriverRegisterOperate(mtd_partition *newNode,
const partition_param *param,
UINT32 partitionNum)
{
INT32 ret;
size_t driverNameSize;
if (param->charname != NULL) {
driverNameSize = strlen(param->charname) + DRIVER_NAME_ADD_SIZE;
newNode->chardriver_name = (CHAR *)malloc(driverNameSize);
if (newNode->chardriver_name == NULL) {
return -ENOMEM;
}
ret = snprintf_s(newNode->chardriver_name, driverNameSize,
driverNameSize - 1, "%s%u", param->charname, partitionNum);
if (ret < 0) {
free(newNode->chardriver_name);
newNode->chardriver_name = NULL;
return -ENAMETOOLONG;
}
//在伪文件系统中注册字符设备驱动程序,生成设备结点 inode
ret = register_driver(newNode->chardriver_name, param->char_ops, RWE_RW_RW, newNode);
if (ret) {
PRINT_ERR("register chardev partion error\n");
free(newNode->chardriver_name);
newNode->chardriver_name = NULL;
return ret;
}
} else {
newNode->chardriver_name = NULL;
}
return ENOERR;
}
//注销块设备驱动程序,从伪文件系统中删除“path”处的块驱动程序inode
static INT32 BlockDriverUnregister(mtd_partition *node)
{
INT32 ret;
if (node->blockdriver_name != NULL) {
ret = unregister_blockdriver(node->blockdriver_name);
if (ret == -EBUSY) {
PRINT_ERR("unregister blkdev partion error:%d\n", ret);
return ret;
}
free(node->blockdriver_name);
node->blockdriver_name = NULL;
}
return ENOERR;
}
//注销字符设备驱动程序,从伪文件系统中删除“path”处的字符驱动程序inode
static INT32 CharDriverUnregister(mtd_partition *node)
{
INT32 ret;
if (node->chardriver_name != NULL) {
ret = unregister_driver(node->chardriver_name);
if (ret == -EBUSY) {
PRINT_ERR("unregister chardev partion error:%d\n", ret);
return ret;
}
free(node->chardriver_name);
node->chardriver_name = NULL;
}
return ENOERR;
}
/*
* Attention: both startAddr and length should be aligned with block size.
* If not, the actual start address and length won't be what you expected.
*/
INT32 add_mtd_partition(const CHAR *type, UINT32 startAddr,
UINT32 length, UINT32 partitionNum)
{
INT32 ret;
mtd_partition *newNode = NULL;
partition_param *param = NULL;
if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) || (type == NULL)) {
return -EINVAL;
}
ret = pthread_mutex_lock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
ret = MtdInitFsparParam(type, &param);
if (ret != ENOERR) {
goto ERROR_OUT;
}
ret = AddParamCheck(startAddr, param, partitionNum, length);
if (ret != ENOERR) {
goto ERROR_OUT;
}
newNode = (mtd_partition *)zalloc(sizeof(mtd_partition));
if (newNode == NULL) {
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return -ENOMEM;
}
PAR_ASSIGNMENT(newNode, length, startAddr, partitionNum, param->flash_mtd, param->block_size);
ret = BlockDriverRegisterOperate(newNode, param, partitionNum);
if (ret) {
goto ERROR_OUT1;
}
ret = CharDriverRegisterOperate(newNode, param, partitionNum);
if (ret) {
goto ERROR_OUT2;
}
LOS_ListTailInsert(&param->partition_head->node_info, &newNode->node_info);
(VOID)LOS_MuxInit(&newNode->lock, NULL);
ret = pthread_mutex_unlock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
return ENOERR;
ERROR_OUT2:
(VOID)BlockDriverUnregister(newNode);
ERROR_OUT1:
free(newNode);
ERROR_OUT:
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
static INT32 DeleteParamCheck(UINT32 partitionNum,
const CHAR *type,
partition_param **param)
{
if (strcmp(type, "spinor") == 0) {
*param = g_spinorPartParam;
} else {
PRINT_ERR("type error \n");
return -EINVAL;
}
if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) ||
((*param) == NULL) || ((*param)->flash_mtd == NULL)) {
return -EINVAL;
}
return ENOERR;
}
static INT32 DeletePartitionUnregister(mtd_partition *node)
{
INT32 ret;
ret = BlockDriverUnregister(node);
if (ret == -EBUSY) {
return ret;
}
ret = CharDriverUnregister(node);
if (ret == -EBUSY) {
return ret;
}
return ENOERR;
}
static INT32 OsNodeGet(mtd_partition **node, UINT32 partitionNum, const partition_param *param)
{
LOS_DL_LIST_FOR_EACH_ENTRY(*node, &param->partition_head->node_info, mtd_partition, node_info) {
if ((*node)->patitionnum == partitionNum) {
break;
}
}
if ((*node == NULL) || ((*node)->patitionnum != partitionNum) ||
((*node)->mountpoint_name != NULL)) {
return -EINVAL;
}
return ENOERR;
}
static INT32 OsResourceRelease(mtd_partition *node, const CHAR *type, partition_param *param)
{
(VOID)LOS_MuxDestroy(&node->lock);
LOS_ListDelete(&node->node_info);
(VOID)memset_s(node, sizeof(mtd_partition), 0, sizeof(mtd_partition));
free(node);
(VOID)FreeMtd(param->flash_mtd);
if (LOS_ListEmpty(&param->partition_head->node_info)) {
free(param->partition_head);
param->partition_head = NULL;
free(param);
if (MtdDeinitFsparParam(type) != ENOERR) {
return -EINVAL;
}
}
return ENOERR;
}
INT32 delete_mtd_partition(UINT32 partitionNum, const CHAR *type)
{
INT32 ret;
mtd_partition *node = NULL;
partition_param *param = NULL;
if (type == NULL) {
return -EINVAL;
}
ret = pthread_mutex_lock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
ret = DeleteParamCheck(partitionNum, type, &param);
if (ret) {
PRINT_ERR("delete_mtd_partition param invalid\n");
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = OsNodeGet(&node, partitionNum, param);
if (ret) {
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = DeletePartitionUnregister(node);
if (ret) {
PRINT_ERR("DeletePartitionUnregister error:%d\n", ret);
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = OsResourceRelease(node, type, param);
if (ret) {
PRINT_ERR("DeletePartitionUnregister error:%d\n", ret);
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = pthread_mutex_unlock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
return ENOERR;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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 "mtd_partition.h"
#include "stdlib.h"
#include "stdio.h"
#include "pthread.h"
#include "mtd_list.h"
#include "los_config.h"
#include "los_mux.h"
#include "inode/inode.h"
#if defined(LOSCFG_FS_JFFS)
#include "mtd_common.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define DRIVER_NAME_ADD_SIZE 3
pthread_mutex_t g_mtdPartitionLock = PTHREAD_MUTEX_INITIALIZER;
//通常在NorFlash上会选取jffs及jffs2文件系统
static INT32 JffsLockInit(VOID) __attribute__((weakref("JffsMutexCreate")));//弱引用 JffsMutexCreate
static VOID JffsLockDeinit(VOID) __attribute__((weakref("JffsMutexDelete")));//弱引用 JffsMutexDelete
partition_param *g_spinorPartParam = NULL;
mtd_partition *g_spinorPartitionHead = NULL;
#define RWE_RW_RW 0755 //文件读/写/执权限,chmod 755
mtd_partition *GetSpinorPartitionHead(VOID)
{
return g_spinorPartitionHead;
}
//初始化 norflash 参数
static VOID MtdNorParamAssign(partition_param *spinorParam, const struct MtdDev *spinorMtd)
{
LOS_ListInit(&g_spinorPartitionHead->node_info);//初始化双向链表,链表用于挂其他分区,方便管理
/*
* If the user do not want to use block mtd or char mtd ,
* you can change the SPIBLK_NAME or SPICHR_NAME to NULL.
*/
spinorParam->flash_mtd = (struct MtdDev *)spinorMtd;
spinorParam->flash_ops = GetDevSpinorOps(); //获取块设备操作方法
spinorParam->char_ops = GetMtdCharFops(); //获取字符设备操作方法
spinorParam->blockname = SPIBLK_NAME;
spinorParam->charname = SPICHR_NAME;
spinorParam->partition_head = g_spinorPartitionHead;
spinorParam->block_size = spinorMtd->eraseSize;//4K, 读/写/擦除 的最小单位
}
//反初始化 norflash 参数
static VOID MtdDeinitSpinorParam(VOID)
{
if (JffsLockDeinit != NULL) {
JffsLockDeinit();
}
}
//初始化 nor flash 参数
static partition_param *MtdInitSpinorParam(partition_param *spinorParam)
{
struct MtdDev *spinorMtd = GetMtd("spinor");
if (spinorMtd == NULL) {
return NULL;
}
if (spinorParam == NULL) {
if (JffsLockInit != NULL) {
if (JffsLockInit() != 0) { /* create jffs2 lock failed */
return NULL;
}
}
spinorParam = (partition_param *)zalloc(sizeof(partition_param));
if (spinorParam == NULL) {
PRINT_ERR("%s, partition_param malloc failed\n", __FUNCTION__);
MtdDeinitSpinorParam();
return NULL;
}
g_spinorPartitionHead = (mtd_partition *)zalloc(sizeof(mtd_partition));
if (g_spinorPartitionHead == NULL) {
PRINT_ERR("%s, mtd_partition malloc failed\n", __FUNCTION__);
MtdDeinitSpinorParam();
free(spinorParam);
return NULL;
}
MtdNorParamAssign(spinorParam, spinorMtd);
}
return spinorParam;
}
/* According the flash-type to init the param of the partition. *///根据flash类型初始化分区的参数
static INT32 MtdInitFsparParam(const CHAR *type, partition_param **fsparParam)
{
if (strcmp(type, "spinor") == 0) {
g_spinorPartParam = MtdInitSpinorParam(g_spinorPartParam);
*fsparParam = g_spinorPartParam;
} else {
return -EINVAL;
}
if ((*fsparParam == NULL) || ((VOID *)((*fsparParam)->flash_mtd) == NULL)) {
return -ENODEV;
}
return ENOERR;
}
/* According the flash-type to deinit the param of the partition. */
static INT32 MtdDeinitFsparParam(const CHAR *type)
{
if (strcmp(type, "spinor") == 0) {
MtdDeinitSpinorParam();
g_spinorPartParam = NULL;
} else {
return -EINVAL;
}
return ENOERR;
}
//分区参数检查
static INT32 AddParamCheck(UINT32 startAddr,
const partition_param *param,
UINT32 partitionNum,
UINT32 length)
{
UINT32 startBlk, endBlk;
mtd_partition *node = NULL;
if ((param->blockname == NULL) && (param->charname == NULL)) {
return -EINVAL;
}
if ((length == 0) || (length < param->block_size) ||
(((UINT64)(startAddr) + length) > param->flash_mtd->size)) {
return -EINVAL;
}
ALIGN_ASSIGN(length, startAddr, startBlk, endBlk, param->block_size);
if (startBlk > endBlk) {
return -EINVAL;
}
LOS_DL_LIST_FOR_EACH_ENTRY(node, &param->partition_head->node_info, mtd_partition, node_info) {
if ((node->start_block != 0) && (node->patitionnum == partitionNum)) {
return -EINVAL;
}
if ((startBlk > node->end_block) || (endBlk < node->start_block)) {
continue;
}
return -EINVAL;
}
return ENOERR;
}
//注册块设备,此函数之后设备将支持VFS访问
static INT32 BlockDriverRegisterOperate(mtd_partition *newNode,
const partition_param *param,
UINT32 partitionNum)
{
INT32 ret;
size_t driverNameSize;
if (param->blockname != NULL) {
driverNameSize = strlen(param->blockname) + DRIVER_NAME_ADD_SIZE;
newNode->blockdriver_name = (CHAR *)malloc(driverNameSize);
if (newNode->blockdriver_name == NULL) {
return -ENOMEM;
}
ret = snprintf_s(newNode->blockdriver_name, driverNameSize,
driverNameSize - 1, "%s%u", param->blockname, partitionNum);
if (ret < 0) {
free(newNode->blockdriver_name);
newNode->blockdriver_name = NULL;
return -ENAMETOOLONG;
}
//在伪文件系统中注册块驱动程序,生成设备结点 inode
ret = register_blockdriver(newNode->blockdriver_name, param->flash_ops,
RWE_RW_RW, newNode);
if (ret) {
free(newNode->blockdriver_name);
newNode->blockdriver_name = NULL;
PRINT_ERR("register blkdev partion error\n");
return ret;
}
} else {
newNode->blockdriver_name = NULL;
}
return ENOERR;
}
//注册字符设备,,此函数之后设备将支持VFS访问
static INT32 CharDriverRegisterOperate(mtd_partition *newNode,
const partition_param *param,
UINT32 partitionNum)
{
INT32 ret;
size_t driverNameSize;
if (param->charname != NULL) {
driverNameSize = strlen(param->charname) + DRIVER_NAME_ADD_SIZE;
newNode->chardriver_name = (CHAR *)malloc(driverNameSize);
if (newNode->chardriver_name == NULL) {
return -ENOMEM;
}
ret = snprintf_s(newNode->chardriver_name, driverNameSize,
driverNameSize - 1, "%s%u", param->charname, partitionNum);
if (ret < 0) {
free(newNode->chardriver_name);
newNode->chardriver_name = NULL;
return -ENAMETOOLONG;
}
//在伪文件系统中注册字符设备驱动程序,生成设备结点 inode
ret = register_driver(newNode->chardriver_name, param->char_ops, RWE_RW_RW, newNode);
if (ret) {
PRINT_ERR("register chardev partion error\n");
free(newNode->chardriver_name);
newNode->chardriver_name = NULL;
return ret;
}
} else {
newNode->chardriver_name = NULL;
}
return ENOERR;
}
//注销块设备驱动程序,从伪文件系统中删除“path”处的块驱动程序inode
static INT32 BlockDriverUnregister(mtd_partition *node)
{
INT32 ret;
if (node->blockdriver_name != NULL) {
ret = unregister_blockdriver(node->blockdriver_name);
if (ret == -EBUSY) {
PRINT_ERR("unregister blkdev partion error:%d\n", ret);
return ret;
}
free(node->blockdriver_name);
node->blockdriver_name = NULL;
}
return ENOERR;
}
//注销字符设备驱动程序,从伪文件系统中删除“path”处的字符驱动程序inode
static INT32 CharDriverUnregister(mtd_partition *node)
{
INT32 ret;
if (node->chardriver_name != NULL) {
ret = unregister_driver(node->chardriver_name);
if (ret == -EBUSY) {
PRINT_ERR("unregister chardev partion error:%d\n", ret);
return ret;
}
free(node->chardriver_name);
node->chardriver_name = NULL;
}
return ENOERR;
}
/*
* Attention: both startAddr and length should be aligned with block size.
* If not, the actual start address and length won't be what you expected.
*/ //参数必须对齐 块大小检查
INT32 add_mtd_partition(const CHAR *type, UINT32 startAddr,
UINT32 length, UINT32 partitionNum)
{
INT32 ret;
mtd_partition *newNode = NULL;
partition_param *param = NULL;
if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) || (type == NULL)) {
return -EINVAL;
}
ret = pthread_mutex_lock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
ret = MtdInitFsparParam(type, &param);
if (ret != ENOERR) {
goto ERROR_OUT;
}
ret = AddParamCheck(startAddr, param, partitionNum, length);
if (ret != ENOERR) {
goto ERROR_OUT;
}
newNode = (mtd_partition *)zalloc(sizeof(mtd_partition));
if (newNode == NULL) {
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return -ENOMEM;
}
PAR_ASSIGNMENT(newNode, length, startAddr, partitionNum, param->flash_mtd, param->block_size);
//注册块设备驱动程序,支持VFS访问
ret = BlockDriverRegisterOperate(newNode, param, partitionNum);
if (ret) {
goto ERROR_OUT1;
}
ret = CharDriverRegisterOperate(newNode, param, partitionNum);
if (ret) {
goto ERROR_OUT2;
}
LOS_ListTailInsert(&param->partition_head->node_info, &newNode->node_info);
(VOID)LOS_MuxInit(&newNode->lock, NULL);
ret = pthread_mutex_unlock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
return ENOERR;
ERROR_OUT2:
(VOID)BlockDriverUnregister(newNode);
ERROR_OUT1:
free(newNode);
ERROR_OUT:
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
static INT32 DeleteParamCheck(UINT32 partitionNum,
const CHAR *type,
partition_param **param)
{
if (strcmp(type, "spinor") == 0) {
*param = g_spinorPartParam;
} else {
PRINT_ERR("type error \n");
return -EINVAL;
}
if ((partitionNum >= CONFIG_MTD_PATTITION_NUM) ||
((*param) == NULL) || ((*param)->flash_mtd == NULL)) {
return -EINVAL;
}
return ENOERR;
}
static INT32 DeletePartitionUnregister(mtd_partition *node)
{
INT32 ret;
ret = BlockDriverUnregister(node);
if (ret == -EBUSY) {
return ret;
}
ret = CharDriverUnregister(node);
if (ret == -EBUSY) {
return ret;
}
return ENOERR;
}
static INT32 OsNodeGet(mtd_partition **node, UINT32 partitionNum, const partition_param *param)
{
LOS_DL_LIST_FOR_EACH_ENTRY(*node, &param->partition_head->node_info, mtd_partition, node_info) {
if ((*node)->patitionnum == partitionNum) {
break;
}
}
if ((*node == NULL) || ((*node)->patitionnum != partitionNum) ||
((*node)->mountpoint_name != NULL)) {
return -EINVAL;
}
return ENOERR;
}
static INT32 OsResourceRelease(mtd_partition *node, const CHAR *type, partition_param *param)
{
(VOID)LOS_MuxDestroy(&node->lock);
LOS_ListDelete(&node->node_info);
(VOID)memset_s(node, sizeof(mtd_partition), 0, sizeof(mtd_partition));
free(node);
(VOID)FreeMtd(param->flash_mtd);
if (LOS_ListEmpty(&param->partition_head->node_info)) {
free(param->partition_head);
param->partition_head = NULL;
free(param);
if (MtdDeinitFsparParam(type) != ENOERR) {
return -EINVAL;
}
}
return ENOERR;
}
INT32 delete_mtd_partition(UINT32 partitionNum, const CHAR *type)
{
INT32 ret;
mtd_partition *node = NULL;
partition_param *param = NULL;
if (type == NULL) {
return -EINVAL;
}
ret = pthread_mutex_lock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex lock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
ret = DeleteParamCheck(partitionNum, type, &param);
if (ret) {
PRINT_ERR("delete_mtd_partition param invalid\n");
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = OsNodeGet(&node, partitionNum, param);
if (ret) {
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = DeletePartitionUnregister(node);
if (ret) {
PRINT_ERR("DeletePartitionUnregister error:%d\n", ret);
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = OsResourceRelease(node, type, param);
if (ret) {
PRINT_ERR("DeletePartitionUnregister error:%d\n", ret);
(VOID)pthread_mutex_unlock(&g_mtdPartitionLock);
return ret;
}
ret = pthread_mutex_unlock(&g_mtdPartitionLock);
if (ret != ENOERR) {
PRINT_ERR("%s %d, mutex unlock failed, error:%d\n", __FUNCTION__, __LINE__, ret);
}
return ENOERR;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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_base.h"
#include "los_typedef.h"
#include "string.h"
#ifdef LOSCFG_PLATFORM_HI3518EV300
#include "mtd_partition.h"
#endif
#ifdef LOSCFG_DRIVERS_MMC
#include "mmc/block.h"
#include "disk.h"
#include "ff.h"
#endif
#include "sys/mount.h"
#include "inode/inode.h"
#ifdef LOSCFG_PLATFORM_ROOTFS
#include "los_rootfs.h"
#endif
#include "mtd_list.h"
#ifdef LOSCFG_PLATFORM_HI3518EV300
#define DEV_STORAGE_PATH "/dev/spinorblk2"
#define SECOND_MTD_PART_NUM 2
#define STORAGE_SIZE 0x100000
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#ifdef LOSCFG_PLATFORM_HI3516DV300
#define STORAGE_SIZE 0x3200000
STATIC los_disk *g_emmcDisk = NULL;
#endif
#ifndef LOSCFG_SECURITY_BOOT
STATIC INT32 g_alignSize = 0;
#endif
#define VFAT_STORAGE_MOUNT_DIR_MODE 777
#define DEFAULT_STORAGE_MOUNT_DIR_MODE 755
#ifdef LOSCFG_DRIVERS_MMC
los_disk *GetMmcDisk(UINT8 type)
{
const CHAR *mmcDevHead = "/dev/mmcblk";
for (INT32 diskId = 0; diskId < SYS_MAX_DISK; diskId++) {
los_disk *disk = get_disk(diskId);
if (disk == NULL) {
continue;
} else if (disk->disk_name == NULL) {
continue;
} else if (strncmp(disk->disk_name, mmcDevHead, strlen(mmcDevHead))) {
continue;
} else {
if (disk->type == type) {
return disk;
}
}
}
PRINT_ERR("Cannot find the mmc disk!\n");
return NULL;
}
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
STATIC const CHAR *AddEmmcRootfsPart(INT32 rootAddr, INT32 rootSize)
{
INT32 ret;
struct mmc_block *block = g_emmcDisk->dev->i_private;
const char *node_name = mmc_block_get_node_name(block);
if (los_disk_deinit(g_emmcDisk->disk_id) != ENOERR) {
PRINT_ERR("Failed to deinit emmc disk!\n");
return NULL;
}
struct disk_divide_info *emmc = get_emmc();
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 NULL;
} else {
UINT64 storageStartCnt = (rootAddr + rootSize) / EMMC_SEC_SIZE;
UINT64 storageSizeCnt = STORAGE_SIZE / EMMC_SEC_SIZE;
UINT64 userdataStartCnt = storageStartCnt + storageSizeCnt;
UINT64 userdataSizeCnt = g_emmcDisk->sector_count - userdataStartCnt;
ret = add_mmc_partition(emmc, storageStartCnt, storageSizeCnt);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add mmc storage partition!\n");
}
ret = add_mmc_partition(emmc, userdataStartCnt, userdataSizeCnt);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add mmc userdata partition!\n");
}
LOS_Msleep(10); /* 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 NULL;
}
if (los_disk_init(node_name, mmc_block_get_bops(block), (void *)block, diskId, emmc) != ENOERR) {
PRINT_ERR("Failed to init emmc disk!\n");
return NULL;
}
return node_name;
}
}
#endif
STATIC const CHAR *GetDevName(const CHAR *rootType, INT32 rootAddr, INT32 rootSize)
{
const CHAR *rootDev = NULL;
#ifdef LOSCFG_PLATFORM_HI3518EV300
INT32 ret;
if (strcmp(rootType, "flash") == 0) {
ret = add_mtd_partition(FLASH_TYPE, rootAddr, rootSize, 0);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add spinor root partition!\n");
} else {
rootDev = FLASH_DEV_NAME;
ret = add_mtd_partition(FLASH_TYPE, (rootAddr + rootSize), STORAGE_SIZE, SECOND_MTD_PART_NUM);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add spinor storage partition!\n");
}
}
} else
#endif
#ifdef LOSCFG_DRIVERS_USB_MASS_STORAGE
if (strcmp(rootType, "usb") == 0) {
rootDev = "/dev/sda";
} else
#endif
#ifdef LOSCFG_DRIVERS_SD
if (strcmp(rootType, "sdcard") == 0) {
los_disk *sdDisk = GetMmcDisk(OTHERS);
if (sdDisk == NULL) {
PRINT_ERR("Get sdcard failed!\n");
} else {
rootDev = sdDisk->disk_name;
}
} else
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
if (strcmp(rootType, "emmc") == 0) {
rootDev = AddEmmcRootfsPart(rootAddr, rootSize);
} else
#endif
{
PRINT_ERR("Failed to find root dev type: %s\n", rootType);
}
return rootDev;
}
#ifndef LOSCFG_SECURITY_BOOT
STATIC INT32 GetArgs(CHAR **args)
{
INT32 ret;
INT32 i;
INT32 len = 0;
CHAR *cmdLine = NULL;
CHAR *tmp = NULL;
const CHAR *bootargName = "bootargs=";
cmdLine = (CHAR *)malloc(COMMAND_LINE_SIZE);
if (cmdLine == NULL) {
PRINT_ERR("Malloc cmdLine space error!\n");
return LOS_NOK;
}
#ifdef LOSCFG_PLATFORM_HI3516DV300
g_emmcDisk = GetMmcDisk(EMMC);
if (g_emmcDisk == NULL) {
PRINT_ERR("Get EMMC disk failed!\n");
goto ERROUT;
}
ret = los_disk_read(g_emmcDisk->disk_id, cmdLine, COMMAND_LINE_ADDR / EMMC_SEC_SIZE,
COMMAND_LINE_SIZE / EMMC_SEC_SIZE);
if (ret != 0) {
PRINT_ERR("Read EMMC command line failed!\n");
goto ERROUT;
}
g_alignSize = EMMC_SEC_SIZE;
#endif
#ifdef LOSCFG_PLATFORM_HI3518EV300
struct MtdDev *mtd = GetMtd(FLASH_TYPE);//获取flash设备描述符
if (mtd == NULL) {
PRINT_ERR("Get spinor mtd failed!\n");
goto ERROUT;
}
g_alignSize = mtd->eraseSize;
ret = mtd->read(mtd, COMMAND_LINE_ADDR, COMMAND_LINE_SIZE, cmdLine);
if (ret != COMMAND_LINE_SIZE) {
PRINT_ERR("Read spinor command line failed!\n");
goto ERROUT;
}
#endif
for (i = 0; i < COMMAND_LINE_SIZE; i += len + 1) {
len = strlen(cmdLine + i);
tmp = strstr(cmdLine + i, bootargName);
if (tmp != NULL) {
*args = strdup(tmp + strlen(bootargName));
if (*args == NULL) {
goto ERROUT;
}
free(cmdLine);
return LOS_OK;
}
}
PRINT_ERR("Cannot find bootargs!\n");
ERROUT:
free(cmdLine);
return LOS_NOK;
}
STATIC INT32 MatchRootPos(CHAR *p, const CHAR *rootInfoName, INT32 *rootInfo)
{
UINT32 offset;
CHAR *value = NULL;
if (strncmp(p, rootInfoName, strlen(rootInfoName)) == 0) {
value = p + strlen(rootInfoName);
offset = strspn(value, DEC_NUMBER_STRING);
if (strcmp(p + strlen(p) - 1, "M") == 0) {
if ((offset < (strlen(value) - 1)) || (sscanf_s(value, "%d", rootInfo) <= 0)) {
goto ERROUT;
}
*rootInfo = *rootInfo * BYTES_PER_MBYTE;
} else if (strcmp(p + strlen(p) - 1, "K") == 0) {
if ((offset < (strlen(value) - 1)) || (sscanf_s(value, "%d", rootInfo) <= 0)) {
goto ERROUT;
}
*rootInfo = *rootInfo * BYTES_PER_KBYTE;
} else if (sscanf_s(value, "0x%x", rootInfo) > 0) {
value += strlen("0x");
if (strspn(value, HEX_NUMBER_STRING) < strlen(value)) {
goto ERROUT;
}
} else {
goto ERROUT;
}
}
if ((*rootInfo >= 0) && (g_alignSize != 0) && ((UINT32)(*rootInfo) & (UINT32)(g_alignSize - 1))) {
PRINT_ERR("The bootarg \"%s\" will be 0x%x aligned!\n", p, g_alignSize);
}
return LOS_OK;
ERROUT:
PRINT_ERR("Invalid bootarg \"%s\"!\n", p);
return LOS_NOK;
}
STATIC INT32 MatchRootInfo(CHAR *p, CHAR **rootType, CHAR **fsType, INT32 *rootAddr, INT32 *rootSize)
{
const CHAR *rootName = "root=";
const CHAR *fsName = "fstype=";
const CHAR *rootAddrName = "rootaddr=";
const CHAR *rootSizeName = "rootsize=";
if ((*rootType == NULL) && (strncmp(p, rootName, strlen(rootName)) == 0)) {
*rootType = strdup(p + strlen(rootName));
if (*rootType == NULL) {
return LOS_NOK;
}
return LOS_OK;
}
if ((*fsType == NULL) && (strncmp(p, fsName, strlen(fsName)) == 0)) {
*fsType = strdup(p + strlen(fsName));
if (*fsType == NULL) {
return LOS_NOK;
}
return LOS_OK;
}
if (*rootAddr < 0) {
if (MatchRootPos(p, rootAddrName, rootAddr) != LOS_OK) {
return LOS_NOK;
} else if (*rootAddr >= 0) {
return LOS_OK;
}
}
if (*rootSize < 0) {
if (MatchRootPos(p, rootSizeName, rootSize) != LOS_OK) {
return LOS_NOK;
}
}
return LOS_OK;
}
STATIC INT32 GetRootType(CHAR **rootType, CHAR **fsType, INT32 *rootAddr, INT32 *rootSize)
{
CHAR *args = NULL;
CHAR *argsBak = NULL;
CHAR *p = NULL;
if (GetArgs(&args) != LOS_OK) {
PRINT_ERR("Cannot get bootargs!\n");
return LOS_NOK;
}
argsBak = args;
p = strsep(&args, " ");
while (p != NULL) {
if (MatchRootInfo(p, rootType, fsType, rootAddr, rootSize) != LOS_OK) {
goto ERROUT;
}
p = strsep(&args, " ");
}
if ((*fsType != NULL) && (*rootType != NULL)) {
free(argsBak);
return LOS_OK;
}
ERROUT:
PRINT_ERR("Invalid rootfs information!\n");
if (*rootType != NULL) {
free(*rootType);
*rootType = NULL;
}
if (*fsType != NULL) {
free(*fsType);
*fsType = NULL;
}
free(argsBak);
return LOS_NOK;
}
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
STATIC VOID OsMountUserdata(const CHAR *fsType)//mount emmc /userdata
{
INT32 ret;
INT32 err;
const CHAR *userdataDir = "/userdata";
ret = mkdir(userdataDir, VFAT_STORAGE_MOUNT_DIR_MODE);
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to reserve inode /userdata, errno %d: %s\n", err, strerror(err));
return;
}
CHAR emmcUserdataDev[DISK_NAME] = {0};
if (snprintf_s(emmcUserdataDev, sizeof(emmcUserdataDev), sizeof(emmcUserdataDev) - 1,
"%s%s", g_emmcDisk->disk_name, "p2") < 0) {
PRINT_ERR("Failed to get emmc userdata dev name!\n");
return;
}
ret = mount(emmcUserdataDev, userdataDir, fsType, 0, "umask=000");
if (ret == LOS_OK) {
return;
}
err = get_errno();
if (err == ENOENT) {
ret = format(emmcUserdataDev, 0, FM_FAT32);
if (ret != LOS_OK) {
PRINT_ERR("Failed to format %s\n", emmcUserdataDev);
return;
}
ret = mount(emmcUserdataDev, userdataDir, fsType, 0, "umask=000");
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount /userdata, errno %d: %s\n", err, strerror(err));
}
} else {
PRINT_ERR("Failed to mount /userdata, errno %d: %s\n", err, strerror(err));
}
return;
}
#endif
STATIC INT32 OsMountRootfsAndUserfs(const CHAR *rootDev, const CHAR *fsType)
{
INT32 ret;
INT32 err;
if (strcmp(fsType, "vfat") == 0) { //vfat 格式处理 VFAT (Virtual File Allocation Table) 虚拟文件分配表
ret = mount(rootDev, "/", fsType, MS_RDONLY, NULL);// mount /
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount vfat rootfs, errno %d: %s\n", err, strerror(err));
return ret;
}
g_root_inode->i_mode |= S_IRWXU | S_IRWXG | S_IRWXO; // 777
#ifdef LOSCFG_PLATFORM_HI3516DV300
ret = mkdir("/storage", VFAT_STORAGE_MOUNT_DIR_MODE); //根目录下创建storage目录
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to reserve inode /storage, errno %d: %s\n", err, strerror(err));
} else {
CHAR emmcStorageDev[DISK_NAME] = {0};
if (snprintf_s(emmcStorageDev, sizeof(emmcStorageDev), sizeof(emmcStorageDev) - 1,
"%s%s", g_emmcDisk->disk_name, "p1") < 0) {
PRINT_ERR("Failed to get emmc storage dev name!\n");
} else {
ret = mount(emmcStorageDev, "/storage", fsType, 0, "umask=000");//挂载storage目录
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount /storage, errno %d: %s\n", err, strerror(err));
}
}
}
OsMountUserdata(fsType);
#endif
} else { //非 vfat格式
ret = mount(rootDev, "/", fsType, MS_RDONLY, NULL);
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount rootfs, errno %d: %s\n", err, strerror(err));
return ret;
}
#ifdef LOSCFG_PLATFORM_HI3518EV300
ret = mkdir("/storage", DEFAULT_STORAGE_MOUNT_DIR_MODE);
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to reserve inode /storage, errno %d: %s\n", err, strerror(err));
} else {
ret = mount(DEV_STORAGE_PATH, "/storage", fsType, 0, NULL);//挂载storage目录
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount /storage, errno %d: %s\n", err, strerror(err));
}
}
#endif
}
return LOS_OK;
}
/******************************************************
挂载根文件系统 分两个阶段
1.文件系统提供一个作为初始安装点的空目录
2.内核在空目录上安装根文件系统
******************************************************/
INT32 OsMountRootfs(VOID)
{
INT32 ret = LOS_OK;
INT32 err;
INT32 rootAddr = -1;
INT32 rootSize = -1;
CHAR *rootType = NULL;
CHAR *fsType = NULL;
const CHAR *rootDev = NULL;
#ifdef LOSCFG_SECURITY_BOOT
rootType = strdup(ROOTFS_ROOT_TYPE);
fsType = strdup(ROOTFS_FS_TYPE);
rootAddr = ROOTFS_FLASH_ADDR;
rootSize = ROOTFS_FLASH_SIZE;
#else
ret = GetRootType(&rootType, &fsType, &rootAddr, &rootSize);
if (ret != LOS_OK) {
return ret;
}
rootAddr = (rootAddr >= 0) ? rootAddr : ROOTFS_FLASH_ADDR;
rootSize = (rootSize >= 0) ? rootSize : ROOTFS_FLASH_SIZE;
#endif
rootDev = GetDevName(rootType, rootAddr, rootSize);//获取根设备 /dev/***
if (rootDev != NULL) {
ret = OsMountRootfsAndUserfs(rootDev, fsType);//将根设备挂到 /下,
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount rootfs, errno %d: %s\n", err, strerror(err));
}
}
free(rootType);
free(fsType);
return ret;
}
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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_base.h"
#include "los_typedef.h"
#include "string.h"
#ifdef LOSCFG_PLATFORM_HI3518EV300
#include "mtd_partition.h"
#endif
#ifdef LOSCFG_DRIVERS_MMC
#include "mmc/block.h"
#include "disk.h"
#include "ff.h"
#endif
#include "sys/mount.h"
#include "inode/inode.h"
#ifdef LOSCFG_PLATFORM_ROOTFS
#include "los_rootfs.h"
#endif
#include "mtd_list.h"
#ifdef LOSCFG_PLATFORM_HI3518EV300
#define DEV_STORAGE_PATH "/dev/spinorblk2"
#define SECOND_MTD_PART_NUM 2
#define STORAGE_SIZE 0x100000
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#ifdef LOSCFG_PLATFORM_HI3516DV300
#define STORAGE_SIZE 0x3200000
STATIC los_disk *g_emmcDisk = NULL;
#endif
#ifndef LOSCFG_SECURITY_BOOT
STATIC INT32 g_alignSize = 0;
#endif
#define VFAT_STORAGE_MOUNT_DIR_MODE 777
#define DEFAULT_STORAGE_MOUNT_DIR_MODE 755
#ifdef LOSCFG_DRIVERS_MMC
los_disk *GetMmcDisk(UINT8 type)
{
const CHAR *mmcDevHead = "/dev/mmcblk";
for (INT32 diskId = 0; diskId < SYS_MAX_DISK; diskId++) {
los_disk *disk = get_disk(diskId);
if (disk == NULL) {
continue;
} else if (disk->disk_name == NULL) {
continue;
} else if (strncmp(disk->disk_name, mmcDevHead, strlen(mmcDevHead))) {
continue;
} else {
if (disk->type == type) {
return disk;
}
}
}
PRINT_ERR("Cannot find the mmc disk!\n");
return NULL;
}
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
STATIC const CHAR *AddEmmcRootfsPart(INT32 rootAddr, INT32 rootSize)//在EMMC介质上增加一个根文件系统分区
{
INT32 ret;
struct mmc_block *block = g_emmcDisk->dev->i_private;
const char *node_name = mmc_block_get_node_name(block);
if (los_disk_deinit(g_emmcDisk->disk_id) != ENOERR) {
PRINT_ERR("Failed to deinit emmc disk!\n");
return NULL;
}
struct disk_divide_info *emmc = get_emmc();//获取emmc,将完善其分区信息
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 NULL;
} else {
UINT64 storageStartCnt = (rootAddr + rootSize) / EMMC_SEC_SIZE;
UINT64 storageSizeCnt = STORAGE_SIZE / EMMC_SEC_SIZE;
UINT64 userdataStartCnt = storageStartCnt + storageSizeCnt;
UINT64 userdataSizeCnt = g_emmcDisk->sector_count - userdataStartCnt;
ret = add_mmc_partition(emmc, storageStartCnt, storageSizeCnt);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add mmc storage partition!\n");
}
ret = add_mmc_partition(emmc, userdataStartCnt, userdataSizeCnt);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add mmc userdata partition!\n");
}
LOS_Msleep(10); /* 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 NULL;
}
if (los_disk_init(node_name, mmc_block_get_bops(block), (void *)block, diskId, emmc) != ENOERR) {
PRINT_ERR("Failed to init emmc disk!\n");
return NULL;
}
return node_name;
}
}
#endif
//系统可以有多个根文件系统并存,可放在 USB,SD卡,flash上
STATIC const CHAR *GetDevName(const CHAR *rootType, INT32 rootAddr, INT32 rootSize)
{
const CHAR *rootDev = NULL;
#ifdef LOSCFG_PLATFORM_HI3518EV300
INT32 ret;
if (strcmp(rootType, "flash") == 0) {
ret = add_mtd_partition(FLASH_TYPE, rootAddr, rootSize, 0);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add spinor root partition!\n");
} else {
rootDev = FLASH_DEV_NAME;
ret = add_mtd_partition(FLASH_TYPE, (rootAddr + rootSize), STORAGE_SIZE, SECOND_MTD_PART_NUM);
if (ret != LOS_OK) {
PRINT_ERR("Failed to add spinor storage partition!\n");
}
}
} else
#endif
#ifdef LOSCFG_DRIVERS_USB_MASS_STORAGE
if (strcmp(rootType, "usb") == 0) {
rootDev = "/dev/sda";
} else
#endif
#ifdef LOSCFG_DRIVERS_SD
if (strcmp(rootType, "sdcard") == 0) {
los_disk *sdDisk = GetMmcDisk(OTHERS);
if (sdDisk == NULL) {
PRINT_ERR("Get sdcard failed!\n");
} else {
rootDev = sdDisk->disk_name;
}
} else
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
if (strcmp(rootType, "emmc") == 0) {
rootDev = AddEmmcRootfsPart(rootAddr, rootSize);
} else
#endif
{
PRINT_ERR("Failed to find root dev type: %s\n", rootType);
}
return rootDev;
}
#ifndef LOSCFG_SECURITY_BOOT
STATIC INT32 GetArgs(CHAR **args)
{
INT32 ret;
INT32 i;
INT32 len = 0;
CHAR *cmdLine = NULL;
CHAR *tmp = NULL;
const CHAR *bootargName = "bootargs=";
cmdLine = (CHAR *)malloc(COMMAND_LINE_SIZE);
if (cmdLine == NULL) {
PRINT_ERR("Malloc cmdLine space error!\n");
return LOS_NOK;
}
#ifdef LOSCFG_PLATFORM_HI3516DV300
g_emmcDisk = GetMmcDisk(EMMC);
if (g_emmcDisk == NULL) {
PRINT_ERR("Get EMMC disk failed!\n");
goto ERROUT;
}
ret = los_disk_read(g_emmcDisk->disk_id, cmdLine, COMMAND_LINE_ADDR / EMMC_SEC_SIZE,
COMMAND_LINE_SIZE / EMMC_SEC_SIZE);
if (ret != 0) {
PRINT_ERR("Read EMMC command line failed!\n");
goto ERROUT;
}
g_alignSize = EMMC_SEC_SIZE;
#endif
#ifdef LOSCFG_PLATFORM_HI3518EV300
struct MtdDev *mtd = GetMtd(FLASH_TYPE);//获取flash设备描述符
if (mtd == NULL) {
PRINT_ERR("Get spinor mtd failed!\n");
goto ERROUT;
}
g_alignSize = mtd->eraseSize;
ret = mtd->read(mtd, COMMAND_LINE_ADDR, COMMAND_LINE_SIZE, cmdLine);
if (ret != COMMAND_LINE_SIZE) {
PRINT_ERR("Read spinor command line failed!\n");
goto ERROUT;
}
#endif
for (i = 0; i < COMMAND_LINE_SIZE; i += len + 1) {
len = strlen(cmdLine + i);
tmp = strstr(cmdLine + i, bootargName);
if (tmp != NULL) {
*args = strdup(tmp + strlen(bootargName));
if (*args == NULL) {
goto ERROUT;
}
free(cmdLine);
return LOS_OK;
}
}
PRINT_ERR("Cannot find bootargs!\n");
ERROUT:
free(cmdLine);
return LOS_NOK;
}
STATIC INT32 MatchRootPos(CHAR *p, const CHAR *rootInfoName, INT32 *rootInfo)
{
UINT32 offset;
CHAR *value = NULL;
if (strncmp(p, rootInfoName, strlen(rootInfoName)) == 0) {
value = p + strlen(rootInfoName);
offset = strspn(value, DEC_NUMBER_STRING);
if (strcmp(p + strlen(p) - 1, "M") == 0) {
if ((offset < (strlen(value) - 1)) || (sscanf_s(value, "%d", rootInfo) <= 0)) {
goto ERROUT;
}
*rootInfo = *rootInfo * BYTES_PER_MBYTE;
} else if (strcmp(p + strlen(p) - 1, "K") == 0) {
if ((offset < (strlen(value) - 1)) || (sscanf_s(value, "%d", rootInfo) <= 0)) {
goto ERROUT;
}
*rootInfo = *rootInfo * BYTES_PER_KBYTE;
} else if (sscanf_s(value, "0x%x", rootInfo) > 0) {
value += strlen("0x");
if (strspn(value, HEX_NUMBER_STRING) < strlen(value)) {
goto ERROUT;
}
} else {
goto ERROUT;
}
}
if ((*rootInfo >= 0) && (g_alignSize != 0) && ((UINT32)(*rootInfo) & (UINT32)(g_alignSize - 1))) {
PRINT_ERR("The bootarg \"%s\" will be 0x%x aligned!\n", p, g_alignSize);
}
return LOS_OK;
ERROUT:
PRINT_ERR("Invalid bootarg \"%s\"!\n", p);
return LOS_NOK;
}
STATIC INT32 MatchRootInfo(CHAR *p, CHAR **rootType, CHAR **fsType, INT32 *rootAddr, INT32 *rootSize)
{
const CHAR *rootName = "root=";
const CHAR *fsName = "fstype=";
const CHAR *rootAddrName = "rootaddr=";
const CHAR *rootSizeName = "rootsize=";
if ((*rootType == NULL) && (strncmp(p, rootName, strlen(rootName)) == 0)) {
*rootType = strdup(p + strlen(rootName));
if (*rootType == NULL) {
return LOS_NOK;
}
return LOS_OK;
}
if ((*fsType == NULL) && (strncmp(p, fsName, strlen(fsName)) == 0)) {
*fsType = strdup(p + strlen(fsName));
if (*fsType == NULL) {
return LOS_NOK;
}
return LOS_OK;
}
if (*rootAddr < 0) {
if (MatchRootPos(p, rootAddrName, rootAddr) != LOS_OK) {
return LOS_NOK;
} else if (*rootAddr >= 0) {
return LOS_OK;
}
}
if (*rootSize < 0) {
if (MatchRootPos(p, rootSizeName, rootSize) != LOS_OK) {
return LOS_NOK;
}
}
return LOS_OK;
}
STATIC INT32 GetRootType(CHAR **rootType, CHAR **fsType, INT32 *rootAddr, INT32 *rootSize)
{
CHAR *args = NULL;
CHAR *argsBak = NULL;
CHAR *p = NULL;
if (GetArgs(&args) != LOS_OK) {
PRINT_ERR("Cannot get bootargs!\n");
return LOS_NOK;
}
argsBak = args;
p = strsep(&args, " ");
while (p != NULL) {
if (MatchRootInfo(p, rootType, fsType, rootAddr, rootSize) != LOS_OK) {
goto ERROUT;
}
p = strsep(&args, " ");
}
if ((*fsType != NULL) && (*rootType != NULL)) {
free(argsBak);
return LOS_OK;
}
ERROUT:
PRINT_ERR("Invalid rootfs information!\n");
if (*rootType != NULL) {
free(*rootType);
*rootType = NULL;
}
if (*fsType != NULL) {
free(*fsType);
*fsType = NULL;
}
free(argsBak);
return LOS_NOK;
}
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
STATIC VOID OsMountUserdata(const CHAR *fsType)//mount emmc /userdata
{
INT32 ret;
INT32 err;
const CHAR *userdataDir = "/userdata";
ret = mkdir(userdataDir, VFAT_STORAGE_MOUNT_DIR_MODE);
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to reserve inode /userdata, errno %d: %s\n", err, strerror(err));
return;
}
CHAR emmcUserdataDev[DISK_NAME] = {0};
if (snprintf_s(emmcUserdataDev, sizeof(emmcUserdataDev), sizeof(emmcUserdataDev) - 1,
"%s%s", g_emmcDisk->disk_name, "p2") < 0) {
PRINT_ERR("Failed to get emmc userdata dev name!\n");
return;
}
ret = mount(emmcUserdataDev, userdataDir, fsType, 0, "umask=000");
if (ret == LOS_OK) {
return;
}
err = get_errno();
if (err == ENOENT) {
ret = format(emmcUserdataDev, 0, FM_FAT32);
if (ret != LOS_OK) {
PRINT_ERR("Failed to format %s\n", emmcUserdataDev);
return;
}
ret = mount(emmcUserdataDev, userdataDir, fsType, 0, "umask=000");
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount /userdata, errno %d: %s\n", err, strerror(err));
}
} else {
PRINT_ERR("Failed to mount /userdata, errno %d: %s\n", err, strerror(err));
}
return;
}
#endif
STATIC INT32 OsMountRootfsAndUserfs(const CHAR *rootDev, const CHAR *fsType)
{
INT32 ret;
INT32 err;
if (strcmp(fsType, "vfat") == 0) { //vfat 格式处理 VFAT (Virtual File Allocation Table) 虚拟文件分配表
ret = mount(rootDev, "/", fsType, MS_RDONLY, NULL);// mount /
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount vfat rootfs, errno %d: %s\n", err, strerror(err));
return ret;
}
g_root_inode->i_mode |= S_IRWXU | S_IRWXG | S_IRWXO; // 777
#ifdef LOSCFG_PLATFORM_HI3516DV300
ret = mkdir("/storage", VFAT_STORAGE_MOUNT_DIR_MODE); //根目录下创建storage目录
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to reserve inode /storage, errno %d: %s\n", err, strerror(err));
} else {
CHAR emmcStorageDev[DISK_NAME] = {0};
if (snprintf_s(emmcStorageDev, sizeof(emmcStorageDev), sizeof(emmcStorageDev) - 1,
"%s%s", g_emmcDisk->disk_name, "p1") < 0) {
PRINT_ERR("Failed to get emmc storage dev name!\n");
} else {
ret = mount(emmcStorageDev, "/storage", fsType, 0, "umask=000");//挂载storage目录
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount /storage, errno %d: %s\n", err, strerror(err));
}
}
}
OsMountUserdata(fsType);//挂载用户数据
#endif
} else { //非 vfat格式
ret = mount(rootDev, "/", fsType, MS_RDONLY, NULL);
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount rootfs, errno %d: %s\n", err, strerror(err));
return ret;
}
#ifdef LOSCFG_PLATFORM_HI3518EV300
ret = mkdir("/storage", DEFAULT_STORAGE_MOUNT_DIR_MODE);
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to reserve inode /storage, errno %d: %s\n", err, strerror(err));
} else {
ret = mount(DEV_STORAGE_PATH, "/storage", fsType, 0, NULL);//挂载storage目录
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount /storage, errno %d: %s\n", err, strerror(err));
}
}
#endif
}
return LOS_OK;
}
/******************************************************
挂载根文件系统 分两个阶段
1.文件系统提供一个作为初始安装点的空目录
2.内核在空目录上安装根文件系统
******************************************************/
INT32 OsMountRootfs(VOID)
{
INT32 ret = LOS_OK;
INT32 err;
INT32 rootAddr = -1;
INT32 rootSize = -1;
CHAR *rootType = NULL;
CHAR *fsType = NULL;
const CHAR *rootDev = NULL;
#ifdef LOSCFG_SECURITY_BOOT
rootType = strdup(ROOTFS_ROOT_TYPE);
fsType = strdup(ROOTFS_FS_TYPE);
rootAddr = ROOTFS_FLASH_ADDR;
rootSize = ROOTFS_FLASH_SIZE;
#else
ret = GetRootType(&rootType, &fsType, &rootAddr, &rootSize);
if (ret != LOS_OK) {
return ret;
}
rootAddr = (rootAddr >= 0) ? rootAddr : ROOTFS_FLASH_ADDR;
rootSize = (rootSize >= 0) ? rootSize : ROOTFS_FLASH_SIZE;
#endif
rootDev = GetDevName(rootType, rootAddr, rootSize);//获取根设备 /dev/***
if (rootDev != NULL) {
ret = OsMountRootfsAndUserfs(rootDev, fsType);//将根设备挂到 /下,
if (ret != LOS_OK) {
err = get_errno();
PRINT_ERR("Failed to mount rootfs, errno %d: %s\n", err, strerror(err));
}
}
free(rootType);
free(fsType);
return ret;
}
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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.
*/
#ifndef _LOS_ROOTFS_H
#define _LOS_ROOTFS_H
#define BYTES_PER_MBYTE 0x100000 //1M = 1024 * 1024
#define BYTES_PER_KBYTE 0x400 //1K = 1024
#define COMMAND_LINE_ADDR 512 * BYTES_PER_KBYTE
#define COMMAND_LINE_SIZE 1024
#ifdef LOSCFG_PLATFORM_HI3518EV300
#define ROOTFS_ROOT_TYPE "flash" //根文件系统存放在哪种设备上,这里是flash
#define ROOTFS_FS_TYPE "jffs2" //3518 平台使用根文件系统的类型
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
#define ROOTFS_ROOT_TYPE "emmc" //eMMC=NAND闪存+闪存控制芯片+标准接口封装 https://blog.csdn.net/xjw1874/article/details/81505967
#define ROOTFS_FS_TYPE "vfat" //3516 平台使用根文件系统的类型
#endif
#ifdef LOSCFG_TEE_ENABLE
#define ROOTFS_FLASH_ADDR 0x600000
#define ROOTFS_FLASH_SIZE 0x800000
#else
#define ROOTFS_FLASH_ADDR 0x400000
#define ROOTFS_FLASH_SIZE 0xa00000
#endif
#define FLASH_TYPE "spinor" //flash类型
#define FLASH_DEV_NAME "/dev/spinorblk0" //根文件系统路径
//扇区是对硬盘而言,而块是对文件系统而言
#define EMMC_SEC_SIZE 512 //扇区大小,按512个字节,按扇区对齐
#define DEC_NUMBER_STRING "0123456789"
#define HEX_NUMBER_STRING "0123456789abcdefABCDEF"
INT32 OsMountRootfs(VOID);
#endif /* _LOS_ROOTFS_H */
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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.
*/
#ifndef _LOS_ROOTFS_H
#define _LOS_ROOTFS_H
/**********************************************
rootfs之所以存在,是因为需要在VFS机制下给系统提供最原始的挂载点
https://blog.csdn.net/tankai19880619/article/details/12093239
与linux一样,在鸿蒙内核一切皆文件:普通文件、目录、字符设备、块设备、套接字
等都以文件被对待;他们具体的类型及其操作不同,但需要向上层提供统一的操作接口。
虚拟文件系统VFS就是内核中的一个软件层,向上给用户空间程序提供文件系统操作接口;
向下允许不同的文件系统共存。所以,所有实际文件系统都必须实现VFS的结构封装。
系统中任何文件系统的挂载必须满足两个条件:挂载点和文件系统。
rootfs是基于内存的文件系统,所有操作都在内存中完成;也没有实际的存储设备,所以不需要设备驱动程序的参与.
只在启动阶段使用rootfs文件系统,当磁盘驱动程序和磁盘文件系统成功加载后,系统会将系统根目录从rootfs切换
到磁盘上的具体文件系统。
rootfs的特点:
1.它是系统自己创建并加载的第一个文件系统;
2.该文件系统的挂载点就是它自己的根目录项对象;
3.该文件系统仅仅存在于内存中。
VFS是一种机制、是每一种文件系统都必须按照这个机制去实现的一种规范;
而rootfs仅仅是符合VFS规范的而且又具有如上3个特点的一个文件系统。
**********************************************/
#define BYTES_PER_MBYTE 0x100000 //1M = 1024 * 1024
#define BYTES_PER_KBYTE 0x400 //1K = 1024
#define COMMAND_LINE_ADDR 512 * BYTES_PER_KBYTE
#define COMMAND_LINE_SIZE 1024
#ifdef LOSCFG_PLATFORM_HI3518EV300
#define ROOTFS_ROOT_TYPE "flash" //根文件系统存放在nor flash上
#define ROOTFS_FS_TYPE "jffs2" //Journalling Flash File System(闪存设备日志型文件系统,JFFS),一般用于nor flash的文件系统
#endif
#ifdef LOSCFG_PLATFORM_HI3516DV300
#define ROOTFS_ROOT_TYPE "emmc" //eMMC=NAND闪存+闪存控制芯片+标准接口封装 https://blog.csdn.net/xjw1874/article/details/81505967
#define ROOTFS_FS_TYPE "vfat" //即FAT32,采用32位的文件分配表,支持最大分区128GB,最大文件4GB
#endif
#ifdef LOSCFG_TEE_ENABLE //TEE(Trust Execution Environment),可信执行环境,和REE(Rich Execution Environment)相对应
#define ROOTFS_FLASH_ADDR 0x600000
#define ROOTFS_FLASH_SIZE 0x800000
#else
#define ROOTFS_FLASH_ADDR 0x400000 //根文件系统地址
#define ROOTFS_FLASH_SIZE 0xa00000 //根文件系统大小 10M
#endif
#define FLASH_TYPE "spinor" //flash类型
#define FLASH_DEV_NAME "/dev/spinorblk0" //根文件系统路径
//扇区是对硬盘而言,而块是对文件系统而言
#define EMMC_SEC_SIZE 512 //扇区大小,按512个字节,按扇区对齐
#define DEC_NUMBER_STRING "0123456789"
#define HEX_NUMBER_STRING "0123456789abcdefABCDEF"
INT32 OsMountRootfs(VOID);
#endif /* _LOS_ROOTFS_H */
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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 "virtual_serial.h"
#include "fcntl.h"
#ifdef LOSCFG_FILE_MODE
#include "stdarg.h"
#endif
#ifdef LOSCFG_FS_VFS
#include "inode/inode.h"
#include "console.h"
#endif
#include "uart.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
STATIC volatile UINT32 g_serialType = 0;
STATIC struct file g_serialFilep;
UINT32 SerialTypeGet(VOID)
{
return g_serialType;
}
STATIC VOID SerialTypeSet(const CHAR *deviceName)
{
if (!strncmp(deviceName, SERIAL_UARTDEV, strlen(SERIAL_UARTDEV))) {
g_serialType = SERIAL_TYPE_UART_DEV;
} else if (!strncmp(deviceName, SERIAL_TTYGS0, strlen(SERIAL_TTYGS0))) {
g_serialType = SERIAL_TYPE_USBTTY_DEV;
}
}
STATIC INT32 SerialOpen(struct file *filep)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = EINVAL;
goto ERROUT;
}
ret = FilepOpen(privFilep, fileOps);
if (ret < 0) {
ret = EPERM;
goto ERROUT;
}
if (g_serialType == SERIAL_TYPE_UART_DEV) {
HalIrqUnmask(NUM_HAL_INTERRUPT_UART);
}
return ENOERR;
ERROUT:
set_errno(ret);
return VFS_ERROR;
}
STATIC INT32 SerialClose(struct file *filep)
{
(VOID)filep;
if (g_serialType == SERIAL_TYPE_UART_DEV) {
HalIrqMask(NUM_HAL_INTERRUPT_UART);
}
#if defined(LOSCFG_DRIVERS_USB_SERIAL_GADGET) || defined(LOSCFG_DRIVERS_USB_ETH_SER_GADGET)
else if (g_serialType == SERIAL_TYPE_USBTTY_DEV) {
userial_mask_set(0);
}
#endif
return ENOERR;
}
STATIC ssize_t SerialRead(struct file *filep, CHAR *buffer, size_t bufLen)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepRead(privFilep, fileOps, buffer, bufLen);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
/* Note: do not add print function in this module! */
STATIC ssize_t SerialWrite(FAR struct file *filep, FAR const CHAR *buffer, size_t bufLen)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepWrite(privFilep, fileOps, buffer, bufLen);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
STATIC INT32 SerialIoctl(struct file *filep, INT32 cmd, unsigned long arg)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepIoctl(privFilep, fileOps, cmd, arg);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
STATIC INT32 SerialPoll(struct file *filep, poll_table *fds)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepPoll(privFilep, fileOps, fds);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
//实现VFS接口函数,对串行设备进行操作
STATIC const struct file_operations_vfs g_serialDevOps = {
SerialOpen, /* open */
SerialClose, /* close */
SerialRead, /* read */
SerialWrite,
NULL,
SerialIoctl,
NULL,
#ifndef CONFIG_DISABLE_POLL
SerialPoll,
#endif
NULL,
};
INT32 virtual_serial_init(const CHAR *deviceName)
{
INT32 ret;
CHAR *fullpath = NULL;
struct inode *inode = NULL;
struct inode_search_s desc;
if (deviceName == NULL) {
ret = EINVAL;
goto ERROUT;
}
SerialTypeSet(deviceName);
ret = vfs_normalize_path(NULL, deviceName, &fullpath);
if (ret < 0) {
ret = EINVAL;
goto ERROUT;
}
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_find(&desc);
if (ret < 0) {
ret = EACCES;
goto ERROUT_WITH_FULLPATH;
}
inode = desc.node;
(VOID)memset_s(&g_serialFilep, sizeof(struct file), 0, sizeof(struct file));
g_serialFilep.f_oflags = O_RDWR;
g_serialFilep.f_inode = inode;
if (inode->u.i_ops->open != NULL) {
(VOID)inode->u.i_ops->open(&g_serialFilep);
} else {
ret = EFAULT;
inode_release(inode);
goto ERROUT_WITH_FULLPATH;
}
(VOID)register_driver(SERIAL, &g_serialDevOps, DEFFILEMODE, &g_serialFilep);
inode_release(inode);
free(fullpath);
return ENOERR;
ERROUT_WITH_FULLPATH:
free(fullpath);
ERROUT:
set_errno(ret);
return VFS_ERROR;
}
INT32 virtual_serial_deinit(VOID)
{
INT32 ret;
struct file *filep = NULL;
struct inode *inode = NULL;
CHAR *fullpath = NULL;
struct inode_search_s desc;
/* It's a process opposite virtual_serial_init */
ret = vfs_normalize_path(NULL, SERIAL, &fullpath);
if (ret < 0) {
ret = EINVAL;
goto ERROUT;
}
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_find(&desc);
if (ret < 0) {
ret = EACCES;
goto ERROUT_WITH_FULLPATH;
}
inode = desc.node;
filep = inode->i_private;
if ((filep != NULL) && (inode->u.i_ops != NULL)) {
(VOID)inode->u.i_ops->close(filep); /* close filep */
inode->i_private = NULL;
} else {
ret = EBADF;
goto ERROUT_WITH_INODE;
}
inode_release(inode);
free(fullpath);
(VOID)unregister_driver(SERIAL);
return ENOERR;
ERROUT_WITH_INODE:
inode_release(inode);
ERROUT_WITH_FULLPATH:
free(fullpath);
ERROUT:
set_errno(ret);
return VFS_ERROR;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, 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 "virtual_serial.h"
#include "fcntl.h"
#ifdef LOSCFG_FILE_MODE
#include "stdarg.h"
#endif
#ifdef LOSCFG_FS_VFS
#include "inode/inode.h"
#include "console.h"
#endif
#include "uart.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
STATIC volatile UINT32 g_serialType = 0;
STATIC struct file g_serialFilep;
UINT32 SerialTypeGet(VOID)
{
return g_serialType;
}
STATIC VOID SerialTypeSet(const CHAR *deviceName)
{
if (!strncmp(deviceName, SERIAL_UARTDEV, strlen(SERIAL_UARTDEV))) {
g_serialType = SERIAL_TYPE_UART_DEV;
} else if (!strncmp(deviceName, SERIAL_TTYGS0, strlen(SERIAL_TTYGS0))) {
g_serialType = SERIAL_TYPE_USBTTY_DEV;
}
}
STATIC INT32 SerialOpen(struct file *filep)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = EINVAL;
goto ERROUT;
}
ret = FilepOpen(privFilep, fileOps);
if (ret < 0) {
ret = EPERM;
goto ERROUT;
}
if (g_serialType == SERIAL_TYPE_UART_DEV) {
HalIrqUnmask(NUM_HAL_INTERRUPT_UART);
}
return ENOERR;
ERROUT:
set_errno(ret);
return VFS_ERROR;
}
STATIC INT32 SerialClose(struct file *filep)
{
(VOID)filep;
if (g_serialType == SERIAL_TYPE_UART_DEV) {
HalIrqMask(NUM_HAL_INTERRUPT_UART);
}
#if defined(LOSCFG_DRIVERS_USB_SERIAL_GADGET) || defined(LOSCFG_DRIVERS_USB_ETH_SER_GADGET)
else if (g_serialType == SERIAL_TYPE_USBTTY_DEV) {
userial_mask_set(0);
}
#endif
return ENOERR;
}
STATIC ssize_t SerialRead(struct file *filep, CHAR *buffer, size_t bufLen)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepRead(privFilep, fileOps, buffer, bufLen);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
/* Note: do not add print function in this module! */
STATIC ssize_t SerialWrite(FAR struct file *filep, FAR const CHAR *buffer, size_t bufLen)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepWrite(privFilep, fileOps, buffer, bufLen);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
STATIC INT32 SerialIoctl(struct file *filep, INT32 cmd, unsigned long arg)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepIoctl(privFilep, fileOps, cmd, arg);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
STATIC INT32 SerialPoll(struct file *filep, poll_table *fds)
{
INT32 ret;
struct file *privFilep = NULL;
const struct file_operations_vfs *fileOps = NULL;
ret = GetFilepOps(filep, &privFilep, &fileOps);
if (ret != ENOERR) {
ret = -EINVAL;
goto ERROUT;
}
ret = FilepPoll(privFilep, fileOps, fds);
if (ret < 0) {
goto ERROUT;
}
return ret;
ERROUT:
set_errno(-ret);
return VFS_ERROR;
}
//实现VFS接口函数,对串行设备进行操作
STATIC const struct file_operations_vfs g_serialDevOps = {
SerialOpen, /* open */
SerialClose, /* close */
SerialRead, /* read */
SerialWrite,
NULL,
SerialIoctl,//ioctl主要用read/write很难定义的情况,比如 光盘播放的快进,倒退等,ioctl命令和设备紧耦合.
NULL,
#ifndef CONFIG_DISABLE_POLL
SerialPoll,
#endif
NULL,
};
INT32 virtual_serial_init(const CHAR *deviceName)
{
INT32 ret;
CHAR *fullpath = NULL;
struct inode *inode = NULL;
struct inode_search_s desc;
if (deviceName == NULL) {
ret = EINVAL;
goto ERROUT;
}
SerialTypeSet(deviceName);
ret = vfs_normalize_path(NULL, deviceName, &fullpath);
if (ret < 0) {
ret = EINVAL;
goto ERROUT;
}
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_find(&desc);
if (ret < 0) {
ret = EACCES;
goto ERROUT_WITH_FULLPATH;
}
inode = desc.node;
(VOID)memset_s(&g_serialFilep, sizeof(struct file), 0, sizeof(struct file));
g_serialFilep.f_oflags = O_RDWR;
g_serialFilep.f_inode = inode;
if (inode->u.i_ops->open != NULL) {
(VOID)inode->u.i_ops->open(&g_serialFilep);
} else {
ret = EFAULT;
inode_release(inode);
goto ERROUT_WITH_FULLPATH;
}
(VOID)register_driver(SERIAL, &g_serialDevOps, DEFFILEMODE, &g_serialFilep);
inode_release(inode);
free(fullpath);
return ENOERR;
ERROUT_WITH_FULLPATH:
free(fullpath);
ERROUT:
set_errno(ret);
return VFS_ERROR;
}
INT32 virtual_serial_deinit(VOID)
{
INT32 ret;
struct file *filep = NULL;
struct inode *inode = NULL;
CHAR *fullpath = NULL;
struct inode_search_s desc;
/* It's a process opposite virtual_serial_init */
ret = vfs_normalize_path(NULL, SERIAL, &fullpath);
if (ret < 0) {
ret = EINVAL;
goto ERROUT;
}
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_find(&desc);
if (ret < 0) {
ret = EACCES;
goto ERROUT_WITH_FULLPATH;
}
inode = desc.node;
filep = inode->i_private;
if ((filep != NULL) && (inode->u.i_ops != NULL)) {
(VOID)inode->u.i_ops->close(filep); /* close filep */
inode->i_private = NULL;
} else {
ret = EBADF;
goto ERROUT_WITH_INODE;
}
inode_release(inode);
free(fullpath);
(VOID)unregister_driver(SERIAL);
return ENOERR;
ERROUT_WITH_INODE:
inode_release(inode);
ERROUT_WITH_FULLPATH:
free(fullpath);
ERROUT:
set_errno(ret);
return VFS_ERROR;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#编译器将本文件自动生成 menuconfig.h 放在..\..\..\platform\include\menuconfig.h
#详见 zzz\autogen\menuconfig.h
#
# Automatically generated file; DO NOT EDIT.
# Huawei LiteOS Configuration
#
#
# Compiler
#
# LOSCFG_COMPILER_HIMIX_32 is not set
LOSCFG_COMPILER_CLANG_LLVM=y
#
# Platform
#
LOSCFG_PLATFORM="hi3516dv300" #平台名称
LOSCFG_PLATFORM_HI3516DV300=y #编译平台开关
# LOSCFG_PLATFORM_HI3518EV300 is not set
# LOSCFG_TEE_ENABLE is not set
LOSCFG_PLATFORM_BSP_GIC_V2=y
LOSCFG_ARCH_ARM=y
LOSCFG_ARCH_ARM_AARCH32=y
LOSCFG_ARCH_ARM_V7A=y
LOSCFG_ARCH_ARM_VER="armv7-a"
LOSCFG_ARCH_FPU_VFP_V4=y
LOSCFG_ARCH_FPU_VFP_D32=y
LOSCFG_ARCH_FPU_VFP_NEON=y
LOSCFG_ARCH_FPU="neon-vfpv4"
LOSCFG_ARCH_CORTEX_A7=y
LOSCFG_ARCH_CPU="cortex-a7"
#
# Extra Configurations
#
# LOSCFG_ARCH_FPU_DISABLE is not set
LOSCFG_IRQ_USE_STANDALONE_STACK=y
LOSCFG_PLATFORM_ROOTFS=y
#
# Kernel
#
LOSCFG_KERNEL_SMP=y #打开多CPU核开关
LOSCFG_KERNEL_SMP_CORE_NUM=2 #2个CPUcore
LOSCFG_KERNEL_SMP_LOCKDEP=y #打开多CPU的死锁检测
LOSCFG_KERNEL_SMP_TASK_SYNC=y #打开多CPU下的任务同步
# LOSCFG_KERNEL_SCHED_STATISTICS is not set
LOSCFG_KERNEL_EXTKERNEL=y #
LOSCFG_KERNEL_CPPSUPPORT=y #支持C++编译
LOSCFG_KERNEL_CPUP=y #打开CPU检测 ,用于查询系统CPU的占用率。
LOSCFG_CPUP_INCLUDE_IRQ=y #打开CPU检测(包含中断)
LOSCFG_KERNEL_DYNLOAD=y #打开内核动态加载ELF功能
LOSCFG_ASLR=y #ASLR(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。
LOSCFG_KERNEL_VDSO=y #VDSO就是Virtual Dynamic Shared Object,就是内核提供的虚拟的.so,这个.so文件不在磁盘上,而是在内核里头
# LOSCFG_KERNEL_TICKLESS is not set
# LOSCFG_KERNEL_TRACE is not set
LOSCFG_KERNEL_LITEIPC=y #用于轻量级进程间通讯
LOSCFG_KERNEL_PIPE=y #管道支持
LOSCFG_BASE_CORE_HILOG=y #hilog 日志支持 /dev/hilog
#
# Lib
#
LOSCFG_LIB_LIBC=y
LOSCFG_LIB_ZLIB=y
#
# Compat
#
LOSCFG_COMPAT_POSIX=y #兼容posix
LOSCFG_COMPAT_BSD=y #兼容bsd
#
# FileSystem
#
LOSCFG_FS_VFS=y #虚拟文件系统
LOSCFG_FS_VFS_BLOCK_DEVICE=y #块设备支持
LOSCFG_FILE_MODE=y #文件权限支持 例如:chmod 777
LOSCFG_FS_FAT=y #文件配置表(英语:File Allocation Table,首字母缩略字:FAT),是一种由微软发明并拥有部分专利的文件系统
LOSCFG_FS_FAT_CACHE=y #FAT缓存支持
# LOSCFG_FS_FAT_CACHE_SYNC_THREAD is not set
LOSCFG_FS_FAT_CHINESE=y #区域设置和命名空间配置
LOSCFG_FS_FAT_VIRTUAL_PARTITION=y
LOSCFG_FS_FAT_VOLUMES=16
LOSCFG_FS_FAT_DISK=y #
LOSCFG_FS_RAMFS=y
LOSCFG_FS_NFS=y #网络文件系统,英文Network File System(NFS)
LOSCFG_FS_PROC=y
LOSCFG_FS_JFFS=y #Journalling Flash File System(闪存设备日志型文件系统,JFFS),一般用于nor flash的文件系统
#
# Net
#
LOSCFG_NET_LWIP_SACK=y
LOSCFG_NET_LWIP_SACK_2_1=y
#
# Debug
#
# LOSCFG_COMPILE_DEBUG is not set
LOSCFG_PLATFORM_ADAPT=y
LOSCFG_ENABLE_OOM_LOOP_TASK=y #支持内存溢出检测
LOSCFG_ENABLE_MAGICKEY=y #支持魔法键
# LOSCFG_THUMB is not set
# LOSCFG_DEBUG_VERSION is not set
LOSCFG_DRIVERS_HDF_PLATFORM_UART=y
# LOSCFG_PLATFORM_UART_WITHOUT_VFS is not set
# LOSCFG_PLATFORM_NO_UART is not set
#
# Driver
#
LOSCFG_DRIVERS=y
LOSCFG_DRIVERS_USB=y
LOSCFG_DRIVERS_USB_HOST_DRIVER=y
# LOSCFG_DRIVERS_USB_HOST_EHCI is not set
LOSCFG_DRIVERS_USB_HOST_XHCI=y
LOSCFG_DRIVERS_USB_DEVICE_CLASS_DRIVERS=y
#
# USB Device Class Drivers
#
LOSCFG_DRIVERS_USB_MASS_STORAGE=y
LOSCFG_DRIVERS_USB_RNDIS_HOST=y
LOSCFG_DRIVERS_USB_4G_MODEM=y
LOSCFG_DRIVERS_USB_SERIAL=y
LOSCFG_DRIVERS_USB_ETHERNET=y
LOSCFG_DRIVERS_USB_WIRELESS=y
LOSCFG_DRIVERS_USB_HID_CLASS=y
LOSCFG_DRIVERS_HDF=y
LOSCFG_DRIVERS_HDF_PLATFORM=y
LOSCFG_DRIVERS_HDF_PLATFORM_I2C=y
LOSCFG_DRIVERS_HDF_PLATFORM_SPI=y
LOSCFG_DRIVERS_HDF_PLATFORM_GPIO=y
LOSCFG_DRIVERS_HDF_PLATFORM_WATCHDOG=y
LOSCFG_DRIVERS_HDF_PLATFORM_SDIO=y
LOSCFG_DRIVERS_HDF_PLATFORM_RTC=y
LOSCFG_DRIVERS_HDF_PLATFORM_HISI_SDK=y
LOSCFG_DRIVERS_HDF_WIFI=y
LOSCFG_DRIVERS_HI3881=y
LOSCFG_DRIVERS_HDF_INPUT=y
LOSCFG_DRIVERS_HDF_TP_5P5_GT911=y
LOSCFG_DRIVERS_HDF_LCD=y
LOSCFG_DRIVERS_HDF_LCD_ICN9700=y
LOSCFG_DRIVERS_HDF_USB=y
LOSCFG_DRIVERS_NETDEV=y
LOSCFG_DRIVERS_HIETH_SF=y
LOSCFG_DRIVERS_MEM=y
LOSCFG_DRIVERS_MMC=y
LOSCFG_DRIVERS_SD=y
LOSCFG_DRIVERS_EMMC=y
LOSCFG_DRIVERS_EMMC_HS200=y
LOSCFG_DRIVERS_MTD=y
LOSCFG_DRIVERS_MTD_SPI_NOR=y
LOSCFG_DRIVERS_MTD_SPI_NOR_HIFMC100=y
LOSCFG_DRIVERS_RANDOM=y
LOSCFG_HW_RANDOM_ENABLE=y
LOSCFG_DRIVERS_VIDEO=y
LOSCFG_DRIVERS_HIEVENT=y
#
# Security
#
LOSCFG_SECURITY=y
LOSCFG_SECURITY_CAPABILITY=y
LOSCFG_SECURITY_VID=y
# LOSCFG_SECURITY_BOOT is not set
#
# Stack Smashing Protector (SSP) Compiler Feature
#
# LOSCFG_CC_NO_STACKPROTECTOR is not set
# LOSCFG_CC_STACKPROTECTOR is not set
LOSCFG_CC_STACKPROTECTOR_STRONG=y
# LOSCFG_CC_STACKPROTECTOR_ALL is not set
#编译器将本文件自动生成 menuconfig.h 放在..\..\..\platform\include\menuconfig.h
#详见 zzz\autogen\menuconfig.h
#
# Automatically generated file; DO NOT EDIT.
# Huawei LiteOS Configuration
#
#
# Compiler
#
# LOSCFG_COMPILER_HIMIX_32 is not set
LOSCFG_COMPILER_CLANG_LLVM=y
#
# Platform
#
LOSCFG_PLATFORM="hi3516dv300" #平台名称
LOSCFG_PLATFORM_HI3516DV300=y #编译平台开关
# LOSCFG_PLATFORM_HI3518EV300 is not set
# LOSCFG_TEE_ENABLE is not set
LOSCFG_PLATFORM_BSP_GIC_V2=y
LOSCFG_ARCH_ARM=y
LOSCFG_ARCH_ARM_AARCH32=y
LOSCFG_ARCH_ARM_V7A=y
LOSCFG_ARCH_ARM_VER="armv7-a"
LOSCFG_ARCH_FPU_VFP_V4=y
LOSCFG_ARCH_FPU_VFP_D32=y
LOSCFG_ARCH_FPU_VFP_NEON=y
LOSCFG_ARCH_FPU="neon-vfpv4"
LOSCFG_ARCH_CORTEX_A7=y
LOSCFG_ARCH_CPU="cortex-a7"
#
# Extra Configurations
#
# LOSCFG_ARCH_FPU_DISABLE is not set
LOSCFG_IRQ_USE_STANDALONE_STACK=y
LOSCFG_PLATFORM_ROOTFS=y
#
# Kernel
#
LOSCFG_KERNEL_SMP=y #打开多CPU核开关
LOSCFG_KERNEL_SMP_CORE_NUM=2 #2个CPUcore
LOSCFG_KERNEL_SMP_LOCKDEP=y #打开多CPU的死锁检测
LOSCFG_KERNEL_SMP_TASK_SYNC=y #打开多CPU下的任务同步
# LOSCFG_KERNEL_SCHED_STATISTICS is not set
LOSCFG_KERNEL_EXTKERNEL=y #
LOSCFG_KERNEL_CPPSUPPORT=y #支持C++编译
LOSCFG_KERNEL_CPUP=y #打开CPU检测 ,用于查询系统CPU的占用率。
LOSCFG_CPUP_INCLUDE_IRQ=y #打开CPU检测(包含中断)
LOSCFG_KERNEL_DYNLOAD=y #打开内核动态加载ELF功能
LOSCFG_ASLR=y #ASLR(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。
LOSCFG_KERNEL_VDSO=y #VDSO就是Virtual Dynamic Shared Object,就是内核提供的虚拟的.so,这个.so文件不在磁盘上,而是在内核里头
# LOSCFG_KERNEL_TICKLESS is not set
# LOSCFG_KERNEL_TRACE is not set
LOSCFG_KERNEL_LITEIPC=y #用于轻量级进程间通讯
LOSCFG_KERNEL_PIPE=y #管道支持
LOSCFG_BASE_CORE_HILOG=y #hilog 日志支持 /dev/hilog
#
# Lib
#
LOSCFG_LIB_LIBC=y
LOSCFG_LIB_ZLIB=y
#
# Compat
#
LOSCFG_COMPAT_POSIX=y #兼容posix
LOSCFG_COMPAT_BSD=y #兼容bsd
#
# FileSystem
#
LOSCFG_FS_VFS=y #虚拟文件系统
LOSCFG_FS_VFS_BLOCK_DEVICE=y #块设备支持
LOSCFG_FILE_MODE=y #文件权限支持 例如:chmod 777
LOSCFG_FS_FAT=y #文件配置表(英语:File Allocation Table,首字母缩略字:FAT),是一种由微软发明并拥有部分专利的文件系统
LOSCFG_FS_FAT_CACHE=y #FAT缓存支持
# LOSCFG_FS_FAT_CACHE_SYNC_THREAD is not set
LOSCFG_FS_FAT_CHINESE=y #区域设置和命名空间配置
LOSCFG_FS_FAT_VIRTUAL_PARTITION=y
LOSCFG_FS_FAT_VOLUMES=16
LOSCFG_FS_FAT_DISK=y #
LOSCFG_FS_RAMFS=y #内存文件系统
LOSCFG_FS_NFS=y #网络文件系统,英文Network File System(NFS)
LOSCFG_FS_PROC=y #一个伪文件系统,提供了访问内核数据的方法 /proc
LOSCFG_FS_JFFS=y #Journalling Flash File System(闪存设备日志型文件系统,JFFS),一般用于nor flash的文件系统
#
# Net
#
LOSCFG_NET_LWIP_SACK=y
LOSCFG_NET_LWIP_SACK_2_1=y
#
# Debug
#
# LOSCFG_COMPILE_DEBUG is not set
LOSCFG_PLATFORM_ADAPT=y
LOSCFG_ENABLE_OOM_LOOP_TASK=y #支持内存溢出检测
LOSCFG_ENABLE_MAGICKEY=y #支持魔法键
# LOSCFG_THUMB is not set
# LOSCFG_DEBUG_VERSION is not set
LOSCFG_DRIVERS_HDF_PLATFORM_UART=y
# LOSCFG_PLATFORM_UART_WITHOUT_VFS is not set
# LOSCFG_PLATFORM_NO_UART is not set
#
# Driver
#
LOSCFG_DRIVERS=y
LOSCFG_DRIVERS_USB=y
LOSCFG_DRIVERS_USB_HOST_DRIVER=y
# LOSCFG_DRIVERS_USB_HOST_EHCI is not set
LOSCFG_DRIVERS_USB_HOST_XHCI=y
LOSCFG_DRIVERS_USB_DEVICE_CLASS_DRIVERS=y
#
# USB Device Class Drivers
#
LOSCFG_DRIVERS_USB_MASS_STORAGE=y
LOSCFG_DRIVERS_USB_RNDIS_HOST=y
LOSCFG_DRIVERS_USB_4G_MODEM=y
LOSCFG_DRIVERS_USB_SERIAL=y
LOSCFG_DRIVERS_USB_ETHERNET=y
LOSCFG_DRIVERS_USB_WIRELESS=y
LOSCFG_DRIVERS_USB_HID_CLASS=y
LOSCFG_DRIVERS_HDF=y
LOSCFG_DRIVERS_HDF_PLATFORM=y
LOSCFG_DRIVERS_HDF_PLATFORM_I2C=y
LOSCFG_DRIVERS_HDF_PLATFORM_SPI=y
LOSCFG_DRIVERS_HDF_PLATFORM_GPIO=y
LOSCFG_DRIVERS_HDF_PLATFORM_WATCHDOG=y
LOSCFG_DRIVERS_HDF_PLATFORM_SDIO=y
LOSCFG_DRIVERS_HDF_PLATFORM_RTC=y
LOSCFG_DRIVERS_HDF_PLATFORM_HISI_SDK=y
LOSCFG_DRIVERS_HDF_WIFI=y
LOSCFG_DRIVERS_HI3881=y
LOSCFG_DRIVERS_HDF_INPUT=y
LOSCFG_DRIVERS_HDF_TP_5P5_GT911=y
LOSCFG_DRIVERS_HDF_LCD=y
LOSCFG_DRIVERS_HDF_LCD_ICN9700=y
LOSCFG_DRIVERS_HDF_USB=y
LOSCFG_DRIVERS_NETDEV=y
LOSCFG_DRIVERS_HIETH_SF=y
LOSCFG_DRIVERS_MEM=y
LOSCFG_DRIVERS_MMC=y
LOSCFG_DRIVERS_SD=y
LOSCFG_DRIVERS_EMMC=y
LOSCFG_DRIVERS_EMMC_HS200=y
LOSCFG_DRIVERS_MTD=y
LOSCFG_DRIVERS_MTD_SPI_NOR=y
LOSCFG_DRIVERS_MTD_SPI_NOR_HIFMC100=y
LOSCFG_DRIVERS_RANDOM=y
LOSCFG_HW_RANDOM_ENABLE=y
LOSCFG_DRIVERS_VIDEO=y
LOSCFG_DRIVERS_HIEVENT=y
#
# Security
#
LOSCFG_SECURITY=y
LOSCFG_SECURITY_CAPABILITY=y
LOSCFG_SECURITY_VID=y
# LOSCFG_SECURITY_BOOT is not set
#
# Stack Smashing Protector (SSP) Compiler Feature
#
# LOSCFG_CC_NO_STACKPROTECTOR is not set
# LOSCFG_CC_STACKPROTECTOR is not set
LOSCFG_CC_STACKPROTECTOR_STRONG=y
# LOSCFG_CC_STACKPROTECTOR_ALL is not set
git add -A
git commit -m '1.zzz目录添加编译hi3516dv300后自动生成的宏文件 2.内核有哪些块/字符设备,是如何实现的?
搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
'
git push origin
git push gitee_origin master
git push github_origin master
git push coding_origin master
#git remote add github_origin git@github.com:kuangyufei/kernel_liteos_a_note.git
#git remote add gitee_origin git@gitee.com:weharmony/kernel_liteos_a_note.git
#git remote add origin git@codechina.csdn.net:kuangyufei/kernel_liteos_a_note.git
git add -A
git commit -m '根文件系统rootfs 部分注释
搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
'
git push origin
git push gitee_origin master
git push github_origin master
git push coding_origin master
#git remote add github_origin git@github.com:kuangyufei/kernel_liteos_a_note.git
#git remote add gitee_origin git@gitee.com:weharmony/kernel_liteos_a_note.git
#git remote add origin git@codechina.csdn.net:kuangyufei/kernel_liteos_a_note.git
#git remote add coding_origin git@e.coding.net:weharmony/harmony/kernel_liteos_a_note.git
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册