(四)根文件系统--从零开始自制linux掌上电脑(F1C200S)<嵌入式项目>

目录

一、根文件系统介绍

二、根文件系统移植

1、buildroot下载

2、根文件系统制作

3、根文件系统移植

4、根文件系统加载

5、mmc设备问题分析

6、mmc功能开启

7、设备树编译与下载

三、参考内容


一、根文件系统介绍

文件系统是对一个存储设备上的数据和元数据进行组织的机制,这种机制有利于用户和操作系统的交互。在Linux没有文件系统的话,用户和操作系统的交互也就断开了。

Unix没有盘符的概念,要求自己的文件系统是单一的一棵树。直接挂载在整棵树根上的那个盘里面的文件系统,就是根文件系统。

文件系统不是指某一个文件系统类型,而是指任何可以将文件目录组织成特定系统所需结构的文件系统,然后把它挂载在系统的上。

Linux中的根文件系统像是一个文件夹管理系统,或者说像是一本书的目录,在某种意义上讲,根文件系统就是一个文件夹,只不过是这是一个特殊的文件夹,在这个目录里面会有很多的子目录,如下图所示。

下面是虚拟机中Ubuntu系统的根文件系统,根文件系统的目录名字为 ‘/’ ,也就是一个斜杠,各个目录的功能在下面的表格中做了详细介绍。

ItemDescription
/ (root filesystem)根文件系统是文件系统的最高级别目录。在其他文件系统被挂载之前,它必须包含启动Linux系统所需的所有文件。它必须包括启动其余文件系统所需的所有可执行文件和库。在系统启动后,所有其他文件系统都被挂载在标准的、定义明确的挂载点上,作为根文件系统的子目录。
/bin/bin目录包含用户可执行文件。
/boot包含启动Linux计算机所需的静态引导程序和内核可执行文件以及配置文件。
/dev这个目录包含了连接到系统的每个硬件设备的设备文件。这些不是设备驱动程序,而是代表计算机上每个设备的文件,并为访问这些设备提供便利。
/etc包含主机的本地系统配置文件。
/home用户文件的主目录存储。每个用户都有一个/home的子目录。
/lib包含启动系统所需的共享库文件。
/media一个安装外部可移动媒体设备的地方,如可能连接到主机的USB拇指驱动器。
/mnt普通文件系统(如不是可移动媒体)的临时挂载点,可以在管理员修复或处理文件系统的时候使用。
/opt可选的文件,如供应商提供的应用程序应位于这里。
/root这不是根(/)文件系统。它是根用户的主目录。
/sbin系统二进制文件。这些是用于系统管理的可执行文件。
/tmp临时目录。由操作系统和许多程序用来存储临时文件。用户也可以在这里临时存储文件。请注意,存储在这里的文件可能在任何时候被删除,而无需事先通知。
/usr这些是可共享的、只读的文件,包括可执行的二进制文件和库、人文件和其他类型的文件。
/var可变的数据文件被存储在这里。这可以包括像日志文件、MySQL和其他数据库文件、网络服务器数据文件、电子邮件收件箱,以及更多的东西。

二、根文件系统移植

1、buildroot下载

我们使用buildroot制作根文件系统,之前imx6ull使用的busybox,这里换一下,哈哈,首先进入官网,下载根文件系统buildroot2018.2.11版本,与墨云保持一致,下载后放到Ubuntu中解压。https://buildroot.org/download.htmlhttps://buildroot.org/download.html

这个网站比较友好,不需要魔法,buildroot体积较小,直接下载即可,下面是几个不同后缀的文件。

 上面的四个选项,下载后是下面的文件,sign是什么文件我不清楚,嘿嘿,欢迎评论区指出,选择一个压缩包,到Ubuntu中解压

2、根文件系统制作

 解压完成后进入根目录,清理工程后,进入图形界面配置:

make clean
make menuconfig

图形配置界面如下图所示,使用方向键选择不同选项,空格进行选中,回车进行确认。

Target options选项的配置如下图所示,每个选项的含义墨云解释过了,我就不造轮子了。  

  • 第一个选项为架构选择,这里选择ARM架构小端模式,
  • 第二个为输出的二进制文件格式,这里选择EFL格式,
  • 第三个为架构体系,这里选择arm926t,因为F1C200S/F1C100S的架构就是这个架构,
  • 第四个为矢量浮点处理器,这里不勾选,因为对于F1C200S/F1C100S而言,其内部没有浮点运算单元,只能进行软浮点运算,也就是模拟浮点预运算。
  • 第五个为应用程序二进制接口,这里选择EABI,原因是该格式支持软件浮点和硬件实现浮点功能混用。
  • 第六个为浮点运算规则,这里使用软件浮点
  • 第七个选择指令集,这里选择ARM指令集,因为thumb主要针对Cortex M系列而言的,对于运行操作系统的A系列以及ARM9和ARM11而言,使用的都是32位的ARM指令集。

来自:小白自制Linux开发板 三. Linux内核与文件系统移植 - 淡墨青云 - 博客园

据说Toolchain按照下方配置(打开了一些功能)可以在开发板上直接编译程序。 

登录的时候会显示 “Wecome to kashine linux system.” ,并且我们设置了root用户密码为“good luck!”。

配置完成后,使用make命令进行编译,从下面可以看出,buildroot的编译需要网络支持,以通过网络配置我们选择的内容。 当然如果你的虚拟机无法连接网络,请看虚拟机ubuntu桥接怎么联网,或者是虚拟机net模式访问互联网

此处是漫长的等待..........,建议来一道力扣中等!复杂链表的复制!力扣https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/?envType=study-plan&id=lcof&plan=lcof&plan_progress=y16046r

这个下载速度真的是奇慢无比!如果下载依赖包或者软件速度非常慢,可以尝试(不要试了,我试过不管用,哈哈)Ubuntu20.04换源之后依旧慢?Ubuntu16.04找不到Software&Updates(软件更新),但我试了一下仍然很慢,这不科学呀!魔法也不管用。

终于编译完成了!已经是第二天了,昨天搞到1:00还没有编译完,我就直接挂起虚拟机,今天早晨打开Ubuntu没大会,就已经编译完成了,大概两个多小时。编译完成后,在buildroot根目录的output/images目录下生成一个rootfs.rar文件这个就是我们心心念念的根文件系统。

注意:第二次编译就会快很多,比如误删,别问我怎么知道的,唔哈哈哈。 

 3、根文件系统移植

将上面得到的rootfs.rar解压到TF卡的第二个分区,也就是rootfs分区,不要解压完成在复制过去,因为解压出来好多文件夹。两种选择,要么把压缩包复制到rootfs分区,解压后删除压缩包,要么直接解压到第二分区。使用如下命令将压缩包解压到rootfs分区后如下图所示:

sudo tar -vxf rootfs.tar -C /media/project01/rootfs/

其中tar解压缩命令格式如下:

选项含义
-x对 tar 包做解打包操作。
-f指定要解压的 tar 包的包名。
-t只查看 tar 包中有哪些文件或目录,不对 tar 包做解打包操作。
-C 目录指定解打包位置。
-v显示解打包的具体过程。

4、根文件系统加载

TF卡第二个分区内已经放置了我们制作好的根文件系统,将TF卡插到开发板上并上电启动,打开串口调试助手,设置波特率115200,可以看到下面的内容,uboot和内核启动成功。

但是并没有启动Linux的根文件系统,我们看最后打印出的提示代码为: Waiting for root device /dev/mmcblk0p2...,看来是mmcblk0p2表示mmc设备(MultiMedia Card,多媒体存储卡)没有被内核启动成功,mmcblk0是我们的TF卡,p2代表第二个分区,我们最终确定是mmc设备出了问题。

 5、mmc设备问题分析

我们先来分析一下出现这个问题的原因,如果说mmcblk0p2设备出现问题,那么为什么在启动Linux内核的时候没有出错的,内核文件和设备树文件存放在mmcblk0p1中,如果是mmcblk0p2加载出错,也就表示TF卡的设备树或者是驱动出了问题,那么mmcblk0p1不应该也是错的吗?那Linux内核不应该能够启动才对的?

