本文主要是介绍Linux_kernel原理08,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、温故知新
系统移植
1、uboot
uboot主要做两件事:1、负责初始化硬件;2、负责引导操作系统的启动
2、Linux内核
Linux内核的五大功能
【1】进程间通信
【2】进程管理
【3】网络子系统
【4】虚拟文件子系统
【5】内存管理
3、根文件系统
当Linux内核启动之后需要执行1号进程(init进程)
1号进程对应的程序:cd ls cat touch cp。。。
使用busybox工具制作自己的根文件系统
4、开发板的烧写实验
1)对emmc分区(按扇区进行访问)
EMMC的大小(8G)
根据uboot的大小来分区
根据uImage的大小来分区
根据rootfs的大小来分区
mmc erase 0 0x100000
tdisk 2 3 0x100000:0x4000000 0x4100000:0x2f200000 0x33300000:0
0M 1M 65M 819M 剩余空间 字节0 0x100000 0x4100000 0x33300000 剩余空间 uboot uboot-uImage uImage-rootfs rootfs-app app 未分区 未分区-mmcblk0p1 mmcblk0p1-mmcblk0p2 mmcblk0p2-mmcblk0p3 mmcblk0p3
2)烧写uboot
cp ubootpak.bin /tftp_share/
tftp 0x48000000 ubootpak.bin
update_mmc 2 2ndboot 0x48000000 0x200 0x53ba8
注释:
0x200 = 512byte = 1个扇区
3)烧写uImage
cp uImage /tftp_share/
tftp 0x48000000 uImage
mmc write 0x48000000 0x800 0x3000
setenv bootcmd mmc read 48000000 800 3000 \; bootm 48000000
4)烧写rootfs
cp rootfs /tftp_share/
tftp 0x48000000 rootfs
mmc write 48000000 0x20800 0x32000
setenv bootargs root=/dev/mmcblk0p2 rootfstype=ext4 console=ttySAC0,115200 maxcpus=1 lcd=wy070ml tp=gslx680
5、通过nfs方式挂载根文件系统
[1]上位机安装nfs服务
sudo apt-get install nfs-kernel-server
[2]创建nfs共享目录
sudo mkdir /nfs_share
[3]修改nfs共享目录的权限
sudo chmod 777 /nfs_share
[4]把根文件系统解压缩到nfs共享目录
tar -xvf /nfs_share
[5]修改配置文件
sudo vim /etc/exports
/nfs_share/rootfs *(rw,sync,no_root_squash)
[6]修改服务文件
sudo vim /etc/default/nfs-kernel-server
[7]重启nfs服务
sudo service nfs-kernel-server restart
或
sudo /etc/init.d/nfs-kernel-server restart
[8]关闭防火墙
sudo service ufw stop
或
sudo /etc/init.d/ufw stop
[9]修改下位机的环境变量
setenv bootargs root=/dev/nfs nfsroot=192.168.1.8:/nfs_share/rootfs ip=192.168.1.6:192.168.1.8:192.168.1.1:255.255.255.0 init=/linuxrc
二、uboot的基本概念
1、通用的ubootloader
类似于PC机上的BIOS
【1】负责初始化硬件
【2】负责引导操作系统的启动
bootloader不属于操作系统内核的一部分,这部分的代码不具有可移植性,如我我们将来换了一块开发板,现在的uboot不一定可以直接使用。
通用的含义:
【1】:支持多种CPU架构:arm、mips、ppc、x86。。。
【2】:支持多种类型的操作系统:Linux、windows、vxworks、RTOS。。。
我们现在使用的就是支持ARM架构下Linux操作系统的bootloader
2、ubootpak.bin从何而来?
程序编译uboot源码得到ubootpak.bin
1)uboot
uboot是非常著名的开源软件,但原始包里有很多我们今后开发不一定用到的资源
官网:DENX Software Engineering – the Embedded Linux Experts
2)从上游厂商获取(从demo板中获取)
uboot.tar.gz
demo版本是芯片厂商提供的参考版本,可能方便使用,也可能不方便使用,所以我们需要做uboot开发的工程师进行修改或调试,让这个uboot可以在我们的开发板上完美的运行。
3)获取并编译uboot源码
/*将源码拷贝至实验目录*/
cp /mnt/hgfs/easthome_porting/uboot.tar.gz ~/S5p6818/
/*解压源码*/
tar -xvf uboot.tar.gz
cd uboot
/*获取最干净的uboot源码*/
make distclean
/*获取uboot编译的配置文件*/
make x6818_config
/*对源码进行编译*/
make
4)修改uboot命令行的提示符
vim uboot/include/configs/x6818.h
#define CONFIG_SYS_PROMPT "zjd#"
5)修改默认ip配置
vim uboot/include/configs/x6818.h
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.6
#define CONFIG_SERVERIP 192.168.1.8
#define CONFIG_GATEWAYIP 192.168.1.1
3、uboot源码的目录结构
uboot的目录大致分为3类
【1】与处理器体系结构或者开发板硬件直接相关
【2】一些通用的函数或驱动程序
【3】是uboot的应用程序\工具\文档
1)api (应用程序编程接口) | 独立于体系架构之外的功能函数接口,一般是uboot本身使用的,uboot在移植的时候基本不用动。 |
2)arch(Architecture) 体系架构 | 包含了特定的处理器架构的代码,如:ARM、PPC、MIPS、X86等 arch/arm 在arch目录下现在只剩下arm了,已经被上游厂商裁剪过了。 arch/arm/cpu:存放了和cpu紧密相关的内容 arch/arm/cpu/slsiap:存放了三星公司的工程内容 arch/arm/cpu/slsiap/s5p6818:有关s5p6818芯片的内容 |
3)board开发板相关的配置文件 | 存放与开发板相关的代码,如:初始化脚本、设备树等 |
4)common通用的 | 包含大多数uboot的代码使用的通用函数 主要是两类:1、实现uboot的命令;2、实现环境变量 |
5)disk硬盘 | 提供硬盘驱动的位置,用于文件系统的读写操作 |
6)doc文档 | 包含uboot的文档 |
7)drivers驱动 | 包含各种设备的驱动程序,如:网络驱动程序\显示驱动程序。。。 存放的是从Linux内核源码中拷贝过来的Linux设备驱动 主要是uboot在启动时所支持的硬件的驱动 其实uboot在一定程度上移植了Linux驱动 |
8)dts设备树 | 提供设备树工具 |
9)examples示例代码 | 提供了一些示例代码,如:使用uboot的命令,使用uboot的API |
a)fs文件系统 | 里面存放了支持的文件系统类型 |
b)include头文件 | 里面存放了各种常用函数的头文件 |
c)lib库 | 里面存放了各种常用函数的实现 |
d)net有关网络 | 包含网络相关的代码,如:nfs、tftp |
e)post上电自检 | 属于硬件自检的操作 |
f)scripts | 包含用于编译uboot的脚本 |
g)test测试 | 提供测试代码,用于验证uboot的功能 |
h)tools工具 | 包含用于处理uboot镜像的工具 |
我们可以将uboot认为是一个巨大无比的裸板程序,几乎在uboot的每一级目录下都有一个makefile文件,决定了当前目录下,哪些文件参与编译,哪些不参与编译,那些需要重新编译。 uboot/common/Makefile |
4、找到uboot的入口点文件
C程序的启动与终止
【1】内核通过exec——族函数调用C启动例程
【2】C启动例程再调用main函数,进程开始运行
【3】main函数return就返回到了C启动例程
【4】C启动例程需要调用exit(3)函数
注意:C启动例程不能直接返回给内核
【5】exit(3)再调用_exit(2)或者_Exit(2)函数返回给内核进程才会结束
注意:内核预留的终止进程的函数结构是_exit(2)或_Exit(2)
【6】exit(3)函数在调用_exit(2)或_Exit(2)函数之前还会调用其他的函数接口,比如标准IO的清理程序(清缓冲区)
1) 查找源码的入口点文件(法一)
gcc -v // 查看gcc版本
make -v // 查看make版本
arm-cortex_a9-linux-gnueabi-gcc -v // 查看交叉编译工具链版本
make V=1 // V=1将编译链接的详细过程展示出来
/*查看最后的链接*/
arm-cortex_a9-linux-gnueabi-ld.bfd -pie --gc-sections -Bstatic -Ttext 0x43C00000 -o u-boot -T u-boot.lds arch/arm/cpu/slsiap/start.o
/*这里的start.o是.c文件还是.s文件*/
/*是.s文件,因为在初始化硬件初期时,内存没有被初始化,不能是.c文件,由此确定*/
/*入口点文件是start.S文件*/
2) 查找源码的入口点文件(法二)
/*通过查看链接脚本文件,确定入口点*/
vim uboot/u-boot.lds //连接脚本
/*文件内容*/
arch/arm/cpu/slsiap/s5p6818/start.o 入口点目标文件
arch/arm/cpu/slsiap/s5p6818/start.S 入口点文件
/*发现于法一的结果不同,以链接脚本文件为准,由此确定*/
/*入口点文件是arch/arm/cpu/slsiap/s5p6818/start.S文件*/
5、uboot的执行流程
【1】vim arch/arm/cpu/slsiap/s5p6818/start.S
【2】设置cpu为SVC管理模式
【3】关闭看门狗
【4】禁止L1 L2缓存,关闭MMU内存管理单元
关闭MMU内存管理单元的目的:要使用物理地址
【5】回到被调用的位置
【6】跳转到cpu_init_crit
【7】跳转到lowlevel_init
【8】vim arch/arm/cpu/slsiap/s5p6818/low_init.S
【9】跳转到clear_bss
【10】先打开MMU内存管理单元,再清除bss段
打开MMU内存管理单元的目的:可以使用虚拟地址,MMU在不断的更新物理地址和虚拟地址的映射
【11】跳转到board_init_f
【12】vim arch/arm/lib/board.c
【13】board_init_f(重要!!!)
它完成了一系列硬件的初始化
如:cpu、uart、display、env。。。
init_fnc_ptr:指向各硬件初始化函数的指针
init_sequence:一个函数指针数组,包含着各硬件初始化函数的入口地址
经过一边循环,就可以对所有保存在数组里的硬件进行初始化
【14】跳转到board_init_r
【15】vim arch/arm/lib/board.c
【16】board_init_r(重要!!!)
它指定堆栈的区域,对EMMC进行初始化
【17】main_loop()可以返回自动引导,如果已经引导了,那就再引导一次
【18】cli_loop()
【19】cli_simple_loop()
6、总结
1)uboot的执行流程
【1】设置cpu为svc管理模式
【2】关闭看门狗,防止系统复位重启
【3】禁止L1 L2缓存,以及关闭MMU,使用物理地址
【4】检验CPU-ID是否合法,防止不法厂商
【5】清除BSS段
【6】打开MMU,使用虚拟地址
【7】跳转到board_init_f初始化硬件(关键!!!)
【8】跳转到board_init_r指定堆栈区域,初始化EMMC(关键!!!)
【9】main_loop
【a】cli_loop
【b】cli_simple_loop
2)修改默认配置
include/config/x6818.h
【a】波特率
【b】命令行提示符
【c】各种环境变量
三、uboot中添加启动logo
我们可以在所有的显示类设备增加一个启动logo(商业行为)
LCD、OLED、段码屏、数码管、点阵屏、LED灯、水立方
1、显示原理
2、图像的构成
图像是由一个一个像素点构成
三原色
16位色:RGB565
32位色:RGB888【0~255】(前8位保留)
红色:0x00FF0000
绿色:0x0000FF00
蓝色:0x000000FF
白色:0xFFFFFFFF
黑色:0x00000000
3、LCD的分辨率
7寸的LCD液晶显示屏
lcd的分辨率 1024 * 600
lcd的显存地址是由三星公司规定的0x46000000
vim uboot/include/configs/x6818.h
计算lcd对应点的地址P0(x0, y0)
/*将P0点设置为红色*/
*(volatile unsigned int *)(0x46000000 + ((y0 * 1024) + x0) * 4) = 0x00FF000000
4、将图片转换为RGB
工具位置:easthome_poriting\u-boot-logo\tools\Image2Lcd\Img2Lcd.exe
5、实验步骤
1】将生成的子模文件拷贝至uboot目录
cp logo.c uboot/common
2】编写画点及画logo的函数
vim uboot/common/draw_logo.c
#define LCD_BASE 0x46000000 #define WIDTH 1024 #define HIGHT 600 #define X0 0 #define Y0 0 #define LOGO_W 1024 #define LOGO_H 600extern const unsigned char gImage_logo[];void draw_pixel(int row, int col, int color) {*(int *)(LCD_BASE + ((row * WIDTH) + col) * 4) = color; }void lcd_draw_logo(void) {int i = 0, j = 0;unsigned int blue = 0;unsigned int green = 0;unsigned int red = 0;unsigned int color = 0;const unsigned char *p = gImage_logo;for(i = Y0; i < (Y0 + LOGO_H); i++) {for(j = X0; j < (X0 + LOGO_W); j++) {blue = *p++;green = *p++;red = *p++;color = red << 16 | green << 8 | blue;draw_pixel(i, j, color);}}}
3】添加调用画logo的函数
vim uboot/arch/arm/cpu/slsiap/common/cmd_draw_logo.c
4】修改Makefile文件
vim uboot/common/Makefile
5】编译uboot
1]make distclean
2]make x6818_config
3]make
6】烧写uboot
1]上位机把新生成的ubootpak.bin文件拷贝到tftp共享目录中
cp ubootpak.bin /tftpboot
2]下位机下载uboot
tftp 48000000 ubootpak.bin
3]更新emmc
update_mmc 2 2ndboot 48000000 200 [下载的字节数]
4]重启uboot
re
这篇关于Linux_kernel原理08的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!