Linux启动流程
驱动(程序) : 驱使设备行动的程序
1. 启动bootloader---引导操作系统启动的(裸机)程序,为操作系统启动准备环境,并引导操作系统启动
2. 启动kernel---操作系统核心 (俗称的操作系统)
3. 加载根文件系统---一堆文件的集合(根目录下的文件)
存储分类 | ||||
---|---|---|---|---|
RAM(随机存储) |
SRAM 静态 |
DRAM 动态 |
SDRAM 同步动态 |
SDR(DDR2345) |
ROM(只读存储) |
PROM 可编程 |
EPROM 可擦除 |
EEPROM 电子可擦除 |
Flash : 是RAM和ROM的结合体。具有速度快,掉电不丢失的特点
Norflash
: 可线性访问 (和内存访问方式相同)
Nandflash
:不可线性访问 (需要专门的软件访问)
地址相关代码:运行地址(加载地址)和链接地址必须保持一致
地址无关代码:运行地址(加载地址)和链接地址可以不同
长跳转(绝对跳转): 目标函数的跳转地址是固定的(绝对位置)
短跳转(相对跳转): 目标函数的跳转地址是可变的(相对位置)
Bootloader |
Kernel |
根文件系统:一堆文件的集合 |
uboot ------ booloader 初始 初始化异常向量表 初始化栈 初始化时钟 初始化内存 关看门狗 关闭 初始相关外设 集成相关的协议 搬移 向内核传参 置 ip/ 引导 (bootloader cpu |
内存管理 文件管理 进程管理 网络管理 设备管理 启动到最后阶段时加载 形式 先启动 |
配置文件 系统命令 库文件 用户程序 普通文件 |
Tftp:简单文件传输协议 将uImage拷贝到tftp服务目录下
Nfs:网络文件系统 将rootfs.tar.gz拷贝到nfs服务目录下,并加sudo解压
程序编译的过程:
预处理 编译 汇编 链接
main.c main.i main.s main.o mainapp
fun.c fun.o
gcc main.c fun.o -o mainapp
库:xxx.o的集合---归并
静态库 :会被编译进可执行程序 , 程序执行时不需要库文件
动态库 :不会被编译进可执行程序 , 程序执行时需要库文件 (编译和运行都需要库文件的存在)
动态库生成: gcc -fPIC -shared fun.c -o libfun.so
静态库生成: gcc -c fun.c -o fun.o
ar -rcv libfun.a fun.o
Uboot启动:
Norflash:NORFLASH被接在0地址处,系统上电后PC默认指向0地址,直接运行norflash中的uboot
Nandflash:
系统上电后自动搬移
uboot
的前
4KB
的程序到
IRAM
中
(IRAM
的起始地址
0x40000000
,大小
4KB)
,此时
PC(0
地址
)
被映射到0x40000000
地址处,
uboot
必须在前
4KB
程序中完成内存的初始化,并将自己剩余的部分搬移到内存继续执行。
Kernel:
Nandflash : uboot
直接搬移
nandflash
中的
uImage
到内存的
0x30008000
地址处,启动内核
远程主机(ubuntu): uboot通过tftp将ubuntu中的uImage下载到内存的0x30008000地址处,启动内核
Rootfs:
Nandflash :
内核启动到最后阶段时直接挂载到
nandflash
上
远程主机(ubuntu): 通过nfs挂载到ubuntu中的nfs目录下
内核编译:
选择模块进行编译------条件编译
Kconfig 定义 make menuconfig 中的配置选项
make menuconfig 可视化界面配置.config中的宏(内核活地图)
.config 保存内核的配置(保存的是选择条件的值)
Makefile:根据 .config 文件中的宏的值进行编译
同层目录下 Kconfig 和 makefile 总是成对出现
动态加载驱动模块:
编译内核模块:
1. 配置 make menuconfig 模块编译选项为M (Kconfig 中类型定义为 tristate)
2. make uImage (如果原来该模块为 y,则需要重新编译出不包含该模块的内核)------非必要
3. make modules 编译内核模块 在源文件同层目录下生成同名的内核模块 xxx.ko
4. 将编译生成的 xxx.ko 拷贝到目标平台
动态加载:
1. insmod led.ko 动态加载内核模块(类似于windows下安装一个新的驱动)
2. lsmod 查看动态加载的驱动模块
3. rmmod led 卸载动态加载的驱动模块
ADC模块驱动编译
#include <linux/init.h> #include <linux/kernel.h> #include <linux/kdev_t.h> #include <linux/fs.h> #include <linux/module.h> #include <linux/cdev.h> #include <asm/string.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/miscdevice.h> #include <linux/interrupt.h> #include <linux/irqreturn.h> #include <linux/wait.h> #include <linux/sched.h> #define MAJOR_NUM 251 #define MINOR_NUM 0 #define DEV_NAME "adc" #define ADCCON 0x58000000 #define ADCDAT0 0x5800000C #define CLKCON 0x4C00000C static volatile unsigned long * adccon; static volatile unsigned long * adcdat0; static volatile unsigned long * clkcon; static wait_queue_head_t wq; static unsigned int condition = 0; static irqreturn_t irq_handler(int num, void * arg) { printk("irq_handler num = %d ", num); condition = 1; wake_up_interruptible(&wq); return IRQ_HANDLED; } static int init_adc(void) { *adccon = (1 << 14) | (49 << 6); return 0; } static int adc_start(void) { *adccon |= (1 << 0); return 0; } static unsigned short adc_read(void) { unsigned short adc_value = *adcdat0 & 0x3ff; return adc_value; } static int open(struct inode * node, struct file * file) { init_adc(); printk("adc open ... "); return 0; } static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * loff) { unsigned short data = 0; printk("adc read start ... "); condition = 0; adc_start(); wait_event_interruptible(wq, condition); data = adc_read(); copy_to_user(buf, &data, sizeof(data)); printk("adc read end ... "); return sizeof(data); } static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * loff) { return 0; } static int close(struct inode * node, struct file * file) { printk("adc close ... "); return 0; } static struct file_operations fops = { .owner = THIS_MODULE, .open = open, .read = read, .write = write, .release = close }; static struct miscdevice misc_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEV_NAME, .fops = &fops }; static int __init adc_init(void) { int ret = 0; ret = misc_register(&misc_dev); if(ret < 0) goto err; ret = request_irq(IRQ_ADC, irq_handler, IRQF_DISABLED, "irq_adc", NULL); if(ret < 0) goto err_irq; init_waitqueue_head(&wq); adccon = ioremap(ADCCON, sizeof(adccon)); adcdat0 = ioremap(ADCDAT0, sizeof(adcdat0)); clkcon = ioremap(CLKCON, sizeof(clkcon)); *clkcon |= (1 << 15); printk("CLKCON = %lx ", *clkcon); printk("adc_init ############################### "); return 0; err: misc_deregister(&misc_dev); printk("adc cdev_add failed ret = %d ", ret); return ret; err_irq: disable_irq(IRQ_ADC); free_irq(IRQ_ADC, NULL); misc_deregister(&misc_dev); printk("adc cdev_add failed ret = %d ", ret); return ret; } static void __exit adc_exit(void) { iounmap(clkcon); iounmap(adcdat0); iounmap(adccon); disable_irq(IRQ_ADC); free_irq(IRQ_ADC, NULL); misc_deregister(&misc_dev); printk("adc_exit ############################### "); } module_init(adc_init); module_exit(adc_exit); MODULE_LICENSE("GPL");