小朋友,你是否有很多问号?好的,现在来说一下我对上面问题的理解。其实上面的问题有点不太对,不知道大家是否有相同的疑问,所以我对上面也进行了保留。下面分析:首先是uboot的启动,在TF卡的8k处,我们硬件没有问题,也就是说TF卡接在F1C200s的指定引脚,bootROM启动的时候一定会读取TF卡的8k位置,成功启动uboot,而在uboot启动后,进入倒计时,倒计时结束后,执行bootcmd命令,bootcmd命令如下所示:

load mmc 0:1 0x80008000 zImage;load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb;bootz 0x80008000 - 0x80c08000;

该命令的主要作用是将zImage和设备树从mmc的第一个分区拷贝到内存中执行,这个应该好理解哈,Linux内核启动成功了,说明uboot能够将两个文件拷贝到内存中执行,进一步说明uboot的TF卡驱动是没有问题的,拷贝结束后,uboot生命周期结束,Linux内核启动,但是Linux内核TF卡启动出错,导致无法加载TF卡第二分区中的根文件系统。

至此,我们大致分析出导致无法启动Linux根文件系统的原因是:TF卡设备树或者驱动出错。对于设备树来讲,我们只需要提供对应的硬件信息,即可在不同的开发板可以使用相同的驱动。形象一点讲就是:对某个LED点灯程序(驱动),我宏定义了一个LED管脚(设备树),程序是官方给的,也就是说确定这个程序可以点灯,现在我们将这套程序放到另一个相同主控的开发板上运行,出问题的话就很可能是我们的宏定义出错了,也就是说,很可能是设备树出错。

通过上面的分析,我们怀疑很可能是设备树出了问题那下面我们对设备树进行检查。首先介绍一下设备树相关文件,打开/arch/arm/boot/dts可以看到我们我们前面拷贝到TF卡KERNEL分区的设备树文件,其中.dtsi文件为“头文件”,储存一个主控芯片的共同信息,供针对相同主控芯片不同开发板的设备树源文件.dts文件调用,编译后生成设备树文件.dtb。

打开/arch/arm/boot/dts目录下的suniv-f1c100s-licheepi-nano.dts、suniv-f1c100s.dtsi,在dtsi文件中并没有发现mmc的内容,也就是如orange2c所说,是因为我们使用的主线Linux内核源码,而主线Linux设备树中并没有开启mmc。

6、mmc功能开启

参考荔枝派设备树源码,进行以下修改。首先添加头文件:

#include <dt-bindings/clock/suniv-ccu-f1c100s.h>
#include <dt-bindings/reset/suniv-ccu-f1c100s.h>

然后在soc结点下的pio添加如下代码,其中PF0、PF1、PF2、PF3、PF4、PF5为TF卡相关引脚,详见https://blog.csdn.net/qq_41709234/article/details/124389957

mmc0_pins: mmc0-pins {
                pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
                function = "mmc0";
            };

在soc结点下添加如下代码,使用pinctrl子系统初始化引脚,其中compatible变量保存着mmc对应的驱动。其他时钟总线之类的我就不详细解释了,因为我也不懂,哈哈。但是一定要注意,.dtsi文件里面是默认关闭mm功能的(可以看到下面的status是disabled状态),需要在.dts里面使能。

mmc0: mmc@1c0f000 {
            compatible = "allwinner,suniv-f1c100s-mmc",
                     "allwinner,sun7i-a20-mmc";
            reg = <0x01c0f000 0x1000>;
            clocks = <&ccu CLK_BUS_MMC0>,
                 <&ccu CLK_MMC0>,
                 <&ccu CLK_MMC0_OUTPUT>,
                 <&ccu CLK_MMC0_SAMPLE>;
            clock-names = "ahb",
                          "mmc",
                          "output",
                          "sample";
            resets = <&ccu RST_BUS_MMC0>;
            reset-names = "ahb";
            interrupts = <23>;
            pinctrl-names = "default";
            pinctrl-0 = <&mmc0_pins>;
            status = "disabled";
            #address-cells = <1>;
            #size-cells = <0>;
        };

 .dtsi文件修改完成后如下所示:

