系统移植三

一、设备树

  • 设备树(Device Tree)是 Linux 系统中用于描述硬件信息的一种机制,尤其在 ARM 平台上广泛使用。
  • 在早期版本的 Linux(如 2.6 及之前),设备的硬件信息通常是通过硬编码方式写在平台相关的文件中。这种方式给维护和扩展带来了很大麻烦,尤其是对于那些支持众多嵌入式平台的内核代码而言,几乎每个开发板都需要独立的板级支持代码,造成了内核代码的臃肿。
  • Linux2.6版本之前没有设备树
  • 从 Linux 3.0 开始,设备树引入到内核中,作为一种描述硬件的方法。设备树将板级的硬件描述从内核代码中分离出来,以一种结构化的方式定义硬件信息,并使得内核代码对硬件的依赖性大大减少。
  • 设备树文件路径:设备树文件通常位于 arch/arm/boot/dts/ 目录下,文件名格式为 xxxxxx.dts,例如 exynos4412-origen.dts。

1. 主要作用

  1. 设备树的主要作用是将硬件信息从内核代码中分离出来,使得内核变得更加通用,支持更多硬件时无需修改内核源码。设备树文件可以描述硬件的各种属性,比如:
  • 寄存器地址(register addresses):设备在系统中的物理地址。
  • 中断号(interrupt numbers):设备所使用的中断信息。
  • 时钟源(clock sources):设备所依赖的时钟。
  • GPIO 配置:设备所使用的 GPIO 管脚。
  • 其他硬件属性:如 DMA 通道、设备型号等。
  1. 设备树文件是用一种层次化的结构来表示硬件的信息,以树形结构表示不同设备和其相关的属性。设备树可以很方便地被驱动程序使用,使驱动能够正确地访问和控制硬件。

2. 文件结构

  • 设备树文件(.dts)使用一种类 C 的语法描述硬件。设备树文件的扩展名为 .dts,而编译后的二进制文件称为设备树 blob(.dtb),它会被内核在启动时加载并解析。
  • 设备树文件的构成类似于类 C 语言的结构,通过节点和属性来描述系统中的硬件。每一个节点代表一个硬件设备或子系统,属性则描述该设备的具体配置(如寄存器地址、中断号等)。
  • 设备树的基本元素
    • 节点(Node):节点可以理解为设备或子系统,通常对应硬件中的某个设备。
    • 属性(Property):属性用于描述节点的一些具体信息,如地址、名称、功能等。
  • 节点和属性的关系:
    设备树是由节点和属性共同组成的。节点可以包含子节点,形成树形结构;属性则是节点的具体描述信息。
  • 示例:描述一所大学的设备树
/ {
    university = "重庆高等大学";  // 根节点,描述学校
    address = "重庆大足区xxx村235号";  // 属性:学校地址
    established_year = <5>;  // 属性:学校成立年份
    president_name = "张校长";  // 属性:校长姓名

    president {  // 子节点:校长
        name = "张XX";
        title = "副教授";
        age = <56>;
        gender = "女";
    };

    college_of_electronics {  // 子节点:电子信息与自动化学院
        name = "电子信息和自动化学院";

        class_info_1 {  // 子节点:信息1班
            class_name = "信息1班";

            monitor {  // 子节点:班长
                name = "小李";
                age = <18>;
                gender = "男";
            };

            student_xiaowang {  // 子节点:小王
                name = "小王";
                age = <19>;
                gender = "男";
            };
        };

        class_info_2 {  // 子节点:信息2班
            monitor {
                name = "班长";
            };
        };
    };

    college_of_broadcasting {  // 子节点:广播电视学院
        class_1 {
            // 广播1班信息
        };
        class_2 {
            // 广播2班信息
        };
    };
};

  • 设备树结构说明
    • 根节点 /:设备树的根节点,所有硬件描述都在这个节点下。类似于学校的根节点,描述学校的基本信息(地址、校长等)。
    • 节点(Node):每个节点代表系统中的一个设备或子系统,类似于大学中的一个学院(如电子信息与自动化学院)。节点可以包含多个子节点。
    • 属性(Property):属性是节点的具体描述,如设备的地址、中断号等。属性是以 key = value 的形式出现的,类似于描述学校的地址、校长的姓名等。
  • 公有属性和私有属性
    • 公有属性
      • 公有属性指的是可以在多个节点中共享的属性。例如,姓名(name)、年龄(age)、地址(address)等是所有学生、老师等节点中都可能会存在的公有属性
      • 在设备树中,诸如寄存器地址、设备兼容性(compatible)等信息通常属于公有属性。
    • 私有属性
      • 私有属性是仅在特定节点中存在的属性。例如,校长的职称(title)、年薪等信息是校长独有的属性,其他节点不会拥有这些属性。
      • 在设备树中,特定硬件设备的专有属性,如时钟源、特殊功能标志,通常属于私有属性

3. 设备树在硬件描述中的应用

在实际硬件中,设备树文件通常用于描述各种硬件设备的配置信息

gpio@11400000 {
    compatible = "samsung,exynos4412-gpio";  // 描述与该设备兼容的驱动
    reg = <0x11400000 0x1000>;  // 描述 GPIO 控制器的寄存器地址
    interrupts = <0 1 4>;  // 定义 GPIO 使用的中断号
};

i2c@13860000 {
    compatible = "samsung,exynos4-i2c";  // I2C 控制器的兼容性描述
    reg = <0x13860000 0x100>;  // I2C 寄存器地址和大小
    interrupts = <14>;  // I2C 使用的中断号
    status = "okay";  // 设备状态,表示设备启用
};
//gpio@11400000:该节点描述了一个 GPIO 控制器,地址为 0x11400000,大小为 0x1000。
//compatible:这个属性描述该设备与哪些驱动兼容。驱动程序会根据这个属性来匹配硬件设备。
//reg = <寄存器起始地址, 寄存器空间长度>:寄存器地址,表示设备的物理地址范围。
//interrupts = <中断号, 触发方式>:定义设备使用的中断号。
//status="okay"/"disabled";	使能该节点/禁止该节点
//interrupt-parent:属性指定中断控制器的父节点,表示当前设备的中断由哪个中断控制器管理。

4. 设备树的编译与加载

设备树文件(.dts)在使用前需要编译为二进制格式(.dtb),并由内核加载。

  1. 编译
dtc -I dts -O dtb -o exynos4412-fs4412.dtb exynos4412-fs4412.dts//手动不推荐
推荐如下
# 编译所有设备树文件
make dtbs ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
# 编译你指定的 exynos4412-fs4412.dtb 文件
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- arch/arm/boot/dts/exynos4412-fs4412.dtb

  1. 加载
    设备树文件在内核启动时加载。内核通过 U-Boot 等引导加载程序将设备树二进制文件传递给内核
tftp 0x41000000 uImage
tftp 0x42000000 exynos4412-fs4412.dtb
bootm 0x41000000 - 0x42000000

文件系统

  • 在 Linux 中,文件系统是系统最原始的用户与硬件交互界面。Linux 系统中采用了一种抽象机制:一切皆文件。换句话说,系统中的每个硬件设备、进程、内核信息等都被抽象为文件,用户和应用程序通过访问这些文件的方式来与硬件和系统进行交互。
普通文件与目录
  1. /bin:
    存放基本的系统命令,所有用户都可以使用这些命令,例如 ls、cp、mv 等。
  2. /sbin:
    存放系统管理员使用的系统命令,通常只有 root 用户可以执行的命令,例如 ifconfig、reboot 等。
  3. /etc:
    存放系统的配置文件,包括用户信息、网络设置、服务启动脚本等。例如 /etc/passwd(用户信息)、/etc/hostname(主机名)。
  4. /linuxrc:
    在某些嵌入式 Linux 系统中,linuxrc 是在系统启动时的初始化程序,指向启动脚本或可执行文件。
  5. /mnt:
    Linux 中推荐的挂载点目录,通常用于临时挂载文件系统。例如,可以将 USB 设备或远程文件系统挂载到 /mnt/usb。
  6. /usr:
    usr 代表 Unix System Resources,是用户级的文件系统,存放用户的二进制程序和库文件。
    • /usr/bin:用户可以执行的命令和工具。
    • /usr/sbin:系统管理员执行的命令和工具。
    • 以后所有的个人文件、第三方工具都建议放在 /usr 下。
  7. /lib:
    存放系统库文件,包括 C 标准库、C++ 标准库、线程库等。这些库为系统中的应用程序和命令提供支持。
  8. /lost+found:
    文件系统检查时,系统会将修复的孤立文件放在这个目录中。通常在 ext4 文件系统中出现。
  9. /var:
    存放可变数据,例如日志文件、临时文件、缓存数据等。
    • /var/log:系统日志文件存放目录。
    • /var/tmp:系统的临时文件夹,用于存放临时文件,系统重启后不一定清空。
  10. /tmp:
    存放临时文件的目录,系统重启后会清空其中的内容。程序的临时缓存文件通常会放在这个目录中。
