

鸿蒙内核源码分析(根文件系统) | 先挂到`/`上的文件系统 | 百篇博客分析OpenHarmony源...
source link: https://my.oschina.net/weharmony/blog/5177087
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

百篇博客系列篇.本篇为:
v66.xx 鸿蒙内核源码分析(根文件系统) | 先挂到/
上的文件系统 | 51 .c .h .o
文件系统相关篇为:
FHS | 文件系统层次结构标准
-
在 挂载目录篇 中提到内核为了兼容文件系统的差异性,引出了目录树的概念,目录树是由各个文件系统像搭积木一样拼接起来的,任何文件系统只需要挂载到一个目录上就能对接进来,内核抽象出统一的挂载接口,各文件系统自己实现这些接口就行. 既然目录如此重要, 就需要规范管理, 类Unix都遵循 FHS 规范,鸿蒙同样遵循.
-
文件系统层次结构标准(英语:Filesystem Hierarchy Standard,FHS)定义了Linux操作系统中的主要目录及目录内容。FHS由Linux基金会维护。 当前版本为3.0版,于2015年发布。基本目录如下:
/ 根目录 /home 用户主文件夹 /etc 系统主要的配置文件几乎都放置在这个目录内 /root 系统管理员(root)的主文件夹 /bin 可以被 root 与一般账号所使用 /sbin 这些命令只有 root 才能够利用来“设置”系统 /lib 放置的则是在开机时会用到的函数库 /opt 用于安装第三方应用程序的 /dev 任何设备与接口设备都是以文件的形式存在于这个目录当中 /proc 一个虚拟的文件系统, 它放置的数据都是在内存当中 /sys 也是一个虚拟的文件系统,主要也是记录与内核相关的信息 /media 放置的就是可删除的设备 /mnt 暂时挂载某些额外的设备 /srv 一些网络服务启动之后,这些服务所需要取用的数据目录 /tmp 正在执行的程序暂时放置文件的地方, 系统会不定期删除 /usr “UNIX 操作系统软件资源” 所放置的目录 /usr/bin/: 绝大部分的用户可使用命令都放在这里 /usr/include/:C/C++等程序语言的头文件 header 与包含文件include放置处 /usr/lib/: 包含各应用软件的函数库、目标文件以及一些不被一般用户惯用的执行文件或脚本 /usr/local/: 系统管理员在本机自行安装下载的软件建议安装到此目录 /usr/sbin/: 非系统正常运行所需的系统命令 /usr/share/: 放置共享文件的地方 /usr/src/: 一般源码建议放置到这里 /var 该目录主要针对常态性可变动文件 /var/cache/: 应用程序本身运行过程中会产生的一些暂存文件 /var/lib/: 程序本身执行的过程中,需要的数据文件放置的目录 /var/lock/: 目录下的文件资源一次只能被一个应用程序所使用 /var/log/: 放置登录文件的目录 /var/mail/: 放置个人电子邮件信箱的目录 /var/run/: 某些程序或服务启动后的PID目录 /var/spool/: 放置排队等待其他应用程程序使用的数据
什么是根文件系统
什么是根文件系统? 看网上有很多的文章,但基本全是一大抄,说是内核启动时所mount的第一个文件系统,这话固然是没错, 但想重新定义下这个概念,所谓 根文件系统 就是先挂到根目录/
上的文件系统. 核心是根目录 /
. /
目录并不必先属于哪个文件系统,否则就是先有蛋还是先有鸡的问题,所以别被蒙圈了,它跟其他文件系统没有任何区别,只是它先来,把坑/
给占了,后续来的只能挂到它下面的目录上,最终形成整颗目录树.
理解了上面,就容易明白以下几个问题:
- 一个系统可以存在多个不同的文件系统,谁做根文件系统只决于内核在启动阶段想让谁做.
- 文件系统可存在于诸多介质上,例如:硬盘(mmc),闪存(flash),内存(RAM).每种介质上有其最合适配套的文件系统,mmc一般是(fat,ext),flash包括(jffs2),内存(proc,sys,tmpfs,ramfs)
- 文件系统可简单,可复杂,只要能实现内核定义的三类接口就可以称之为文件系统,哪三类接口:
- 挂载接口:
MountOps ops
- 操作
inode
节点接口:VnodeOps *vop
- 操作
file
接口:file_operations_vfs *fop
,这个接口底层实际操作的是inode
所指向的数据块.
- 挂载接口:
- 不管怎样,内核启动后必须得有一个文件系统用于挂载到
/
下. 鸿蒙根文件系统目录结构如下:. ├── app ├── bin │ ├── init │ ├── shell │ └── tftp ├── data │ └── system │ └── param ├── etc ├── lib │ ├── libc++.so │ └── libc.so ├── system │ ├── external │ └── internal └── usr ├── bin └── lib
这些数据是怎么来的呢 ? 比如:libc.so
这种C库函数,启动后就马上需要使用的, 这需要先外部制作好,烧录到flash的指定位置. 同时注意鸿蒙制作的根文件系统并没有 /dev
目录,这个在 设备文件篇 中详细说明.
根文件系统制作过程
以liteos_a
内核为例,其提供了制作根文件系统的方法:
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/kernel/liteos_a$ make help
-------------------------------------------------------
1.====make help: get help infomation of make
2.====make: make a debug version based the .config
3.====make debug: make a debug version based the .config
4.====make release: make a release version for all platform
5.====make release PLATFORM=xxx: make a release version only for platform xxx
6.====make rootfsdir: make a original rootfs dir
7.====make rootfs FSTYPE=***: make a original rootfs img
8.====make test: make the testsuits_app and put it into the rootfs dir
9.====make test_apps FSTYPE=***: make a rootfs img with the testsuits_app in it
xxx should be one of (hi3516cv300 hi3516ev200 hi3556av100/cortex-a53_aarch32 hi3559av100/cortex-a53_aarch64)
*** should be one of (jffs2)
其中第七项 make rootfs
, FSTYPE
支持 jffs2
,vfat
文件格式系统
本篇跟踪敲下 make rootfs FSTYPE=jffs2
后发生了什么
#执行 make rootfs FSTYPE=jffs2 一切从这里开始
$(ROOTFS): $(ROOTFSDIR) #依赖于 ROOTFSDIR
$(HIDE)$(LITEOSTOPDIR)/tools/scripts/make_rootfs/rootfsimg.sh $(ROOTFS_DIR) $(FSTYPE) #制作镜像文件
$(HIDE)cd $(ROOTFS_DIR)/.. && zip -r $(ROOTFS_ZIP) $(ROOTFS) #打rootfs.zip包
解读
-
编译整个内核的目标文件
$(LITEOS_TARGET): $(__LIBS) sysroot $(HIDE)touch $(LOSCFG_ENTRY_SRC) #逐个编译子目录中的 makefile $(HIDE)for dir in $(LITEOS_SUBDIRS); \ do $(MAKE) -C $$dir all || exit 1; \ done # 生成 liteos.map $(LD) $(LITEOS_LDFLAGS) $(LITEOS_TABLES_LDFLAGS) $(LITEOS_DYNLDFLAGS) -Map=$(OUT)/[email protected] -o $(OUT)/$@ --start-group $(LITEOS_LIBDEP) --end-group # $(SIZE) -t --common $(OUT)/lib/*.a >$(OUT)/[email protected] $(OBJCOPY) -O binary $(OUT)/$@ $(LITEOS_TARGET_DIR)/[email protected] #生成 liteos.bin 文件 $(OBJDUMP) -t $(OUT)/$@ |sort >$(OUT)/[email protected] #生成 liteos.sym.sorted 文件 $(OBJDUMP) -d $(OUT)/$@ >$(OUT)/[email protected] # 生成 liteos.asm文件
-
使用
$(APPS)
编译 kernel/liteos_a/apps 目录下的各个APP
如(init
,shell
,tftp
),这些APP也称为内置到内核的APP,# 编译多个应用程序 $(APPS): $(LITEOS_TARGET) sysroot #依赖于 LITEOS_TARGET , sysroot $(HIDE)$(MAKE) -C apps all #执行apps目录下Makefile 的all目标, -C代表进入apps目录,
-
使用 tools/scripts/make_rootfs/rootfsdir.sh 创建根系统下的各个目录(
/bin
,/app
,/lib
).#创建根文件系统的各个目录 mkdir -p ${ROOTFS_DIR}/bin ${ROOTFS_DIR}/lib ${ROOTFS_DIR}/usr/bin ${ROOTFS_DIR}/usr/lib ${ROOTFS_DIR}/etc \ ${ROOTFS_DIR}/app ${ROOTFS_DIR}/data ${ROOTFS_DIR}/proc ${ROOTFS_DIR}/dev ${ROOTFS_DIR}/data/system ${ROOTFS_DIR}/data/system/param \ ${ROOTFS_DIR}/system ${ROOTFS_DIR}/system/internal ${ROOTFS_DIR}/system/external ${OUT_DIR}/bin ${OUT_DIR}/libs if [ -d "${BIN_DIR}" ] && [ "$(ls -A "${BIN_DIR}")" != "" ]; then cp -f ${BIN_DIR}/* ${ROOTFS_DIR}/bin if [ -e ${BIN_DIR}/shell ] && [ "${BIN_DIR}/shell" != "${OUT_DIR}/bin/shell" ]; then cp -f ${BIN_DIR}/shell ${OUT_DIR}/bin/shell #拷贝 shell 到根文件系统的 /bin下 fi if [ -e ${BIN_DIR}/tftp ] && [ "${BIN_DIR}/tftp" != "${OUT_DIR}/bin/tftp" ]; then cp -f ${BIN_DIR}/tftp ${OUT_DIR}/bin/tftp #拷贝 tftp 到根文件系统的 /bin下 fi fi cp -f ${LIB_DIR}/* ${ROOTFS_DIR}/lib #将c/c++ .so 库拷贝到根文件系统的 /lib cp -f ${LIB_DIR}/* ${OUT_DIR}/libs
-
使用
prepare
创建musl
目录,并将 c/c++ 库拷贝到该目录下prepare: #准备工作,创建 musl 目录,用于拷贝 c/c++ .so库 $(HIDE)mkdir -p $(OUT)/musl ifeq ($(LOSCFG_COMPILER_CLANG_LLVM), y) #使用clang-9 ,鸿蒙默认用这个编译 $(HIDE)cp -f $$($(CC) --target=$(LLVM_TARGET) --sysroot=$(SYSROOT_PATH) $(LITEOS_CFLAGS) -print-file-name=libc.so) $(OUT)/musl #将C库复制到musl目录下 $(HIDE)cp -f $$($(GPP) --target=$(LLVM_TARGET) --sysroot=$(SYSROOT_PATH) $(LITEOS_CXXFLAGS) -print-file-name=libc++.so) $(OUT)/musl #将C++库复制到musl目录下 else $(HIDE)cp -f $(LITEOS_COMPILER_PATH)/target/usr/lib/libc.so $(OUT)/musl $(HIDE)cp -f $(LITEOS_COMPILER_PATH)/arm-linux-musleabi/lib/libstdc++.so.6 $(OUT)/musl $(HIDE)cp -f $(LITEOS_COMPILER_PATH)/arm-linux-musleabi/lib/libgcc_s.so.1 $(OUT)/musl $(STRIP) $(OUT)/musl/* endif
-
tools/scripts/make_rootfs/rootfsimg.sh 生成镜像文件 rootfs_jffs2.img , 调用
mkfs.jffs2
来制作jffs2
文件格式的镜像.ROOTFS_IMG=${ROOTFS_DIR}"_"${FSTYPE}".img" JFFS2_TOOL=mkfs.jffs2 #linux 下 制作 jffs2镜像文件的工具 WIN_JFFS2_TOOL=mkfs.jffs2.exe #windows 下 制作 jffs2镜像文件的工具 chmod -R 755 ${ROOTFS_DIR} if [ -f "${ROOTFS_DIR}/bin/init" ]; then chmod 700 ${ROOTFS_DIR}/bin/init 2> /dev/null fi if [ -f "${ROOTFS_DIR}/bin/shell" ]; then chmod 700 ${ROOTFS_DIR}/bin/shell 2> /dev/null fi if [ "${FSTYPE}" = "jffs2" ]; then if [ "${system}" != "Linux" ] ; then tool_check ${WIN_JFFS2_TOOL} ${WIN_JFFS2_TOOL} -q -o ${ROOTFS_IMG} -d ${ROOTFS_DIR} --pagesize=4096 else tool_check ${JFFS2_TOOL} ${JFFS2_TOOL} -q -o ${ROOTFS_IMG} -d ${ROOTFS_DIR} --pagesize=4096 fi elif [ "${FSTYPE}" = "yaffs2" ]; then # to do fi
-
最后用 zip 命令将
rootfs
打包成rootfs.zip
,至此完成了鸿蒙根系统的制作过程. 将增加了一个out
目录,内容如下:turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/kernel/liteos_a/out/hi3518ev300$ ls bin lib liteos liteos.asm liteos.bin liteos.map liteos.sym.sorted musl obj rootfs rootfs_jffs2.img rootfs.zip
rootfs
便为制作的鸿蒙根文件系统rootfs_jffs2.img
为镜像文件,可以烧到flash
中.
这里列出启动根文件系统的相关代码
STATIC UINT32 OsSystemInitTaskCreate(VOID)
{
UINT32 taskID;
TSK_INIT_PARAM_S sysTask;
(VOID)memset_s(&sysTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
sysTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SystemInit;
sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
sysTask.pcName = "SystemInit";
sysTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
sysTask.uwResved = LOS_TASK_STATUS_DETACHED;
#if (LOSCFG_KERNEL_SMP == YES)
sysTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
#endif
return LOS_TaskCreate(&taskID, &sysTask);
}
解读
- 首先内核开了一个叫
SystemInit
任务来处理系统初始化代码,任务入口函数为SystemInit
SystemInit
层层调用到MountPartitions
,挂载分区.
在 设备文件篇 中将详细说明SystemInit(void) ... OsMountRootfs() AddPartitions //注册分区驱动程序 MountPartitions() #define ROOT_DEV_NAME "/dev/spinorblk0" #define ROOT_DIR_NAME "/" ret = mount(ROOT_DEV_NAME, ROOT_DIR_NAME, fsType, mountFlags, NULL);//
/dev/spinorblk0
的来源,简单的说就根文件系统烧录在nor flash
介质设备的第一个分区上,分区名称/dev/spinorblk0
只是表示一个“虚”的设备文件名而已,其背后是个实实在在的文件系统.现将它挂到/
上,结果是nor flash
的第一个分区成了根文件系统.
鸿蒙内核源码分析.总目录
v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51 .c .h .o
百万汉字注解.百篇博客分析
百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding >
百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto | csdn | harmony | osc >
关注不迷路.代码即人生
原创不易,欢迎转载,但麻烦请注明出处.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK