鸿蒙内核源码分析(根文件系统)|先挂到`/`上的文件系统|百篇博客分析openharmony源码|v66.01(代码片段)

鸿蒙内核源码分析 鸿蒙内核源码分析     2022-12-20     256

关键词:

百篇博客系列篇.本篇为:

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后发生了什么

查看 kernel/liteos_a/Makefile

#执行 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)/$@.map -o $(OUT)/$@ --start-group $(LITEOS_LIBDEP) --end-group
      #	$(SIZE) -t --common $(OUT)/lib/*.a >$(OUT)/$@.objsize
          $(OBJCOPY) -O binary $(OUT)/$@ $(LITEOS_TARGET_DIR)/$@.bin #生成 liteos.bin 文件
          $(OBJDUMP) -t $(OUT)/$@ |sort >$(OUT)/$@.sym.sorted	#生成 liteos.sym.sorted 文件
          $(OBJDUMP) -d $(OUT)/$@ >$(OUT)/$@.asm # 生成 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 >

关注不迷路.代码即人生

热爱是所有的理由和答案 - turing

原创不易,欢迎转载,但麻烦请注明出处.

v74.01鸿蒙内核源码分析(控制台)|一个让很多人模糊的概念|百篇博客分析openharmony源码

...制台篇)|一个让很多人模糊的概念文件系统相关篇为:v62.02鸿蒙内核源码分析(文件概念)|为什么说一切皆是文件v63.04鸿蒙内核源码分析(文件系统)|用图书管理说文件系统v64.06鸿蒙内核源码分析(索引节点)|谁是文件系统最重要的概念... 查看详情

v75.01鸿蒙内核源码分析(远程登录篇)|内核如何接待远方的客人|百篇博客分析openharmony源码(代码片段)

...登录篇)|内核如何接待远方的客人文件系统相关篇为:v62.02鸿蒙内核源码分析(文件概念)|为什么说一切皆是文件v63.04鸿蒙内核源码分析(文件系统)|用图书管理说文件系统v64.06鸿蒙内核源码分析(索引节点)|谁是文件系统最重要的概念... 查看详情

鸿蒙内核源码分析(挂载目录篇)|为何文件系统需要挂载|百篇博客分析openharmony源码|v65.01(代码片段)

百篇博客系列篇.本篇为:v65.xx鸿蒙内核源码分析(挂载目录篇)|为何文件系统需要挂载|51.c.h.o文件系统相关篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.ov63.xx鸿蒙内核源码分析(文件系统篇)|用图书管理说文... 查看详情

鸿蒙内核源码分析(文件句柄篇)|深挖应用操作文件的细节|百篇博客分析openharmony源码|v69.01(代码片段)

百篇博客系列篇.本篇为:v69.xx鸿蒙内核源码分析(文件句柄篇)|深挖应用操作文件的细节|51.c.h.o文件系统相关篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.ov63.xx鸿蒙内核源码分析(文件系统篇)|用图书管理说... 查看详情

鸿蒙内核源码分析(管道文件篇)|如何降低数据流动成本|百篇博客分析openharmony源码|v70.01(代码片段)

百篇博客系列篇.本篇为:v70.xx鸿蒙内核源码分析(管道文件篇)|如何降低数据流动成本|51.c.h.o文件系统相关篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.ov63.xx鸿蒙内核源码分析(文件系统篇)|用图书管理说文... 查看详情

鸿蒙内核源码分析(索引节点篇)|谁是文件系统最重要的概念|百篇博客分析openharmony源码|v64.01(代码片段)

百篇博客系列篇.本篇为:v64.xx鸿蒙内核源码分析(索引节点篇)|谁是文件系统最重要的概念|51.c.h.o文件系统相关篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.ov63.xx鸿蒙内核源码分析(文件系统篇)|用图书管理... 查看详情

鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|百篇博客分析openharmony源码|v62.01(代码片段)

百篇博客系列篇.本篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.o本篇开始说文件系统,它是内核五大模块之一,甚至有Linux的设计哲学是"一切皆文件"的说法。所以其重要性不言而喻.搞不清楚文件系... 查看详情

鸿蒙轻内核源码分析:虚拟文件系统vfs(代码片段)

本文分享自华为云社区《鸿蒙轻内核M核源码分析系列二一01虚拟文件系统VFS》,作者:zhushy。VFS(VirtualFileSystem)是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合... 查看详情

鸿蒙内核源码分析(vfs篇)|文件系统和谐共处的基础|百篇博客分析openharmony源码|v68.01(代码片段)