特殊文件

特殊文件包括内存文件系统和硬件设备文件,通常映射到内核数据或硬件设备,访问这些文件等同于与内核或硬件直接交互。

  1. /proc - 内存文件系统:
    /proc 是 Linux 系统中的虚拟文件系统,存放与系统和进程状态相关的信息。/proc 中的文件实际上并不占据磁盘空间,而是由内核动态生成,内容是系统的实时信息。访问 /proc 中的文件,可以获取系统状态和硬件信息。

    • 常见的 /proc 文件:
      • cmdline:系统启动时传递给内核的命令行参数,通常与 bootargs 相关。
      • cpuinfo:记录当前 CPU 的信息,如处理器型号、频率、核数等。
      • device-tree:描述设备树信息,驱动程序会根据设备树信息进行设备初始化。
      • devices:列出系统中所有注册的设备信息。
      • diskstats:提供磁盘的 I/O 统计信息。
      • interrupts:列出内核的中断处理统计信息,包括中断号和处理的次数。
      • meminfo:显示系统的内存使用情况,例如总内存、可用内存、缓存等。
      • partitions:显示磁盘分区的信息。
      • uptime:系统的运行时间和负载信息。
      • 进程目录:每个进程都会有一个以其 PID 命名的目录,里面包含该进程的状态、内存、打开的文件描述符等信息。
  2. /dev - 设备文件系统:
    /dev 目录是设备文件系统,所有硬件设备在 Linux 系统中都会映射为一个文件,用户通过读写这些文件来操作硬件。例如:

    • /dev/sda:表示第一个硬盘。
    • /dev/ttyS0:表示第一个串口设备。
    • /dev/null:表示虚拟的“黑洞”,写入的数据都会被丢弃。
    • /dev/zero:提供无限的零数据输出。
    • /dev/random:提供随机数生成设备。
      每个设备文件都有主设备号和次设备号,主设备号标识设备类型,次设备号标识设备的具体实例。
  3. /sys - 设备与驱动信息系统:

  • /sys 是另一个虚拟文件系统,存放系统中设备和驱动的信息。与 /proc 类似,/sys 中的文件也并不占用实际的磁盘空间,而是由内核动态生成。
  • /sys 主要用于内核与用户空间之间的交互,用户和应用程序可以通过修改 /sys 中的文件来配置设备。
文件系统的核心理念:一切皆文件

在 Linux 中,一切皆文件 是核心理念。硬件设备、内存信息、进程状态等都通过文件系统进行抽象,统一为文件的形式提供给用户和应用程序。

如何操作硬件?

硬件设备在 Linux 系统中被抽象为文件,用户可以通过标准的文件操作(如打开、读取、写入、关闭等)与硬件进行交互。
1. 读取硬件设备: 例如,通过 cat /proc/cpuinfo 可以获取当前系统 CPU 的信息,或者通过 cat /dev/ttyS0 读取串口设备的数据。
2. 写入硬件设备: 通过向设备文件写入数据来控制设备,例如向 /dev/led 写入控制信号可以点亮或关闭 LED。
3. 设备节点: 每个设备文件都有其主设备号和次设备号,主设备号用于标识设备的类型,次设备号用于标识同一类型的不同设备实例。通过 mknod 命令可以手动创建设备节点。
在这里插入图片描述

开机启动过程

Linux 系统的启动过程是一个复杂的过程,从启动内核到启动第一个用户进程,再到执行用户定义的初始化脚本,最后完成系统启动。以下是对 开机启动过程 的详细补充与完善。

