我用#CSDN#这个app发现了有技术含量的博客,小伙伴们求同去《Linux内核与根文件系统的关系》, 一起来围观吧 https://blog.csdn.net/NO_007/article/details/26289739?utm_source=app&app_version=4.19.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

1.VFS的概念及作用

其中kernel中以VFS去支持各种文件系统,如yaffs,ext3,cramfs等等。yaffs/yaffs2是专为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统。在内核中以VFS来屏蔽各种文件系统的接口不同,以VFS向kernel提供一个统一的接口。如打开一个文件时统一使用open,写时采用write,而不用去考虑是那种文件系统,也不用去考虑文件系统是如何将数据写入物理介质的。其中 kernel中的配置,只是让VFS支持这种接口。

2.根文件系统的作用?

以只读的方式挂载根文件系统,之所以采用只读的方式挂载根文件系统是因为:此时Linux内核仍在启动阶段,还不是很稳定,如果采用可读可写的方式挂载根文件系统,万一Linux不小心宕机了,一来可能破坏根文件系统上的数据,再者Linux下次开机时得花上很长的时间来检查并修复根文件系统。

挂载根文件系统的而目的有两个:一是安装适当的内核模块,以便驱动某些硬件设备或启用某些功能;二是启动存储于文件系统中的init服务,以便让init服务接手后续的启动工作。

根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中(这里为什莫说内核映像文件在根文件系统中??真是令人疑惑,根文件系统在内核启动的最后阶段才挂载的),系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。

根文件系统与内核其实是分开的,bootloader启动内核以后,内核需要完成诸如初始化内存结构,创建异常向量表和初始化中断处理函数,初始化系统核心进程调度器和时钟中断处理机制,创建和初始化系统cache,为各种内存调用机制提供缓存等等。这些步骤完了以后,才会开始挂载根文件系统,有了根文件系统我们才能看到我们熟悉的/bin、/etc、/lib、/dev等目录,根文件系统的目的主要有两个一是安装适当的内核模块,以便驱动某些硬件设备或启用某些功能;二是启动存储于文件系统中的init服务。以便让init服务接手兴许的启动工作。所以没有先挂载根文件系统又如何能找到flash中的init程序呢?接下来的init进程有会继续做没有完成的初始化操作,如挂载其他的文件系统。

3.*Linux系统结构详解

我用#CSDN#这个app发现了有技术含量的博客,小伙伴们求同去《Linux系统结构详解》, 一起来围观吧
https://blog.csdn.net/hguisu/article/details/6122513?utm_source=app&app_version=4.19.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

4.## 加载内核映像和根文件系统映像

我用#CSDN#这个app发现了有技术含量的博客,小伙伴们求同去《加载内核映像和根文件系统映像》, 一起来围观吧 https://blog.csdn.net/NO_007/article/details/26289575?utm_source=app&app_version=4.19.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

加载内核映像和根文件系统映像
(1) 规划内存占用的布局

这里包括两个方面:(1)内核映像所占用的内存范围;(2)根文件系统所占用的内存范围。在规划内存占用的布局时,主要考虑基地址和映像的大小两个方面。
对于内核映像,一般将其拷贝到从(MEM_START+0x8000) 这个基地址开始的大约1MB大小的内存范围内(嵌入式Linux 的内核一般都不操过 1MB)。为什么要把从 MEM_START 到 MEM_START+0x8000 这段 32KB 大小的内存空出来呢?这是因为 Linux 内核要在这段内存中放置一些全局数据结构,如:启动参数和内核页表等信息。
而对于根文件系统映像,则一般将其拷贝到 MEM_START+0x0010,0000 开始的地方。如果用 Ramdisk 作为根文件系统映像,则其解压后的大小一般是1MB。

(2)从 Flash 上拷贝

由于像 ARM 这样的嵌入式 CPU 通常都是在统一的内存地址空间中寻址 Flash 等固态存储设备的,因此从Flash 上读取数据与从 RAM 单元中读取数据并没有什么不同。用一个简单的循环就可以完成从 Flash 设备上拷贝映像的工作:

while(count) {*dest++ = *src++; /* they are all aligned with word boundary */count -= 4; /* byte number */};

3.2.4 设置内核的启动参数

应该说,在将内核映像和根文件系统映像拷贝到 RAM 空间中后,就可以准备启动 Linux 内核了。但是在调用内核之前,应该作一步准备工作,即:设置 Linux 内核的启动参数。

Linux 2.4.x 以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。启动参数标记列表以标记ATAG_CORE 开始,以标记 ATAG_NONE 结束。每个标记由标识被传递参数的 tag_header 结构以及随后的参数值数据结构来组成。数据结构 tag 和 tag_header 定义在 Linux 内核源码的include/asm/setup.h 头文件中:

/* The list ends with an ATAG_NONE node. */#define ATAG_NONE 0x00000000struct tag_header {u32 size; /* 注意,这里size是字数为单位的 */u32 tag;};……struct tag {struct tag_header hdr;union {struct tag_core core;struct tag_mem32 mem;struct tag_videotext videotext;struct tag_ramdisk ramdisk;struct tag_initrd initrd;struct tag_serialnr serialnr;struct tag_revision revision;struct tag_videolfb videolfb;struct tag_cmdline cmdline;/** Acorn specific*/struct tag_acorn acorn;/** DC21285 specific*/struct tag_memclk memclk;} u;};在嵌入式 Linux 系统中,通常需要由 Boot Loader 设置的常见启动参数有:ATAG_CORE、ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等。比如,设置 ATAG_CORE 的代码如下:params = (struct tag *)BOOT_PARAMS;params->hdr.tag = ATAG_CORE;params->hdr.size = tag_size(tag_core);params->u.core.flags = 0;params->u.core.pagesize = 0;params->u.core.rootdev = 0;params = tag_next(params);

其中,BOOT_PARAMS 表示内核启动参数在内存中的起始基地址,指针 params 是一个 struct tag 类型的指针。宏 tag_next() 将以指向当前标记的指针为参数,计算紧临当前标记的下一个标记的起始地址。注意,内核的根文件系统所在的设备ID就是在这里设置的。

下面是设置内存映射情况的示例代码:

for(i = 0; i < NUM_MEM_AREAS; i++) {if(memory_map[i].used) {params->hdr.tag = ATAG_MEM;params->hdr.size = tag_size(tag_mem32);params->u.mem.start = memory_map[i].start;params->u.mem.size = memory_map[i].size;params = tag_next(params);}}

可以看出,在 memory_map[]数组中,每一个有效的内存段都对应一个 ATAG_MEM 参数标记。

Linux 内核在启动时可以以命令行参数的形式来接收信息,利用这一点我们可以向内核提供那些内核不能自己检测的硬件参数信息,或者重载(override)内核自己检测到的信息。比如,我们用这样一个命令行参数字符串"console=ttyS0,115200n8"来通知内核以 ttyS0 作为控制台,且串口采用 "115200bps、无奇偶校验、8位数据位"这样的设置。下面是一段设置调用内核命令行参数字符串的示例代码:

char *p;/* eat leading white space */for(p = commandline; *p == ' '; p++);/* skip non-existent command lines so the kernel will still* use its default command line.*/if(*p == '')return;params->hdr.tag = ATAG_CMDLINE;params->hdr.size = (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;strcpy(params->u.cmdline.cmdline, p);params = tag_next(params);

请注意在上述代码中,设置 tag_header 的大小时,必须包括字符串的终止符’’,此外还要将字节数向上圆整4个字节,因为 tag_header 结构中的size 成员表示的是字数。

下面是设置 ATAG_INITRD 的示例代码,它告诉内核在 RAM 中的什么地方可以找到 initrd 映象(压缩格式)以及它的大小:

params->hdr.tag = ATAG_INITRD2;params->hdr.size = tag_size(tag_initrd);params->u.initrd.start = RAMDISK_RAM_BASE;params->u.initrd.size = INITRD_LEN;params = tag_next(params);

下面是设置 ATAG_RAMDISK 的示例代码,它告诉内核解压后的 Ramdisk 有多大(单位是KB):

params->hdr.tag = ATAG_RAMDISK;params->hdr.size = tag_size(tag_ramdisk);params->u.ramdisk.start = 0;params->u.ramdisk.size = RAMDISK_SIZE; /* 请注意,单位是KB */params->u.ramdisk.flags = 1; /* automatically load ramdisk */params = tag_next(params);

最后,设置 ATAG_NONE 标记,结束整个启动参数列表:

static void setup_end_tag(void){params->hdr.tag = ATAG_NONE;params->hdr.size = 0;}

3.2.5 调用内核

Boot Loader 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START+0x8000地址处。在跳转时,下列条件要满足:

1. CPU 寄存器的设置:

  • R0=0;

  • R1=机器类型 ID;关于 Machine Type Number,可以参见 linux/arch/arm/tools/mach-types。

  • R2=启动参数标记列表在 RAM 中起始基地址;

2. CPU 模式:

  • 必须禁止中断(IRQs和FIQs);

  • CPU 必须 SVC 模式;

3. Cache 和 MMU 的设置:

  • MMU 必须关闭;

  • 指令 Cache 可以打开也可以关闭;

  • 数据 Cache 必须关闭;

如果用 C 语言,可以像下列示例代码这样来调用内核:

void (*theKernel)(int zero, int arch, u32 params_addr) = (void (*)(int, int, u32))KERNEL_RAM_BASE;……theKernel(0, ARCH_NUMBER, (u32) kernel_params_start);

注意,theKernel()函数调用应该永远不返回的。如果这个调用返回,则说明出错。

  1. 关于串口终端

在 boot loader 程序的设计与实现中,没有什么能够比从串口终端正确地收到打印信息能更令人激动了。此外,向串口终端打印信息也是一个非常重要而又有效的调试手段。但是,我们经常会碰到串口终端显示乱码或根本没有显示的问题。造成这个问题主要有两种原因:(1) boot loader 对串口的初始化设置不正确。(2) 运行在host 端的终端仿真程序对串口的设置不正确,这包括:波特率、奇偶校验、数据位和停止位等方面的设置。

此外,有时也会碰到这样的问题,那就是:在 boot loader 的运行过程中我们可以正确地向串口终端输出信息,但当 boot loader 启动内核后却无法看到内核的启动输出信息。对这一问题的原因可以从以下几个方面来考虑:

(1) 首先请确认你的内核在编译时配置了对串口终端的支持,并配置了正确的串口驱动程序。

(2) 你的 boot loader 对串口的初始化设置可能会和内核对串口的初始化设置不一致。此外,对于诸如s3c44b0x 这样的 CPU,CPU 时钟频率的设置也会影响串口,因此如果 boot loader 和内核对其 CPU 时钟频率的设置不一致,也会使串口终端无法正确显示信息。

(3) 最后,还要确认 boot loader 所用的内核基地址必须和内核映像在编译时所用的运行基地址一致,尤其是对于 uClinux 而言。假设你的内核映像在编译时用的基地址是 0xc0008000,但你的 boot loader 却将它加载到 0xc0010000 处去执行,那么内核映像当然不能正确地执行了。

  1. 结束语

Boot Loader 的设计与实现是一个非常复杂的过程。如果不能从串口收到那激动人心的"uncompressing linux… done, booting the kernel……"内核启动信息,恐怕谁也不能说:“嗨,我的 boot loader 已经成功地转起来了!”。

根文件系统的作用 VSF的作用 Linux系统结构详解 加载内核映像和根文件系统映像相关推荐

  1. Linux系统结构 详解

    Linux系统结构 详解 标签: 产品产品设计googleapple互联网 2011-01-07 14:14 31038人阅读 评论(6) 收藏 举报 分类: Linux(21) 版权声明:本文为博主 ...

  2. Linux: 系统结构详解

    Linux系统一般有4个主要部分: 内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使用系统.部分层次结构如图1-1所 ...

  3. Linux 系统结构详解——新手上路

    Linux 系统结构详解 Linux系统一般有4个主要部分: 内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使用系统 ...

  4. Linux 系统结构详解

    Linux系统一般有4个主要部分: 内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使用系统.部分层次结构如图1-1所 ...

  5. Linux 系统结构详解,看这一篇就够了

    点击▲关注 "程序IT圈"   给公众号标星置顶 更多精彩 第一时间直达 作者:huangguisu 链接:https://dwz.cn/Jsc4V4Sz Linux系统一般有4个 ...

  6. Linux 系统结构详解,看这一篇就够了?(又一篇万字长文)

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 When one reaches a point of difficulty ...

  7. linux系统结构详解

    文章目录 Linux系统结构 Linux常⽤命令 Linux系统结构 经过学习了系统结构之后,我将自己所见到的知识点都整理起来,查缺补漏, 以下是我整理总结出的目录结构知识点: 以下是我找到得目录结构 ...

  8. Linux系统详解 系统的启动、登录、注销与开关机

    Linux系统详解 第六篇:系统的启动.登录.注销与开关机 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://johncai.blo ...

  9. c linux time微秒_学习linux,看这篇1.5w多字的linux命令详解(6小时讲明白Linux)

    用心分享,共同成长 没有什么比每天进步一点点更重要了 本篇文章主要讲解了一些linux常用命令,主要讲解模式是,命令介绍.命令参数格式.命令参数.命令常用参数示例.由于linux命令较多,我还特意选了 ...

  10. Linux使用详解(进阶篇)

    文章目录 Linux使用详解(进阶篇) 1.Linux目录说明 2.操作防火墙 3.ulimit命令和history命令 4.RPM和Yum的使用 5.设置系统字符集 6.vi & vim编辑 ...

最新文章

  1. 云服务器dns配置文件,linux服务器dns配置文件
  2. Golang sync.Map原理
  3. hdu 2222:Keywords Search
  4. javascript提取标签之间的信息
  5. 大数据打造你的变美频道——数加平台上小红唇的大数据实践
  6. 腾讯视频怎么禁止别人登录我的会员
  7. 安装hdfs集群的具体步骤
  8. 关于ajax请求controller返回中文乱码的解决方法!
  9. HLSL Effect的vertex shader和pixel shader的参数传递
  10. 小程序与H5如何混合开发及WEUI那些事
  11. 阿里云域名绑定IP手把手教学
  12. X006---交叉表(Cross Tab)和转置(Transpose)
  13. windows搭建php运行环境,Windows手动搭建PHP运行环境
  14. 学大伟业 Day 3 培训总结
  15. 关于RundownProtect到底是什么东西
  16. html2canvas导出照片样式乱,html2canvas生成图片(图片样式和显示样式不一致)
  17. 手把手带你爬取百度美女图片,Python练手项目!
  18. ASUS Vivobook archlinux声卡驱动
  19. BZOJ 3573 [HNOI2014]米特运输
  20. u盘引导 在SSD+HHD配置下安装ubuntu16.04

热门文章

  1. 知到计算机应用基础见面课答案,知到计算机应用基础(湖南环境生物职业技术学院)见面课答案...
  2. 天猫魔盘在ubuntu16.04中的使用
  3. linux下用c语言写吃金豆,吃金豆pacmanTC版
  4. 期货反跟单-镜像零滑点软件真有那么靠谱吗?
  5. 8 个经典的 HTML5 游戏及源码
  6. VMware12虚拟机安装教程
  7. win7开机提示由于系统注册表文件丢失或损坏因此无法加载怎么办
  8. MAC 青花瓷(Charles)爪机HTTPS 抓包
  9. 玩家浅谈MID平板电脑主流中端方案
  10. Discuz修改默认用户头像