...。”《论语》:雍也篇百篇博客系列篇.本篇为:v68.xx鸿蒙内核源码分析(VFS篇)|文件系统和谐共处的基础|51.c.h.o文件系统相关篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.ov63.xx鸿蒙内核源码分析(文件系... 查看详情

鸿蒙内核源码分析(文件系统篇)|用图书管理说文件系统|百篇博客分析openharmony源码|v63.01(代码片段)

百篇博客系列篇.本篇为:v63.xx鸿蒙内核源码分析(文件系统篇)|用图书管理说文件系统|51.c.h.o文件系统相关篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.o本篇讲一个大型图书馆的管理方案,来说清楚计算机... 查看详情

鸿蒙内核源码分析(字符设备篇)|字节为单位读写的设备|百篇博客分析openharmony源码|v67.01(代码片段)

百篇博客系列篇.本篇为:v67.xx鸿蒙内核源码分析(字符设备篇)|字节为单位读写的设备|51.c.h.o文件系统相关篇为:v62.xx鸿蒙内核源码分析(文件概念篇)|为什么说一切皆是文件|51.c.h.ov63.xx鸿蒙内核源码分析(文件系统篇)|用图书管理说文... 查看详情

鸿蒙轻内核源码分析:文件系统littlefs(代码片段)

...c;然后分析下LFS文件操作接口。本文分享自华为云社区《#鸿蒙轻内核M核源码分析系列二一02文件系统LittleFS》,作者:zhushy。LittleFS是一个小型的Flash文件系统,它结合日志结构(log-structured)文件系统和COW࿰... 查看详情

鸿蒙内核源码分析(ninja应用篇)|简单而快速的构建系统|百篇博客分析harmonyos源码|v61.01(代码片段)

OpenHarmony|鸿蒙研究站|WeHarmony<国内|国外>百篇博客系列篇.本篇为:v61.xx鸿蒙内核源码分析(ninja应用篇)|简单而快速的构建系统|51.c.h.o编译构建模块相关篇为:v60.xx鸿蒙内核源码分析(gn应用篇)|gn语法及在鸿蒙的使用|51.c.h.ov59.xx鸿... 查看详情

v87.01鸿蒙内核源码分析(内核启动篇)|从汇编到main()|百篇博客分析openharmony源码

...MMU、SVC栈、热启动、内核映射表内核汇编相关篇为:v74.01鸿蒙内核源码分析(编码方式)|机器指令是如何编码的v75.03鸿蒙内核源码分析(汇编基础)|CPU上班也要打卡v76.04鸿蒙内核源码分析(汇编传参)|如何传递复杂的参数v77.01鸿蒙内核... 查看详情

v87.01鸿蒙内核源码分析(内核启动篇)|从汇编到main()|百篇博客分析openharmony源码

...MMU、SVC栈、热启动、内核映射表内核汇编相关篇为:v74.01鸿蒙内核源码分析(编码方式)|机器指令是如何编码的v75.03鸿蒙内核源码分析(汇编基础)|CPU上班也要打卡v76.04鸿蒙内核源码分析(汇编传参)|如何传递复杂的参数v77.01鸿蒙内核... 查看详情

v73.01鸿蒙内核源码分析(注释文档)|内核所有函数调用关系图|百篇博客分析openharmony源码

...文档篇)|内核所有函数调用关系图前因后果相关篇为:v08.03鸿蒙内核源码分析(总目录)|百万汉字注解百篇博客分析v09.04鸿蒙内核源码分析(调度故事)|用故事说内核调度v10.03鸿蒙内核源码分析(内存主奴)|皇上和奴才如何相处v13.05鸿蒙... 查看详情

鸿蒙轻内核源码分析:异常钩子模块系统中断异常,如何转储异常信息(代码片段)

摘要:本篇介绍下鸿蒙轻内核中异常钩子模块发生系统中断异常时如何转储异常信息。本文分享自华为云社区《鸿蒙轻内核M核源码分析系列十七(3)异常信息ExcInfo》,作者:zhushy。ExcHook异常钩子模块是OpenHar... 查看详情

v87.01鸿蒙内核源码分析(内核启动篇)|从汇编到main()|百篇博客分析openharmony源码

...MMU、SVC栈、热启动、内核映射表内核汇编相关篇为:v74.01鸿蒙内核源码分析(编码方式)|机器指令是如何编码的v75.03鸿蒙内核源码分析(汇编基础)|CPU上班也要打卡v76.04鸿蒙内核源码分析(汇编传参)|如何传递复杂的参数v77.01鸿蒙内核... 查看详情