注:以下驱动只是均以GEC6818开发板为例进行撰写
要想写驱动我们得先了解什么是u-boot
一、什么是u-boot ?
Boot,全称 Universal Boot Loader,是遵循GPL条款的开放源码项目。U-Boot的作用是系统引导。U-Boot从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是根据相应的Linux内核源程序进行简化而形成的,尤其是一些设备的驱动程序,这从U-Boot源码的注释中能体现这一点。
1)简单来说:Universal Boot Loader就是
Universal 通用
Boot 启动硬件 对硬件做初始化
阶段一: 初始化CPU 、 PLL、 SRAM/DDR3 、 emmc 、时钟频率…
阶段二: 液晶屏、按键、(触控屏)、网卡、串口…
Loader 加载,加载linux内核
U-Boot就是做这些事情的
2)http://ftp.denx.de/pub/u-boot/ 我们可以下载u-boot的源码
Arch 架构 Board 板级
3) 然后可以看到板级初始化函数(在u-boot的源码逆着main函数找的)
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
if (initcall_run_list(init_sequence_r))
}
init_sequence_r是个函数指针数组,其中一个函数是 run_main_loop,
里面调用了main_loop
/* We come here after U-Boot is initialised and ready to process commands */
void main_loop(void)
启动后的main_loop函数
Main_loop调用了main函数,有兴趣的可以往里面研究
4)接着我们用串口连上开发板与PC端,再打开SecureCRT 8.1,配置完后重启开发板
可以看到以下串口信息:(以下就是U-Boot执行时的调试信息)
working to aarch32 -------- 架构32位
waiting for pll change… -------- 等待时钟
Second Boot by Nexell Co. : Ver0.3.6 - Built on Jun 12 2015 20:06:08
NSIH : Ver0.0.xx
DDR3 POR Init Start 0 ------- 初始化DDR3
phy init
Lock value = 175
GATE CYC = 0x00000492
GATE CODE = 0x00000000
Read DQ = 0x08080808
Write DQ = 0x08080808
DDR3 Init Done! ------- 初始化DDR3完成
CCI Init!
Wakeup CPU Wakeup CPU 1234567
CPU Wakeup done! WFI is expected. — CPU (CPU0 CPU1 CPU2 CPU3 )
CPU0 is Master!
Loading from sdmmc…
Image Loading Done! --------- 从sdmmc 中加载Image镜像(kernel)
Launch to 0x0000000043C00000 ---- 放在内存0x0000000043C00000
U-Boot 2014.07 (Jan 08 2018 - 16:36:11) ----- u-boot 的版本
PLL : [0] = 800000000, [1] = 800000000, [2] = 780000000, [3] = 800000000 — 初始化时钟
(0) PLL1: CPU FCLK = 800000000, HCLK = 200000000 (G0)
(7) PLL1: CPU FCLK = 800000000, HCLK = 200000000 (G1)
(2) PLL3: MEM FCLK = 800000000, DCLK = 800000000, BCLK = 400000000, PCLK = 200000000
(1) PLL0: BUS BCLK = 400000000, PCLK = 200000000
(8) PLL0: CCI4 BCLK = 400000000, PCLK = 200000000
(3) PLL0: G3D BCLK = 400000000
(4) PLL0: CODA BCLK = 400000000, PCLK = 200000000
(5) PLL0: DISP BCLK = 400000000, PCLK = 200000000
(6) PLL0: HDMI PCLK = 133333333
I2C: ready — I2C总线
DRAM: 1 GiB ---- DDR3 1GB内存
Heap = 0x44000000~0x46000000 ----- 堆空间的初始化
Code = 0x43c00000~0x43c89248 ----- 代码段的初始化
GLD = 0x43bffeb8
GLBD = 0x43bffe68
SP = 0x43bffe68,0x43bffe48(CURR) ---- stack point
PC = 0x43c066f0 ---- 程序计数器
TAGS = 0x40000100
PAGE = 0x43c90000~0x43c9c000
MACH = [4330] ----- 机器号
VER = 0
BOARD= [GEC6818] ---- 板级
MMC: NXP DWMMC: 0, NXP DWMMC: 1, NXP DWMMC: 2 ---- 恩智浦mmc
In: serial — 输入设备是串口
Out: serial — 输出设备是串口
Err: serial — 错误输出设备是串口
DCDC_MODE(0x80): DCDC1[PFM], DCDC2[PFM], DCDC3[PFM], DCDC4[PWM], DCDC5[PWM]
STATUS(0x00) : 0xe4 0x10
IRQ(0x48) : 0x00 0x00 0x00 0x00 0x00 ---- 中断
CHG_TYPE : ADP 充电的类型 adaptor 充电器
BAT_VOL : 0mV 电池电压
BAT_CAP : 100% 电池容量
DONE: Logo bmp 300 by 300 (3bpp), len=270056 ----- 显示的u-boot Logo bmp 300 by 300pixel
DRAW: 0x47000000 -> 0x46000000
DONE: Logo bmp 300 by 300 (3bpp), len=270056
DRAW: 0x47000000 -> 0x46000000
RGB: display.0
MIPI: display.0
DSIM_ESCMODE 1 : 0xc0
DSIM_STATUS : 0x10010f
MIPI clk: 420MHz
DSIM_ESCMODE 2 : 0x0
DSIM_STATUS : 0x10010f
Skip BAT Animation.
IRQ(0x48) : 0x00 0x00 0x00 0x00 0x00
chg_type : ADP
battery_vol : 0mV
battery_cap : 100%
Booting
Card did not respond to voltage select!
Net: GEC6818 mac init… ------------------------- 初始化网卡
dwmac.c0060000
Hit any key to stop autoboot: 0 -------------3秒倒计时 按任意一个键就停止自动启动内核
GEC6818# --------------------- u-boot的命令行语句 ----》 说明u-boot支持命令行操作
5)如果串口没有输入按键,U-BOOT就会启动内核
Booting kernel from Legacy Image at 48000000 … 从0x48000000 取出内核镜像文件
Image Name: Linux-3.4.39-gec ---- 内核名称 Linux-3.4.39-内核版本
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 5540912 Bytes = 5.3 MiB ---- 内核大小
Load Address: 40008000 ------ 加载地址 0x40008000
Entry Point: 40008000
Verifying Checksum … OK — 对数据进行校验
Loading Kernel Image … OK ---- 从DDR3中加载内核的镜像
Starting kernel … ----- 内核启动
二、linux的内核
可以参考 linux 电子书《Linux内核设计与实现(第三版).pdf》
https://www.kernel.org/(内核下载地址)
内核主要就干了下面的事情
1、设备驱动和管理
3种设备 : 字符设备(如 /dev/fb0)
块设备(/dev/mmcblk0p2)
网络设备 (socket )
设备号、设备名
对应驱动安装、卸载、文件使用
2、内存管理
内存管理单元
虚拟内存
内存的申请、读写、释放
3、进程管理
进程如何被创建、排队、调度、消亡
进程的调用 最大限度使用CPU
4、网络管理
管理网卡、IP
5、解压rootfs
6、我们跳回到加载内核的串口信息中(以下只截了一部分)
1)初始化CPU
[ 0.000000] Booting Linux on physical CPU 0 ----- 在CPU0上启动linux
[ 0.000000] Initializing cgroup subsys cpu — 初始化CPU子系统
[ 0.000000] Linux version 3.4.39-gec (zr@boLe) (gcc version 4.8 (GCC) ) #14 SMP PREEMPT Fri Dec 15 10:48:48 CST 2017 — kernel的版本 gcc版本 内核镜像的生成时间
[ 0.000000] Initialized persistent memory from 635fc000-635fffff — 初始化memory
[ 0.000000] CPU : iomap[ 0]: p 0xc0000000 -> v 0xf0000000 len=0x300000
[ 0.000000] CPU : iomap[ 1]: p 0xe0000000 -> v 0xf0300000 len=0x100000
[ 0.000000] CPU : iomap[ 2]: p 0xfff00000 -> v 0xf0400000 len=0x100000
[ 0.000000] CPU : iomap[ 3]: p 0x2c000000 -> v 0xf0500000 len=0x100000
[ 0.000000] CPU : iomap[ 4]: p 0x00000000 -> v 0xf0600000 len=0x100000
[ 0.000000] CPU : DMA Zone Size =16M, CORE 8
[ 0.000000] GEC6818 : done board initialize … — 板级初始化cpu完成
[ 0.000000] PERCPU: Embedded 9 pages/cpu @c151e000 s12544 r8192 d16128 u36864
2)内核启动命令
[ 0.000000] Kernel command line: console=ttySAC0,115200n8 androidboot.hardware=GEC6818 androidboot.console=ttySAC0 androidboot.serialno=0123456789abcdef initrd=0x49000000,0x1000000 lcd=at070tn92 tp=ft5x06-linux root=/dev/mmcblk0p2 rw rootfstype=ext4 cam=OV5645
console=ttySAC0 ---- 控制台 ttySAC0 — serial
115200n8 串口配置 波特率是115200 数据位是8位 无奇偶校验
设置启动参数 androidboot.hardware=GEC6818 androidboot.console=ttySAC0 androidboot.serialno=0123456789abcdef
initrd=0x49000000,0x1000000 初始化的地址和长度
lcd=at070tn92 显示屏的型号
tp=ft5x06-linux Touch Panel 触控屏型号
root=/dev/mmcblk0p2 rw 根目录的设置在/dev/mmcblk0p2 有读写权限
rootfstype=ext4 ROOT File System根文件系统 类型为ext4
内核中支持的文件系统 cat /proc/filesystems
3)初始化内存
[ 0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes) — hash table 哈希表
[ 0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
[ 0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
[ 0.000000] allocated 2097152 bytes of page_cgroup
[ 0.000000] please try ‘cgroup_disable=memory’ option if you don’t want memory cgroups
[ 0.000000] Memory: 1024MB = 1024MB total --------内存1GB
[ 0.000000] Memory: 810792k/810792k available, 237784k reserved, 272384K highmem
目前可用810792k
[ 0.000000] Virtual kernel memory layout: 32位内核虚拟内存(4GB)的分配
0X0000 0000~~~ 0XFFFF FFFF 的地址值一共有 0x1 0000 0000 也就是只有4G地址
一个地址只能存放一个字节
[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB) — 向量
[ 0.000000] fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
[ 0.000000] vmalloc : 0xef800000 - 0xfee00000 ( 246 MB) ---- 虚拟映射
[ 0.000000] lowmem : 0xc0000000 - 0xef600000 ( 758 MB)
[ 0.000000] pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
[ 0.000000] modules : 0xbf000000 - 0xbfe00000 ( 14 MB) ---- 模块
[ 0.000000] .text : 0xc0008000 - 0xc0a561c8 (10553 kB) – 代码段
[ 0.000000] .init : 0xc0a57000 - 0xc0a94100 ( 245 kB) – 初始化段
[ 0.000000] .data : 0xc0a96000 - 0xc0b307b0 ( 618 kB) — 初始化的数据段 [ 0.000000] .bss : 0xc0b307d4 - 0xc0d10508 (1920 kB) — 未初始化的数据段
[ 0.000000] SLUB: Genslabs=11, HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
4)初始化GPIO
[ 0.000000] GPIO @f001c000: start 170, mask 0xffffffff (gpio 87)
[ 0.000000] GPIO @f001d000: start 202, mask 0xffffffff (gpio 88)
[ 0.000000] GPIO @f001e000: start 234, mask 0xffffffff (gpio 89)
[ 0.167000] gpiochip_add: registered GPIOs 0 to 31 on device: nxp-gpio.0
[ 0.167000] gpiochip_add: registered GPIOs 32 to 63 on device: nxp-gpio.1
[ 0.167000] gpiochip_add: registered GPIOs 64 to 95 on device: nxp-gpio.2
[ 0.167000] gpiochip_add: registered GPIOs 96 to 127 on device: nxp-gpio.3
[ 0.168000] gpiochip_add: registered GPIOs 128 to 159 on device: nxp-gpio.4
[ 0.168000] gpiochip_add: registered GPIOs 160 to 165 on device: nxp-gpio.5
5)配置CPU
[ 0.008000] Initializing cgroup subsys freezer
[ 0.008000] CPU: Testing write buffer coherency: ok
[ 0.008000] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.008000] hw perfevents: no hardware support available
[ 0.008000] Setting up static identity map for 0x40735d50 - 0x40735da8
[ 0.024000] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[ 0.038000] CPU2: thread -1, cpu 2, socket 0, mpidr 80000002
[ 0.052000] CPU3: thread -1, cpu 3, socket 0, mpidr 80000003
[ 0.066000] CPU4: thread -1, cpu 0, socket 4, mpidr 80040400
[ 0.079000] CPU5: thread -1, cpu 1, socket 4, mpidr 80040401
[ 0.092000] CPU6: thread -1, cpu 2, socket 4, mpidr 80040402
[ 0.105000] CPU7: thread -1, cpu 3, socket 4, mpidr 80040403
[ 0.105000] Brought up 8 CPUs
6)配置I2C
[ 0.175000] i2c-gpio i2c-gpio.0: using pins 99 (SDA) and 98 (SCL)
[ 0.175000] i2c-gpio i2c-gpio.1: using pins 101 (SDA) and 100 (SCL)
[ 0.176000] i2c-gpio i2c-gpio.3: using pins 80 (SDA) and 79 (SCL)
[ 0.177000] s3c-i2c s3c2440-i2c.2: i2c-2: S3C I2C adapter – I2C适配器
[ 0.177000] s3c-i2c s3c2440-i2c.2: slave address 0x10
[ 0.177000] s3c-i2c s3c2440-i2c.2: bus frequency set to 195 KHz
(100k~ 400kHz)
7)音视频接口
[ 0.178000] Linux media interface: v0.10
[ 0.178000] Linux video capture interface: v2.00
8) 电池
[ 0.189000] axp22_ldo1: 3000 mV
[ 0.194000] axp22_aldo1: 700 <–> 3300 mV at 3300 mV
[ 0.198000] axp22_aldo2: 700 <–> 3300 mV at 1800 mV
[ 0.203000] axp22_aldo3: 700 <–> 3300 mV at 1000 mV
[ 0.207000] axp22_dldo1: 700 <–> 3300 mV at 3300 mV
[ 0.209000] axp22_dldo2: No configuration
9)蓝牙
[ 0.276000] Bluetooth: Core ver 2.16
[ 0.276000] NET: Registered protocol family 31
[ 0.276000] Bluetooth: HCI device and connection manager initialized
[ 0.276000] Bluetooth: HCI socket layer initialized
[ 0.276000] Bluetooth: L2CAP socket layer initialized
[ 0.276000] Bluetooth: SCO socket layer initialized
10)网络
0.301000] TCP bind hash table entries: 65536 (order: 8, 1572864 bytes)
[ 0.302000] TCP: Hash tables configured (established 131072 bind 65536)
[ 0.302000] TCP: reno registered
[ 0.303000] UDP hash table entries: 512 (order: 3, 32768 bytes)
[ 0.303000] UDP-Lite hash table entries: 512 (order: 3, 32768 bytes)
[ 0.303000] NET: Registered protocol family 1
[ 0.304000] RPC: Registered named UNIX socket transport module.
[ 0.304000] RPC: Registered udp transport module.
[ 0.304000] RPC: Registered tcp transport module.
[ 0.304000] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 0.304000] Unpacking initramfs…
11)解压initramfs
[ 0.304000] Initramfs unpacking failed: junk in compressed archive 解压失败
[ 0.318000] Freeing initrd memory: 16384K 释放之前申请 16384K
12) LCD显示
[ 0.320000] Display LCD register operation
[ 0.320000] Display LVDS register operation
[ 0.320000] Display MiPi register operation
13)从kernel解压出根文件系统 并挂载mount
[ 3.917000] ALSA device list: — 音频
[ 3.919000] #0: I2S-alc5623
[ 3.922000] #1: SPDIF-Transciever
[ 3.939000] EXT4-fs (mmcblk0p2): recovery complete — EXT4 已经在mmc上的第0个block上第2页
[ 3.939000] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null) — 挂载
[ 3.943000] VFS: Mounted root (ext4 filesystem) on device 179:2.
虚拟文件系统被挂载到根目录中
mmc的主设备是179,次设备号是2
[ 3.948000] devtmpfs: mounted
[ 3.951000] Freeing init memory: 244K 释放刚才初始化占用的内存
[ 3.955000] Write protecting the kernel text section c0008000 - c0a20000
内核的.text 代码段加上写保护
[ 3.962000] rodata_test: attempting to write to read-only section:
[ 3.967000] write to read-only section trapped, success
[ 4.115000] EXT4-fs (mmcblk0p2): re-mounted. Opts: data=ordered
[ 4.453000] eth0: device MAC address fe:12:2e:88:00:76 网卡mac地址
[ 4.460000] stmmac_open: failed PTP initialisation
[ 4.470000] gecBt initialized
[ 4.677000] usbcore: registered new interface driver rtl8723bu
libpng warning: iCCP: known incorrect sRGB profile
[ 6.400000] irq = 147
[ 6.400000] irq = 134
[ 6.400000] irq = 168
[ 6.401000] irq = 169
到这里,整个u-boot加内核的初始化就讲完了,我们还需要研究一下根文件系统
三、根文件系统
根文件系统首先是内核启动时所mount的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行(在根文件系统挂载后会有一些初始化的脚本或者服务开始执行)
1)/IOT Internet Of Things
存放的是iot 可执行文件,对应的是粤嵌的APP
2)/etc
配置文件和启动脚本
3)/ linuxrc
lrwxrwxrwx 1 root root 11 Dec 27 2016 linuxrc -> bin/busybox
BusyBox 是一个集成了三百多个最常用Linux命令和工具的软件。BusyBox 包含了一些简单的工具,例如ls、cat和echo等等,还包含了一些更大、更复杂的工具,例grep、find、mount以及telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令,也包含了 Android 系统的自带的shell。
4)/bin binary 二进制shell命令集
/sbin system bin 管理员权限的二进制shell命令集
/usr/bin /usr/sbin 通常是开发者安装使用的二进制
系统默认的工作目录 $PATH
[root@GEC6818 /]#echo $PATH
/usr/local/Qt-Embedded-5.7.0/bin:/bin:/sbin:/usr/bin:/usr/sbin
5)/dev 设备文件 是给应用层来对具体设备通过vfs进行读写操作
6)/mnt 挂载点
7)/driver 驱动,给开发者放置驱动ko文件
8)/proc 进程管理文件 由内核管理
dr-xr-xr-x 98 root root 0 Jan 1 1970 proc
9)/root root用户的家目录
10)/sys 系统运行情况(驱动等) 由内核管理
dr-xr-xr-x 12 root root 0 Jan 1 00:30 sys
11)/var variable 可变数据 时刻发生变化的数据如log 记录运行情况