// SPDX-License-Identifier: (GPL-2.0+ OR X11)
/*
 * Copyright 2018 Icenowy Zheng <icenowy@aosc.io>
 * Copyright 2018 Mesih Kilinc <mesihkilinc@gmail.com>
 */

// modify by kashine
#include <dt-bindings/clock/suniv-ccu-f1c100s.h>
#include <dt-bindings/reset/suniv-ccu-f1c100s.h>

/ {
	#address-cells = <1>;
	#size-cells = <1>;
	interrupt-parent = <&intc>;

	clocks {
		osc24M: clk-24M {
			#clock-cells = <0>;
			compatible = "fixed-clock";
			clock-frequency = <24000000>;
			clock-output-names = "osc24M";
		};

		osc32k: clk-32k {
			#clock-cells = <0>;
			compatible = "fixed-clock";
			clock-frequency = <32768>;
			clock-output-names = "osc32k";
		};
	};

	cpus {
		cpu {
			compatible = "arm,arm926ej-s";
			device_type = "cpu";
		};
	};

	soc {
		compatible = "simple-bus";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		sram-controller@1c00000 {
			compatible = "allwinner,suniv-f1c100s-system-control",
				     "allwinner,sun4i-a10-system-control";
			reg = <0x01c00000 0x30>;
			#address-cells = <1>;
			#size-cells = <1>;
			ranges;

			sram_d: sram@10000 {
				compatible = "mmio-sram";
				reg = <0x00010000 0x1000>;
				#address-cells = <1>;
				#size-cells = <1>;
				ranges = <0 0x00010000 0x1000>;

				otg_sram: sram-section@0 {
					compatible = "allwinner,suniv-f1c100s-sram-d",
						     "allwinner,sun4i-a10-sram-d";
					reg = <0x0000 0x1000>;
					status = "disabled";
				};
			};
		};

		ccu: clock@1c20000 {
			compatible = "allwinner,suniv-f1c100s-ccu";
			reg = <0x01c20000 0x400>;
			clocks = <&osc24M>, <&osc32k>;
			clock-names = "hosc", "losc";
			#clock-cells = <1>;
			#reset-cells = <1>;
		};

		intc: interrupt-controller@1c20400 {
			compatible = "allwinner,suniv-f1c100s-ic";
			reg = <0x01c20400 0x400>;
			interrupt-controller;
			#interrupt-cells = <1>;
		};

		pio: pinctrl@1c20800 {
			compatible = "allwinner,suniv-f1c100s-pinctrl";
			reg = <0x01c20800 0x400>;
			interrupts = <38>, <39>, <40>;
			clocks = <&ccu 37>, <&osc24M>, <&osc32k>;
			clock-names = "apb", "hosc", "losc";
			gpio-controller;
			interrupt-controller;
			#interrupt-cells = <3>;
			#gpio-cells = <3>;

			uart0_pe_pins: uart0-pe-pins {
				pins = "PE0", "PE1";
				function = "uart0";
			};

			// modify by kashine
			mmc0_pins: mmc0-pins {
                pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
                function = "mmc0";
            };
		};

		timer@1c20c00 {
			compatible = "allwinner,suniv-f1c100s-timer";
			reg = <0x01c20c00 0x90>;
			interrupts = <13>;
			clocks = <&osc24M>;
		};

		wdt: watchdog@1c20ca0 {
			compatible = "allwinner,suniv-f1c100s-wdt",
				     "allwinner,sun4i-a10-wdt";
			reg = <0x01c20ca0 0x20>;
		};

		uart0: serial@1c25000 {
			compatible = "snps,dw-apb-uart";
			reg = <0x01c25000 0x400>;
			interrupts = <1>;
			reg-shift = <2>;
			reg-io-width = <4>;
			clocks = <&ccu 38>;
			resets = <&ccu 24>;
			status = "disabled";
		};

		uart1: serial@1c25400 {
			compatible = "snps,dw-apb-uart";
			reg = <0x01c25400 0x400>;
			interrupts = <2>;
			reg-shift = <2>;
			reg-io-width = <4>;
			clocks = <&ccu 39>;
			resets = <&ccu 25>;
			status = "disabled";
		};

		uart2: serial@1c25800 {
			compatible = "snps,dw-apb-uart";
			reg = <0x01c25800 0x400>;
			interrupts = <3>;
			reg-shift = <2>;
			reg-io-width = <4>;
			clocks = <&ccu 40>;
			resets = <&ccu 26>;
			status = "disabled";
		};

		// modify by kashine
		mmc0: mmc@1c0f000 {
            compatible = "allwinner,suniv-f1c100s-mmc",
                     "allwinner,sun7i-a20-mmc";
            reg = <0x01c0f000 0x1000>;
            clocks = <&ccu CLK_BUS_MMC0>,
                 <&ccu CLK_MMC0>,
                 <&ccu CLK_MMC0_OUTPUT>,
                 <&ccu CLK_MMC0_SAMPLE>;
            clock-names = "ahb",
                          "mmc",
                          "output",
                          "sample";
            resets = <&ccu RST_BUS_MMC0>;
            reset-names = "ahb";
            interrupts = <23>;
            pinctrl-names = "default";
            pinctrl-0 = <&mmc0_pins>;
            status = "disabled";
            #address-cells = <1>;
            #size-cells = <0>;
        };
	};
};

 在.dts文件里面进行以下修改,首先使能mmc:

&mmc0 {
        vmmc-supply = <&reg_vcc3v3>;
        bus-width = <4>;
        broken-cd;
        status = "okay";
};

然后这个是墨云在根节点下添加的一个结点,他并没有说明为什么添加,我百度了一下,这是一个电源管理相关的结点,使用regulator-fixed来实现使用GPIO控制某个电源开关 ,希望在开机时尽快输出高低电平来控制电源。详见。Rockchip RK3588 kernel dts解析之regulator-fixed

reg_vcc3v3: vcc3v3 {
        compatible = "regulator-fixed";
        regulator-name = "vcc3v3";
        regulator-min-microvolt = <3300000>;
        regulator-max-microvolt = <3300000>;
    };

.dts文件修改完成之后下所示:

// SPDX-License-Identifier: (GPL-2.0+ OR X11)
/*
 * Copyright 2018 Icenowy Zheng <icenowy@aosc.io>
 */

/dts-v1/;
#include "suniv-f1c100s.dtsi"

/ {
	model = "Lichee Pi Nano";
	compatible = "licheepi,licheepi-nano", "allwinner,suniv-f1c100s";

	aliases {
		serial0 = &uart0;
	};

	chosen {
		stdout-path = "serial0:115200n8";
	};
	
	// modify by kashine
	reg_vcc3v3: vcc3v3 {
		compatible = "regulator-fixed";
		regulator-name = "vcc3v3";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
	};
};

&uart0 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart0_pe_pins>;
	status = "okay";
};

// modify by kashine
&mmc0 {
        vmmc-supply = <&reg_vcc3v3>;
        bus-width = <4>;
        broken-cd;
        status = "okay";
};

7、设备树编译与下载

在Linux内核根目录下,使用以下命令重新编译设备树,内核无需重新编译。

make dtbs

在内核源码根目录使用make dtbs编译变成后生成设备树文件,如下图所示。

编译完成后,将新的设备树文件(.dtb)拷贝到TF卡的第二分区,zImage无需修改,打开串口调试助手,上电复位,成功启动根文件系统!!!,成功打印出“Welcome to kashine linux system.”,root为管理员用户名,密码为前面设置的“good luck!”,将路径切换到根目录之后,查看根目录的文件夹,如下图所示。

 在上电成功启动根文件系统之后,不要直接拔掉USB断电,可能造成根文件系统损坏,使用poweroff命令关闭根文件系统后断电。


三、参考内容

1. 墨云uboot移植

2. 正点原子《嵌入式Linux驱动开发指南》      


  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kashine

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值