1. Linux 启动后内核的初始化
  1. 内核加载
    • 当系统启动时,首先加载 Linux 内核。内核会初始化硬件设备、加载必要的驱动程序,并准备好启动用户空间进程。
  2. 启动第一个用户进程
    • 在内核完成初始化后,内核会启动第一个用户进程,也就是 init 进程(PID=1)。
    • init 是系统的第一个用户进程,负责启动其他所有用户空间的进程。它是所有进程的祖先。
2. init 进程的工作

init 进程 的主要作用是根据配置文件执行一系列的系统初始化任务。传统的 Linux 系统使用 /sbin/init 作为初始化进程,通常会读取 /etc/inittab 配置文件,执行里面定义的初始化任务。

2.1 读取 /etc/inittab 文件

init 进程在启动后,会读取 /etc/inittab 文件,根据文件中定义的行为执行相应的操作。

/etc/inittab 文件示例

# 系统初始化时执行的任务
::sysinit:/etc/init.d/rcS               # 系统初始化时执行 /etc/init.d/rcS 脚本

# 终端相关的任务
::respawn:-/bin/sh                      # 在终端 respawn /bin/sh,允许重新登录 shell

# 重启相关的任务
::restart:/sbin/init                    # 当重启 init 进程时,重新运行 /sbin/init

# 按下 Ctrl+Alt+Del 时执行的任务
::ctrlaltdel:/sbin/reboot               # 按下 Ctrl+Alt+Del 时执行 /sbin/reboot

2.2inittab 文件的解释
  • sysinit:这个标志告诉 init 进程在系统初始化时要执行的操作。在上面的示例中,/etc/init.d/rcS 是在系统启动时执行的脚本。
  • respawn:指定当某个进程结束时是否重新启动该进程。这里 respawn /bin/sh 表示在终端上启动 shell,且 shell 结束后会重新启动。
  • restart:指定当 init 进程重新启动时要执行的操作。
  • ctrlaltdel:定义按下 Ctrl + Alt + Del 键组合时执行的命令。在上面的示例中,按下组合键会执行 /sbin/reboot,即系统重启。
2.3 init 进程的主要任务

init 进程在系统启动时做了以下几个重要任务:

  1. 系统初始化:
    执行 /etc/init.d/rcS 脚本,完成系统的基础初始化任务,如挂载文件系统、启动虚拟内存、加载系统守护进程等。
  2. 启动登录进程:
    init 进程会在系统的每个终端上启动一个 getty 进程,等待用户登录。用户登录后,getty 会启动一个 login 进程处理用户的登录请求。
  3. 响应重启与关机事件:
    init 还会监控系统的事件,例如用户按下 Ctrl + Alt + Del 键组合时触发的重启命令,或者系统发出的关机请求。
3. 如何开机启动某个程序
  • 可以通过修改系统的初始化脚本,来实现开机启动自定义程序。通常,系统在启动时会执行 /etc/init.d/rcS 脚本,所有初始化任务和服务都在这个脚本中启动。

  • 具体步骤

    1. 打开 /etc/init.d/rcS 脚本
    sudo vi /etc/init.d/rcS
    
    
    1. 添加自定义程序到脚本中
      • 在脚本的尾部添加你希望开机启动的程序。例如,如果你想启动一个叫 my_program 的可执行文件,你可以添加如下行
    /path/to/my_program &
    //确保在程序执行后加上 &,表示在后台执行该程序。
    
    1. 保存并退出
      保存文件并退出编辑器。
    2. 使脚本可执行(如果需要):
      确保脚本具有可执行权限
    sudo chmod +x /etc/init.d/rcS
    
    
    1. 验证程序开机启动
      重启系统后,程序会随着系统启动自动执行。
总结
  1. 系统启动:系统加载内核,内核初始化硬件设备,并启动第一个用户进程 init。

  2. 读取 inittab 文件:init 进程读取 /etc/inittab 文件,执行里面定义的初始化任务。

  3. 执行 rcS 脚本:init 进程执行 /etc/init.d/rcS 脚本,完成系统的初始化操作,包括挂载文件系统、启动关键服务等。

  4. 用户程序启动:通过将自定义程序加入 /etc/init.d/rcS 脚本的尾部,系统在启动时会自动运行该程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值