├── 数码相框项目 ├── 字符编码方式 │ ├── utf-8.txt │ ├── ansi.txt │ ├── 字体文件内容.JPG │ ├── 字符编码注意事项.jpg │ ├── unicodebe.txt │ ├── unicodele.txt │ ├── utf-8编码规则.JPG │ └── 字符编码方式.md └── 系统框架 │ ├── 需求.JPG │ ├── 输入进程.JPG │ ├── 显示图片方式.JPG │ ├── 系统框架总结.jpg │ └── 项目完成步骤.JPG ├── ultraedit使用 └── ultraedit使用.md ├── 2.GPIO实验 ├── 目标.PNG ├── 点亮LED.PNG └── GPIO.md ├── 7. 硬件电路图 ├── 硬件分类.JPG └── 硬件电路图分类.md ├── 8. 软件与硬件初始化 ├── 初始化.JPG ├── nand启动.JPG ├── 强制转换解释.JPG ├── 程序执行步骤.JPG ├── main的调用与返回.JPG ├── 清零和置位的常见操作方式.JPG ├── NOR启动和Nand启动的区别.JPG └── 8. 软件与硬件初始化.md ├── 16. LCD实验 ├── 帧内存和视口.JPG ├── 调色板的作用.JPG ├── 2440与lcd的关系.JPG └── LCD实验.md ├── 9. 存储控制器 ├── 存储控制器作用.JPG ├── SDRAM的结构图.JPG ├── 访问一个芯片需要的条件.JPG ├── s3c2440的程序启动方式.JPG ├── s3c2440和内存芯片的连接方式.JPG ├── s3c2440的内存地址总线连接方式.JPG ├── 程序从Steppingstone到SDRAM的执行过程.JPG └── 存储控制器.md ├── 汇编指令图片笔记 ├── 参数传递规则例子.JPG ├── ldm和stm命令.JPG └── ldr和str命令.JPG ├── 链接脚本代码解释 ├── 链接脚本代码解析.JPG └── 链接脚本代码解析.md ├── 12. 中断控制器 ├── 中断控制器图片笔记 │ ├── 怎么用中断.JPG │ ├── 中断执行过程.JPG │ ├── ARM的7种中断模式.JPG │ ├── 程序状态寄存器格式.JPG │ └── ARM状态下各工作模式使用的寄存器.JPG └── 12.1 中断控制器.md ├── 18. 移植u-boot ├── Makefile分析步骤.JPG ├── u-boot编译过程.JPG ├── u-boot的目录结构说明.JPG ├── U-Boot顶层目录的层次结构.JPG ├── u-boot启动内核图片笔记 │ ├── 分区.JPG │ ├── u-boot启动内核原理分析.JPG │ ├── 启动内核分析各个TAG的作用.JPG │ └── do_bootm_linux的作用.JPG ├── bootloader与内核的交互方式.jpg ├── u-boot要成功启动内核需要实现的功能列表.JPG ├── windows和linux系统启动过程的对比.JPG ├── u-boot命令图片笔记 │ └── u-boot命令图解.JPG ├── u-boot要成功启动内核需要实现的功能列表2.JPG ├── u-boot分析之源码阶段图片笔记 │ ├── sub 与 栈.JPG │ ├── u-boot的核心.JPG │ ├── boot启动内核具体方式.JPG │ ├── u-boot内存使用情况.JPG │ ├── u-boot启动的第一阶段.JPG │ ├── u-boot启动的第二阶段.JPG │ └── u-boot源码分析--条件.JPG ├── u-boot分析之源码阶段.md ├── u-boot分析之u-boot命令.md ├── u-boot分析之u-boot启动内核.md └── u-boot分析之编译体验.md ├── 3.JZ2440的jlink烧写方式 ├── 程序测试.PNG ├── uboot烧写选择.PNG ├── JZ2440开发板JLINK使用手册V1.0版本.pdf └── 烧写方式总结.md ├── bootloader编写步骤 ├── code │ ├── 1th │ │ ├── boot.o │ │ ├── init.o │ │ ├── start.o │ │ ├── boot.bin │ │ ├── boot.elf │ │ ├── boot.lds │ │ ├── Makefile │ │ ├── 1th-question │ │ ├── start.S │ │ ├── boot.c │ │ ├── init.c │ │ └── setup.h │ └── 2th-改进版 │ │ ├── boot.o │ │ ├── init.o │ │ ├── boot.bin │ │ ├── boot.elf │ │ ├── start.o │ │ ├── boot.lds │ │ ├── Makefile │ │ ├── start.S │ │ ├── boot.c │ │ ├── init.c │ │ └── setup.h └── bootloader编写图片笔记 │ ├── ICACHE理解.JPG │ ├── 设置参数列表分析.png │ └── len向四取整的理解.JPG ├── 1.嵌入式编程基础知识 ├── 1.6 gcc命令选项.md ├── 1.3 windows和linux开发程序的区别.PNG ├── 1.4 windows和linux开发程序的区别2.PNG ├── 1.5 leds.lds和makefile规则介绍 │ ├── makefile对比图.png │ ├── makefile规则.PNG │ ├── makefile规则2.PNG │ ├── make_clean虚拟命令.png │ ├── 通配符写法的makefile.png │ ├── makefile中把链接(link)和编译(compile)分开.PNG │ └── 1.5 leds.lds和makefile介绍.md ├── 嵌入式面试题汇总 │ └── 面试题.md ├── 1.2 makefile.md └── 1.1交叉编译工具选项说明.md ├── 21. 字符设备驱动程序 ├── 字符设备驱动程序图片笔记 │ ├── 驱动与应用.JPG │ ├── 字符设备驱动程序框架.JPG │ ├── 字符设备驱动程序概念.JPG │ ├── linux软件系统层次结构.JPG │ ├── 应用程序的open如何实现内核的open的操作的过程解析.JPG │ └── 第一个驱动程序--open--write驱动框架分析过程.JPG ├── 驱动led灯开与闭的程序例子 │ ├── first_drv.c │ ├── Makefile │ └── firstdrvtest.c ├── 第一个驱动程序例子 --open--write │ ├── first_drv.c │ ├── Makefile │ └── firstdrvtest.c ├── 第二个驱动程序例子 --mdev检测系统信息自动创建硬件设备 │ ├── first_drv.c │ ├── Makefile │ └── firstdrvtest.c ├── 21.2 点LED灯的驱动程序分析.md └── 字符设备驱动程序之基本概念.md ├── 13. 系统时钟和定时器 ├── 系统时钟和定时器图片笔记 │ ├── PLL启动过程.JPG │ └── FCLK-HCLK-PCLK的区别.JPG └── 13.1 系统时钟和定时器.md ├── 10. 内存管理单元MMU ├── 内存管理单元MMU图片笔记 │ ├── MMU实际使用例子.JPG │ ├── MMU的地址映射作用.JPG │ ├── mmu.bin存放地址.JPG │ ├── mmu的虚拟地址和物理地址的映射设置.JPG │ ├── 程序复制代码,设置页表、启动MMU的执行过程.JPG │ └── cpu--MMU--存储管理器--SDRAM关系图.JPG └── 10.1 内存管理单元MMU.md ├── 19. 移植linux内核 ├── linux内核启动图片笔记 │ ├── 内核要处理的参数.JPG │ ├── 内核第二阶段启动流程.JPG │ └── ARM的linux内核启动过程.JPG ├── linux内核移植编译图片笔记 │ ├── 各个符号的意义.JPG │ ├── 怎样编译文件.JPG │ ├── 内核移植编译步骤.JPG │ ├── 内核配置的具体过程.JPG │ ├── linux内核子目录结构.JPG │ ├── 怎样连接文件及顺序特点.JPG │ ├── kernel官网各标记符意义.JPG │ ├── linux内核源码层次结构.JPG │ ├── linux内核Makefile文件分类.JPG │ ├── linux内核的Makefile总结.JPG │ └── 内核启动流程之Makefile的作用.JPG ├── 19.4 修改内核以支持S3C2440开发板.md ├── 19.3 内核Kconfig分析.md └── sourceinsight分析内核代码.md ├── 11. Nand flash控制器 ├── Nand flash图片笔记 │ ├── 不同的寻址方式.JPG │ ├── 读地址操作图片解释.JPG │ ├── Nand flash结构.JPG │ ├── s3c2440访问Nand flash.JPG │ └── 从nand那里读取led代码进SDRAM中并启动.JPG └── Nand flash控制器.md ├── 20. 构建根文件系统 ├── 构建文件系统之启动第一个程序图片笔记 │ ├── init程序解析.JPG │ ├── 根文件系统分析总结.JPG │ ├── fstab的格式说明.JPG │ ├── init程序的工作原理.JPG │ ├── 构建根文件系统之启动第一个程序的步骤.JPG │ └── 构造配置文件(没有配置文件的时候).JPG ├── 20.4 修改MTD分区.md ├── busybox.md ├── 构建根文件系统.md └── 20.3 创建完整的根文件系统.md ├── 4. 通过tftp、nfs进行uboot下载烧写步骤详情 ├── tftpboot设置.JPG ├── 可以挂载的目录设置.JPG ├── u-boot的菜单栏操作1.JPG ├── 设置IP并进行程序的下载操作.JPG └── 通过tftp、nfs进行uboot下载烧写步骤详情.md ├── 配置文件宏分类.md ├── 0. 单板和主机间传输文件的方式.md ├── 5. u-boot、linux内核打补丁、编译以及sourceinsight的使用说明 └── u-boot、linux内核打补丁、编译以及sourceinsight的使用说明.md ├── 汇编指令.md └── 6. 通过nfs进行下载烧写--配置NFS网络文件系统的挂载卸载--制作镜像文件--虚拟机和开发板的交叉编译操作(通过MFS共享目录 └── 通过nfs进行下载烧写--配置NFS网络文件系统的挂载卸载--制作镜像文件--虚拟机和开发板的交叉编译操作(通过MFS共享目录.md /数码相框项目/字符编码方式/utf-8.txt: -------------------------------------------------------------------------------- 1 | abc中 -------------------------------------------------------------------------------- /ultraedit使用/ultraedit使用.md: -------------------------------------------------------------------------------- 1 | ## ultraedit使用 (2018.1.4) 2 | 1. ctrl+ h : 可以切换成hex格式显示 -------------------------------------------------------------------------------- /2.GPIO实验/目标.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/2.GPIO实验/目标.PNG -------------------------------------------------------------------------------- /2.GPIO实验/点亮LED.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/2.GPIO实验/点亮LED.PNG -------------------------------------------------------------------------------- /7. 硬件电路图/硬件分类.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/7. 硬件电路图/硬件分类.JPG -------------------------------------------------------------------------------- /8. 软件与硬件初始化/初始化.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/8. 软件与硬件初始化/初始化.JPG -------------------------------------------------------------------------------- /数码相框项目/系统框架/需求.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/系统框架/需求.JPG -------------------------------------------------------------------------------- /16. LCD实验/帧内存和视口.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/16. LCD实验/帧内存和视口.JPG -------------------------------------------------------------------------------- /16. LCD实验/调色板的作用.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/16. LCD实验/调色板的作用.JPG -------------------------------------------------------------------------------- /9. 存储控制器/存储控制器作用.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/9. 存储控制器/存储控制器作用.JPG -------------------------------------------------------------------------------- /数码相框项目/系统框架/输入进程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/系统框架/输入进程.JPG -------------------------------------------------------------------------------- /汇编指令图片笔记/参数传递规则例子.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/汇编指令图片笔记/参数传递规则例子.JPG -------------------------------------------------------------------------------- /链接脚本代码解释/链接脚本代码解析.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/链接脚本代码解释/链接脚本代码解析.JPG -------------------------------------------------------------------------------- /8. 软件与硬件初始化/nand启动.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/8. 软件与硬件初始化/nand启动.JPG -------------------------------------------------------------------------------- /8. 软件与硬件初始化/强制转换解释.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/8. 软件与硬件初始化/强制转换解释.JPG -------------------------------------------------------------------------------- /8. 软件与硬件初始化/程序执行步骤.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/8. 软件与硬件初始化/程序执行步骤.JPG -------------------------------------------------------------------------------- /9. 存储控制器/SDRAM的结构图.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/9. 存储控制器/SDRAM的结构图.JPG -------------------------------------------------------------------------------- /9. 存储控制器/访问一个芯片需要的条件.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/9. 存储控制器/访问一个芯片需要的条件.JPG -------------------------------------------------------------------------------- /数码相框项目/字符编码方式/ansi.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/字符编码方式/ansi.txt -------------------------------------------------------------------------------- /数码相框项目/字符编码方式/字体文件内容.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/字符编码方式/字体文件内容.JPG -------------------------------------------------------------------------------- /数码相框项目/系统框架/显示图片方式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/系统框架/显示图片方式.JPG -------------------------------------------------------------------------------- /数码相框项目/系统框架/系统框架总结.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/系统框架/系统框架总结.jpg -------------------------------------------------------------------------------- /数码相框项目/系统框架/项目完成步骤.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/系统框架/项目完成步骤.JPG -------------------------------------------------------------------------------- /汇编指令图片笔记/ldm和stm命令.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/汇编指令图片笔记/ldm和stm命令.JPG -------------------------------------------------------------------------------- /汇编指令图片笔记/ldr和str命令.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/汇编指令图片笔记/ldr和str命令.JPG -------------------------------------------------------------------------------- /16. LCD实验/2440与lcd的关系.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/16. LCD实验/2440与lcd的关系.JPG -------------------------------------------------------------------------------- /8. 软件与硬件初始化/main的调用与返回.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/8. 软件与硬件初始化/main的调用与返回.JPG -------------------------------------------------------------------------------- /数码相框项目/字符编码方式/字符编码注意事项.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/字符编码方式/字符编码注意事项.jpg -------------------------------------------------------------------------------- /12. 中断控制器/中断控制器图片笔记/怎么用中断.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/12. 中断控制器/中断控制器图片笔记/怎么用中断.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/Makefile分析步骤.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/Makefile分析步骤.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot编译过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot编译过程.JPG -------------------------------------------------------------------------------- /3.JZ2440的jlink烧写方式/程序测试.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/3.JZ2440的jlink烧写方式/程序测试.PNG -------------------------------------------------------------------------------- /8. 软件与硬件初始化/清零和置位的常见操作方式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/8. 软件与硬件初始化/清零和置位的常见操作方式.JPG -------------------------------------------------------------------------------- /9. 存储控制器/s3c2440的程序启动方式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/9. 存储控制器/s3c2440的程序启动方式.JPG -------------------------------------------------------------------------------- /数码相框项目/字符编码方式/unicodebe.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/字符编码方式/unicodebe.txt -------------------------------------------------------------------------------- /数码相框项目/字符编码方式/unicodele.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/字符编码方式/unicodele.txt -------------------------------------------------------------------------------- /数码相框项目/字符编码方式/utf-8编码规则.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/数码相框项目/字符编码方式/utf-8编码规则.JPG -------------------------------------------------------------------------------- /12. 中断控制器/中断控制器图片笔记/中断执行过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/12. 中断控制器/中断控制器图片笔记/中断执行过程.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot的目录结构说明.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot的目录结构说明.JPG -------------------------------------------------------------------------------- /8. 软件与硬件初始化/NOR启动和Nand启动的区别.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/8. 软件与硬件初始化/NOR启动和Nand启动的区别.JPG -------------------------------------------------------------------------------- /9. 存储控制器/s3c2440和内存芯片的连接方式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/9. 存储控制器/s3c2440和内存芯片的连接方式.JPG -------------------------------------------------------------------------------- /9. 存储控制器/s3c2440的内存地址总线连接方式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/9. 存储控制器/s3c2440的内存地址总线连接方式.JPG -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/boot.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/1th/boot.o -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/init.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/1th/init.o -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/start.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/1th/start.o -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.6 gcc命令选项.md: -------------------------------------------------------------------------------- 1 | ## 1.6 gcc命令选项 (2017.11.20) 2 | * gcc编译出来的是主机的程序 arm-linux-gcc编译出来的是开发板上的程序 3 | 1. `-c` : `编译不链接` -------------------------------------------------------------------------------- /12. 中断控制器/中断控制器图片笔记/ARM的7种中断模式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/12. 中断控制器/中断控制器图片笔记/ARM的7种中断模式.JPG -------------------------------------------------------------------------------- /12. 中断控制器/中断控制器图片笔记/程序状态寄存器格式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/12. 中断控制器/中断控制器图片笔记/程序状态寄存器格式.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/U-Boot顶层目录的层次结构.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/U-Boot顶层目录的层次结构.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot启动内核图片笔记/分区.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot启动内核图片笔记/分区.JPG -------------------------------------------------------------------------------- /3.JZ2440的jlink烧写方式/uboot烧写选择.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/3.JZ2440的jlink烧写方式/uboot烧写选择.PNG -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/boot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/1th/boot.bin -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/boot.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/1th/boot.elf -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/boot.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/2th-改进版/boot.o -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/init.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/2th-改进版/init.o -------------------------------------------------------------------------------- /18. 移植u-boot/bootloader与内核的交互方式.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/bootloader与内核的交互方式.jpg -------------------------------------------------------------------------------- /21. 字符设备驱动程序/字符设备驱动程序图片笔记/驱动与应用.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/字符设备驱动程序图片笔记/驱动与应用.JPG -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/boot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/2th-改进版/boot.bin -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/boot.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/2th-改进版/boot.elf -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/start.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/code/2th-改进版/start.o -------------------------------------------------------------------------------- /13. 系统时钟和定时器/系统时钟和定时器图片笔记/PLL启动过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/13. 系统时钟和定时器/系统时钟和定时器图片笔记/PLL启动过程.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot要成功启动内核需要实现的功能列表.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot要成功启动内核需要实现的功能列表.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/windows和linux系统启动过程的对比.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/windows和linux系统启动过程的对比.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/驱动led灯开与闭的程序例子/first_drv.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/驱动led灯开与闭的程序例子/first_drv.c -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.3 windows和linux开发程序的区别.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.3 windows和linux开发程序的区别.PNG -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.4 windows和linux开发程序的区别2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.4 windows和linux开发程序的区别2.PNG -------------------------------------------------------------------------------- /10. 内存管理单元MMU/内存管理单元MMU图片笔记/MMU实际使用例子.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/10. 内存管理单元MMU/内存管理单元MMU图片笔记/MMU实际使用例子.JPG -------------------------------------------------------------------------------- /12. 中断控制器/中断控制器图片笔记/ARM状态下各工作模式使用的寄存器.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/12. 中断控制器/中断控制器图片笔记/ARM状态下各工作模式使用的寄存器.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot命令图片笔记/u-boot命令图解.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot命令图片笔记/u-boot命令图解.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot要成功启动内核需要实现的功能列表2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot要成功启动内核需要实现的功能列表2.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核启动图片笔记/内核要处理的参数.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核启动图片笔记/内核要处理的参数.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/各个符号的意义.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/各个符号的意义.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/怎样编译文件.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/怎样编译文件.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/字符设备驱动程序图片笔记/字符设备驱动程序框架.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/字符设备驱动程序图片笔记/字符设备驱动程序框架.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/字符设备驱动程序图片笔记/字符设备驱动程序概念.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/字符设备驱动程序图片笔记/字符设备驱动程序概念.JPG -------------------------------------------------------------------------------- /9. 存储控制器/程序从Steppingstone到SDRAM的执行过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/9. 存储控制器/程序从Steppingstone到SDRAM的执行过程.JPG -------------------------------------------------------------------------------- /10. 内存管理单元MMU/内存管理单元MMU图片笔记/MMU的地址映射作用.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/10. 内存管理单元MMU/内存管理单元MMU图片笔记/MMU的地址映射作用.JPG -------------------------------------------------------------------------------- /10. 内存管理单元MMU/内存管理单元MMU图片笔记/mmu.bin存放地址.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/10. 内存管理单元MMU/内存管理单元MMU图片笔记/mmu.bin存放地址.JPG -------------------------------------------------------------------------------- /11. Nand flash控制器/Nand flash图片笔记/不同的寻址方式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/11. Nand flash控制器/Nand flash图片笔记/不同的寻址方式.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段图片笔记/sub 与 栈.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot分析之源码阶段图片笔记/sub 与 栈.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot的核心.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot的核心.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核启动图片笔记/内核第二阶段启动流程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核启动图片笔记/内核第二阶段启动流程.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/内核移植编译步骤.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/内核移植编译步骤.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/内核配置的具体过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/内核配置的具体过程.JPG -------------------------------------------------------------------------------- /20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/init程序解析.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/init程序解析.JPG -------------------------------------------------------------------------------- /20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/根文件系统分析总结.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/根文件系统分析总结.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/字符设备驱动程序图片笔记/linux软件系统层次结构.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/字符设备驱动程序图片笔记/linux软件系统层次结构.JPG -------------------------------------------------------------------------------- /4. 通过tftp、nfs进行uboot下载烧写步骤详情/tftpboot设置.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/4. 通过tftp、nfs进行uboot下载烧写步骤详情/tftpboot设置.JPG -------------------------------------------------------------------------------- /4. 通过tftp、nfs进行uboot下载烧写步骤详情/可以挂载的目录设置.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/4. 通过tftp、nfs进行uboot下载烧写步骤详情/可以挂载的目录设置.JPG -------------------------------------------------------------------------------- /bootloader编写步骤/bootloader编写图片笔记/ICACHE理解.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/bootloader编写图片笔记/ICACHE理解.JPG -------------------------------------------------------------------------------- /bootloader编写步骤/bootloader编写图片笔记/设置参数列表分析.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/bootloader编写图片笔记/设置参数列表分析.png -------------------------------------------------------------------------------- /11. Nand flash控制器/Nand flash图片笔记/读地址操作图片解释.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/11. Nand flash控制器/Nand flash图片笔记/读地址操作图片解释.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot启动内核图片笔记/u-boot启动内核原理分析.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot启动内核图片笔记/u-boot启动内核原理分析.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot启动内核图片笔记/启动内核分析各个TAG的作用.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot启动内核图片笔记/启动内核分析各个TAG的作用.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/linux内核子目录结构.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/linux内核子目录结构.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/怎样连接文件及顺序特点.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/怎样连接文件及顺序特点.JPG -------------------------------------------------------------------------------- /20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/fstab的格式说明.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/fstab的格式说明.JPG -------------------------------------------------------------------------------- /20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/init程序的工作原理.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/init程序的工作原理.JPG -------------------------------------------------------------------------------- /4. 通过tftp、nfs进行uboot下载烧写步骤详情/u-boot的菜单栏操作1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/4. 通过tftp、nfs进行uboot下载烧写步骤详情/u-boot的菜单栏操作1.JPG -------------------------------------------------------------------------------- /bootloader编写步骤/bootloader编写图片笔记/len向四取整的理解.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/bootloader编写步骤/bootloader编写图片笔记/len向四取整的理解.JPG -------------------------------------------------------------------------------- /11. Nand flash控制器/Nand flash图片笔记/Nand flash结构.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/11. Nand flash控制器/Nand flash图片笔记/Nand flash结构.JPG -------------------------------------------------------------------------------- /13. 系统时钟和定时器/系统时钟和定时器图片笔记/FCLK-HCLK-PCLK的区别.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/13. 系统时钟和定时器/系统时钟和定时器图片笔记/FCLK-HCLK-PCLK的区别.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段图片笔记/boot启动内核具体方式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot分析之源码阶段图片笔记/boot启动内核具体方式.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot内存使用情况.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot内存使用情况.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot启动的第一阶段.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot启动的第一阶段.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot启动的第二阶段.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot启动的第二阶段.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot源码分析--条件.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot分析之源码阶段图片笔记/u-boot源码分析--条件.JPG -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot启动内核图片笔记/do_bootm_linux的作用.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/18. 移植u-boot/u-boot启动内核图片笔记/do_bootm_linux的作用.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核启动图片笔记/ARM的linux内核启动过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核启动图片笔记/ARM的linux内核启动过程.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/kernel官网各标记符意义.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/kernel官网各标记符意义.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/linux内核源码层次结构.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/linux内核源码层次结构.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/第一个驱动程序例子 --open--write/first_drv.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/第一个驱动程序例子 --open--write/first_drv.c -------------------------------------------------------------------------------- /3.JZ2440的jlink烧写方式/JZ2440开发板JLINK使用手册V1.0版本.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/3.JZ2440的jlink烧写方式/JZ2440开发板JLINK使用手册V1.0版本.pdf -------------------------------------------------------------------------------- /4. 通过tftp、nfs进行uboot下载烧写步骤详情/设置IP并进行程序的下载操作.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/4. 通过tftp、nfs进行uboot下载烧写步骤详情/设置IP并进行程序的下载操作.JPG -------------------------------------------------------------------------------- /10. 内存管理单元MMU/内存管理单元MMU图片笔记/mmu的虚拟地址和物理地址的映射设置.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/10. 内存管理单元MMU/内存管理单元MMU图片笔记/mmu的虚拟地址和物理地址的映射设置.JPG -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile对比图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile对比图.png -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile规则.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile规则.PNG -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile规则2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile规则2.PNG -------------------------------------------------------------------------------- /10. 内存管理单元MMU/内存管理单元MMU图片笔记/程序复制代码,设置页表、启动MMU的执行过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/10. 内存管理单元MMU/内存管理单元MMU图片笔记/程序复制代码,设置页表、启动MMU的执行过程.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/linux内核Makefile文件分类.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/linux内核Makefile文件分类.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/linux内核的Makefile总结.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/linux内核的Makefile总结.JPG -------------------------------------------------------------------------------- /19. 移植linux内核/linux内核移植编译图片笔记/内核启动流程之Makefile的作用.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/19. 移植linux内核/linux内核移植编译图片笔记/内核启动流程之Makefile的作用.JPG -------------------------------------------------------------------------------- /20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/构建根文件系统之启动第一个程序的步骤.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/构建根文件系统之启动第一个程序的步骤.JPG -------------------------------------------------------------------------------- /20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/构造配置文件(没有配置文件的时候).JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/20. 构建根文件系统/构建文件系统之启动第一个程序图片笔记/构造配置文件(没有配置文件的时候).JPG -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/make_clean虚拟命令.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/make_clean虚拟命令.png -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/通配符写法的makefile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/通配符写法的makefile.png -------------------------------------------------------------------------------- /11. Nand flash控制器/Nand flash图片笔记/s3c2440访问Nand flash.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/11. Nand flash控制器/Nand flash图片笔记/s3c2440访问Nand flash.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/第二个驱动程序例子 --mdev检测系统信息自动创建硬件设备/first_drv.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/第二个驱动程序例子 --mdev检测系统信息自动创建硬件设备/first_drv.c -------------------------------------------------------------------------------- /10. 内存管理单元MMU/内存管理单元MMU图片笔记/cpu--MMU--存储管理器--SDRAM关系图.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/10. 内存管理单元MMU/内存管理单元MMU图片笔记/cpu--MMU--存储管理器--SDRAM关系图.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/字符设备驱动程序图片笔记/应用程序的open如何实现内核的open的操作的过程解析.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/字符设备驱动程序图片笔记/应用程序的open如何实现内核的open的操作的过程解析.JPG -------------------------------------------------------------------------------- /21. 字符设备驱动程序/字符设备驱动程序图片笔记/第一个驱动程序--open--write驱动框架分析过程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/21. 字符设备驱动程序/字符设备驱动程序图片笔记/第一个驱动程序--open--write驱动框架分析过程.JPG -------------------------------------------------------------------------------- /11. Nand flash控制器/Nand flash图片笔记/从nand那里读取led代码进SDRAM中并启动.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/11. Nand flash控制器/Nand flash图片笔记/从nand那里读取led代码进SDRAM中并启动.JPG -------------------------------------------------------------------------------- /配置文件宏分类.md: -------------------------------------------------------------------------------- 1 | ## 配置文件宏分类 (2017.12.09) 2 | 1. `选项` --- `前缀为 “CONFIG_”` 3 | * 用于选择 CPU、SOC、开发板类型,设置系统时钟、选择设备驱动 4 | 2. `参数` --- `前缀为 “CFG_”` 5 | * 用于设置malloc缓冲池的大小、U-BOOT的提示符、U-BOOT下载文件时的默认下载地址,Flash的起始地址 -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile中把链接(link)和编译(compile)分开.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GalenDeng/Embedded-Linux/HEAD/1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/makefile中把链接(link)和编译(compile)分开.PNG -------------------------------------------------------------------------------- /0. 单板和主机间传输文件的方式.md: -------------------------------------------------------------------------------- 1 | ## 单板和主机间传输文件的方式 (2017.12.09) 2 | 1. `串口下载` 3 | * xmodem/ymodem/zmodem协议 --- tera-term 软件有此功能 4 | 2. `网络下载` 5 | * tftp --- 主机需要开启tftp服务 6 | * nfs --- 主机需要开启nfs服务 7 | 3. `usb下载` 8 | * dnw命令方式 -------------------------------------------------------------------------------- /20. 构建根文件系统/20.4 修改MTD分区.md: -------------------------------------------------------------------------------- 1 | ## 20.4 修改MTD分区 (2017.12.14) 2 | 1. `MTD介绍` 3 | ``` 4 | * MTD : Memory Technology Device(内存技术设备),是LINUX中对ROM、NOR Flash、NAND Flash等存储设备抽象 5 | 出来的一个设备层,向上提供统一的访问接口(读、写擦除等),屏蔽底层硬件的操作、各类存储设备的差别 6 | * 得益于MTD设备的作用,重新划分NAND Flash的分区很简单 7 | ``` -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/嵌入式面试题汇总/面试题.md: -------------------------------------------------------------------------------- 1 | ## 嵌入式面试题 2 | 1. [Linux操作系统基础知识](http://mp.weixin.qq.com/s?__biz=MzA3OTgyMDcwNg==&mid=2650633293&idx=1&sn=74570f44767a03f25064b0f5edfbc4bb&chksm=87a47680b0d3ff96737b0d9512665435f64df991ae8b2b25b7e8ee2c37594f64cd7119fb4d32&mpshare=1&scene=1& -------------------------------------------------------------------------------- /21. 字符设备驱动程序/驱动led灯开与闭的程序例子/Makefile: -------------------------------------------------------------------------------- 1 | KERN_DIR = /work/system/linux-2.6.22.6 2 | 3 | all: 4 | make -C $(KERN_DIR) M=`pwd` modules 5 | 6 | clean: 7 | make -C $(KERN_DIR) M=`pwd` modules clean 8 | rm -rf modules.order 9 | 10 | obj-m += first_drv.o 11 | -------------------------------------------------------------------------------- /21. 字符设备驱动程序/第一个驱动程序例子 --open--write/Makefile: -------------------------------------------------------------------------------- 1 | KERN_DIR = /work/system/linux-2.6.22.6 2 | 3 | all: 4 | make -C $(KERN_DIR) M=`pwd` modules 5 | 6 | clean: 7 | make -C $(KERN_DIR) M=`pwd` modules clean 8 | rm -rf modules.order 9 | 10 | obj-m += first_drv.o 11 | -------------------------------------------------------------------------------- /21. 字符设备驱动程序/第二个驱动程序例子 --mdev检测系统信息自动创建硬件设备/Makefile: -------------------------------------------------------------------------------- 1 | KERN_DIR = /work/system/linux-2.6.22.6 2 | 3 | all: 4 | make -C $(KERN_DIR) M=`pwd` modules 5 | 6 | clean: 7 | make -C $(KERN_DIR) M=`pwd` modules clean 8 | rm -rf modules.order 9 | 10 | obj-m += first_drv.o 11 | -------------------------------------------------------------------------------- /链接脚本代码解释/链接脚本代码解析.md: -------------------------------------------------------------------------------- 1 | ## 链接脚本代码解析 (2018.1.7) 2 | ## 链接脚本代码解析 [嵌入式linux应用开发完全手册 P195] 3 | ![链接脚本代码解析](https://github.com/GalenDeng/Embedded-Linux/blob/master/%E9%93%BE%E6%8E%A5%E8%84%9A%E6%9C%AC%E4%BB%A3%E7%A0%81%E8%A7%A3%E9%87%8A/%E9%93%BE%E6%8E%A5%E8%84%9A%E6%9C%AC%E4%BB%A3%E7%A0%81%E8%A7%A3%E6%9E%90.JPG) -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/boot.lds: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x33f80000; 3 | .text : { *(.text) } 4 | 5 | . = ALIGN(4); 6 | .rodata : { *(.rodata) } 7 | 8 | . = ALIGN(4); 9 | .data : { *(.data) } 10 | 11 | . = ALIGN(4); 12 | __bss_start = . ; 13 | .bss : { *(.bss) *(COMMON) } 14 | __bss_end = . ; 15 | } -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/boot.lds: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x33f80000; 3 | .text : { *(.text) } 4 | 5 | . = ALIGN(4); 6 | .rodata : { *(.rodata) } 7 | 8 | . = ALIGN(4); 9 | .data : { *(.data) } 10 | 11 | . = ALIGN(4); 12 | __bss_start = . ; 13 | .bss : { *(.bss) *(COMMON) } 14 | __bss_end = . ; 15 | } -------------------------------------------------------------------------------- /7. 硬件电路图/硬件电路图分类.md: -------------------------------------------------------------------------------- 1 | ## 硬件电路图分类 (2017.12.07) 2 | 1. 硬件电路图分类 3 | ![硬件电路图分类](https://github.com/GalenDeng/Embedded-Linux/blob/master/7.%20%E7%A1%AC%E4%BB%B6%E7%94%B5%E8%B7%AF%E5%9B%BE/%E7%A1%AC%E4%BB%B6%E5%88%86%E7%B1%BB.JPG) 4 | 2. `上拉电阻和下拉电阻的作用` 5 | ``` 6 | 当GPIO引脚处于第三态(既不是输出高电平,也不是低电平,而是高阻态,即相当于没接芯片)时, 7 | 它的电平状态由上拉电阻、下拉电阻确定 8 | ``` 9 | 3. `引脚操作` :`输出高低电平、检测引脚状态、中断` -------------------------------------------------------------------------------- /21. 字符设备驱动程序/第一个驱动程序例子 --open--write/firstdrvtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc,char **argv) 7 | { 8 | int fd; 9 | int val = 1; 10 | fd =open("/dev/xxx",O_RDWR); 11 | if (fd < 0) 12 | printf("can't open!\n"); 13 | write(fd,&val,4); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /21. 字符设备驱动程序/第二个驱动程序例子 --mdev检测系统信息自动创建硬件设备/firstdrvtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc,char **argv) 7 | { 8 | int fd; 9 | int val = 1; 10 | fd =open("/dev/xyz",O_RDWR); 11 | if (fd < 0) 12 | printf("can't open!\n"); 13 | write(fd,&val,4); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /19. 移植linux内核/19.4 修改内核以支持S3C2440开发板.md: -------------------------------------------------------------------------------- 1 | ## 19.4 修改内核以支持S3C2440开发板 (2017.12.13) 2 | 1. 解压源码,修改顶层Makefile 3 | * vim Makefile 4 | * /^ARCH // 查找开头为ARCH的字符串 5 | * d$ // 删除光标到该行的最后字符的所有内容 6 | * 7 | ``` 8 | ARCH ?= arm 9 | CROSS_COMPILE ?= arm-linux- 10 | ``` 11 | * galen@HD66:/work/linux-2.6-transplant/linux-2.6.22.6$ cd arch/arm/configs/ 12 | * make s3c2410_defconfig -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.2 makefile.md: -------------------------------------------------------------------------------- 1 | ## makefile (2017.11.19) 2 | 1. `某个makefile` 3 | ``` 4 | galen@66:/work/hardware/hello$ cat Makefile 5 | hello : hello.o a.o 6 | gcc -o $@ $^ 7 | 8 | %.o : %.c 9 | gcc -o $@ -c $< 10 | 11 | clean : 12 | rm *.o hello 13 | 14 | ``` 15 | 2. `$^` 16 | ``` 17 | 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的, 18 | 那个这个变量会去除重复的依赖目标,只保留一份。 19 | ``` 20 | 3. `$@ ` 21 | ``` 22 | 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是 23 | 匹配于目标中模式定义的集合。 24 | ``` -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.1交叉编译工具选项说明.md: -------------------------------------------------------------------------------- 1 | 1. `pc编译工具` 2 | ``` 3 | * gcc ld objcopy objdump 4 | ``` 5 | 2. `arm编译工具` 6 | ``` 7 | * arm-linux-gcc arm-linux-ld 8 | ``` 9 | 3. `arm-linux-gcc` 10 | * 1) `预处理`:`以#开头的命令`被称为`预处理命令` ; `预处理工具`:arm-linux-cpp 代码 ---> .i文件 11 | * 2) `编译`:工具: cc1 .i文件---> 汇编代码 12 | * 3) `汇编`: 汇编代码 ---> 一定格式的机器代码(表现为ELF目标文件(OBJ文件)) 工具:arm-linux-as 13 | `反汇编`:机器代码 ---> 汇编代码 14 | * 4) `连接`:`3)中生成的OBJ文件、系统库的OBJ文件、库文件连接起来` ---> 在特定平台运行的可执行文件 工具: arm-linux-ld -------------------------------------------------------------------------------- /19. 移植linux内核/19.3 内核Kconfig分析.md: -------------------------------------------------------------------------------- 1 | ## 19.3 内核Kconfig分析 (2017.12.13) 2 | * Kconfig文件用于配置内核,为各种配置界面的源文件 3 | * 内核的配置工具读取各个Kconfig文件,生成配置界面供开发人员配置内核,最后生成配置文件.config 4 | 1. `.config文件的3种配置结果` 5 | * CONFIG_LEDS_S3C24XX=y // 对应文件被编译进内核 6 | * CONFIG_LEDS_S3C24XX=m // 对应文件被编成模块 7 | * #CONFIG_LEDS_S3C24XX // 对应文件没有被使用 8 | 2. `变量` 9 | * bool 取值: y / m 10 | * tristate 取值: y / m / n 11 | * string 取值: 字符串 12 | * hex 取值: 十六进制的数据 13 | * int 取值: 十进制的数据 -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = arm-linux-gcc 3 | LD = arm-linux-ld 4 | AR = arm-linux-ar 5 | OBJCOPY = arm-linux-objcopy 6 | OBJDUMP = arm-linux-objdump 7 | 8 | CFLAGS := -Wall -O2 9 | CPPFLAGS := -nostdinc -nostdlib -fno-builtin 10 | 11 | objs := start.o init.o boot.o 12 | 13 | boot.bin: $(objs) 14 | ${LD} -Tboot.lds -o boot.elf $^ 15 | ${OBJCOPY} -O binary -S boot.elf $@ 16 | ${OBJDUMP} -D -m arm boot.elf > boot.dis 17 | 18 | %.o:%.c 19 | ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $< 20 | 21 | %.o:%.S 22 | ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $< 23 | 24 | clean: 25 | rm -f *.o *.bin *.elf *.dis 26 | -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = arm-linux-gcc 3 | LD = arm-linux-ld 4 | AR = arm-linux-ar 5 | OBJCOPY = arm-linux-objcopy 6 | OBJDUMP = arm-linux-objdump 7 | 8 | CFLAGS := -Wall -O2 9 | CPPFLAGS := -nostdinc -nostdlib -fno-builtin 10 | 11 | objs := start.o init.o boot.o 12 | 13 | boot.bin: $(objs) 14 | ${LD} -Tboot.lds -o boot.elf $^ 15 | ${OBJCOPY} -O binary -S boot.elf $@ 16 | ${OBJDUMP} -D -m arm boot.elf > boot.dis 17 | 18 | %.o:%.c 19 | ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $< 20 | 21 | %.o:%.S 22 | ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $< 23 | 24 | clean: 25 | rm -f *.o *.bin *.elf *.dis 26 | -------------------------------------------------------------------------------- /21. 字符设备驱动程序/驱动led灯开与闭的程序例子/firstdrvtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | * firstdrvtest on 打开 8 | * firstdrvtest off 关闭 9 | */ 10 | 11 | 12 | int main(int argc,char **argv) 13 | { 14 | int fd; 15 | int val=0; 16 | fd =open("/dev/xyz",O_RDWR); 17 | if (fd < 0) 18 | printf("can't open!\n"); 19 | if (argc != 2) 20 | { 21 | printf("usage :\n"); 22 | printf("%s \n",argv[0]); 23 | return 0; 24 | } 25 | 26 | if (strcmp(argv[1],"on") == 0) // 如果第二个参数 == on 的时候 27 | { 28 | val = 1; 29 | } 30 | else 31 | { 32 | val = 0; 33 | } 34 | 35 | write(fd,&val,4); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /13. 系统时钟和定时器/13.1 系统时钟和定时器.md: -------------------------------------------------------------------------------- 1 | ## 13.1 系统时钟和定时器 (2017.12.19) 2 | 1. `FCLK HCLK PCLK` 3 | ``` 4 | * CPUh核S3C2440) ===> FCLK 5 | * AHB总线上的设备 ===> HCLK 6 | * APB总线上的设备 ===> PCLK 7 | ``` 8 | ## FCLK-HCLK-PCLK的区别 9 | ![FCLK-HCLK-PCLK的区别](https://github.com/GalenDeng/Embedded-Linux/blob/master/13.%20%E7%B3%BB%E7%BB%9F%E6%97%B6%E9%92%9F%E5%92%8C%E5%AE%9A%E6%97%B6%E5%99%A8/%E7%B3%BB%E7%BB%9F%E6%97%B6%E9%92%9F%E5%92%8C%E5%AE%9A%E6%97%B6%E5%99%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/FCLK-HCLK-PCLK%E7%9A%84%E5%8C%BA%E5%88%AB.JPG) 10 | * 3c2440的晶振是12M,通过设置PLL来达到提高系统时钟的频率(400MHZ),然后通过分频来给HCLK和PCLK 11 | * PLL : 1.锁定时间 2. PLL寄存器 12 | ## PLL启动过程 13 | ![PLL启动过程](https://github.com/GalenDeng/Embedded-Linux/blob/master/13.%20%E7%B3%BB%E7%BB%9F%E6%97%B6%E9%92%9F%E5%92%8C%E5%AE%9A%E6%97%B6%E5%99%A8/%E7%B3%BB%E7%BB%9F%E6%97%B6%E9%92%9F%E5%92%8C%E5%AE%9A%E6%97%B6%E5%99%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/PLL%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B.JPG) -------------------------------------------------------------------------------- /3.JZ2440的jlink烧写方式/烧写方式总结.md: -------------------------------------------------------------------------------- 1 | ## JZ2440 烧写方式总结 2 | * 注意: 烧写了uboot后进行程序的烧写的时候记得把jlink进行断电处理 3 | * [详细步骤链接](https://github.com/GalenDeng/Embedded-Linux/blob/master/JZ2440%E7%9A%84jlink%E7%83%A7%E5%86%99%E6%96%B9%E5%BC%8F/JZ2440%E5%BC%80%E5%8F%91%E6%9D%BFJLINK%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8CV1.0%E7%89%88%E6%9C%AC.pdf) 4 | * 使用 j-flash 烧写 S3C2440.jflash文件,然后 target --> connect 5 | * 使用 j-flash 烧写 u-boot.bin 文件,然后 target --> programme 6 | * 在虚拟机中的菜单栏 VM -- Romovable Devices -- SEC S3C2410X Test B/D 7 | * lsusb 查看该usb设备是否存在 8 | * 选择 NOR flash启动模式(jlink只支持nor flash启动) ,快速按空格键,出现以下的选择项: 9 | * ![uboot选项](https://github.com/GalenDeng/Embedded-Linux/blob/master/JZ2440%E7%9A%84jlink%E7%83%A7%E5%86%99%E6%96%B9%E5%BC%8F/uboot%E7%83%A7%E5%86%99%E9%80%89%E6%8B%A9.PNG) 10 | * 若选n 即烧写程序到 nand flash中 11 | * sudo dnw /dir/document //进行程序的烧写 12 | * 断电、选择 nand flash启动,出现以下的选项 13 | * ![程序测试](https://github.com/GalenDeng/Embedded-Linux/blob/master/JZ2440%E7%9A%84jlink%E7%83%A7%E5%86%99%E6%96%B9%E5%BC%8F/%E7%A8%8B%E5%BA%8F%E6%B5%8B%E8%AF%95.PNG) 14 | * 进行程序测试 -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/1th-question: -------------------------------------------------------------------------------- 1 | 1th: question 2 | galen@HD66:/work/nfs_root/bootloader-write-myself/1th$ make 3 | make: Warning: File `Makefile' has modification time 9.4e+04 s in the future 4 | arm-linux-gcc -nostdinc -Wall -O2 -c -o start.o start.S 5 | arm-linux-gcc -nostdinc -Wall -O2 -c -o init.o init.c 6 | init.c: In function `copy_code_to_sdram': 7 | init.c:61: error: `nand_read' undeclared (first use in this function) 8 | init.c:61: error: (Each undeclared identifier is reported only once 9 | init.c:61: error: for each function it appears in.) 10 | init.c:61: error: syntax error before '}' token 11 | init.c: In function `nand_read': 12 | init.c:142: error: invalid operands to binary % 13 | init.c:151: warning: passing arg 1 of `nand_addr' makes integer from pointer without a cast 14 | init.c: In function `uart0_init': 15 | init.c:185: error: `sUART_CLK' undeclared (first use in this function) 16 | init.c:185: error: syntax error before "x" 17 | init.c:185: error: stray '\226' in program 18 | init.c:185: error: stray '\128' in program 19 | init.c:185: error: stray '\147' in program 20 | init.c: In function `putc': 21 | init.c:193: error: syntax error before ';' token 22 | init.c:191: warning: unused variable `i' 23 | init.c: At top level: 24 | init.c:199: warning: conflicting types for built-in function 'puts' 25 | init.c:226:2: warning: no newline at end of file 26 | make: *** [init.o] Error 1 27 | galen@HD66:/work/nfs_root/bootloader-write-myself/1th$ 28 | -------------------------------------------------------------------------------- /16. LCD实验/LCD实验.md: -------------------------------------------------------------------------------- 1 | ## LCD实验 (2018.1.5) 2 | 1. `介绍` 3 | ``` 4 | * vsync : 垂直同步信号 5 | * Hsync : 水平同步信号 6 | * vclk : 时钟 7 | * VDEN : 使能信号 8 | * VD0 - VD23 : 数据信号 9 | * LED+ LED- : 背光信号 10 | ``` 11 | ## 2440和lcd的关系 12 | ![2440和lcd的关系](https://github.com/GalenDeng/Embedded-Linux/blob/master/16.%20LCD%E5%AE%9E%E9%AA%8C/2440%E4%B8%8Elcd%E7%9A%84%E5%85%B3%E7%B3%BB.JPG) 13 | 2. `像素颜色三部分: 红、绿、蓝` 14 | ``` 15 | 显示器上的每个像素的颜色由3部分组成:红、绿、蓝,他们被称为三原色 16 | ``` 17 | 3. `LCD控制器` 18 | ``` 19 | * LCD控制器支持单色(1BPP)、4级灰色(2BPP)、16级灰色(4BPP)、256色(8BPP)的调色板显示模式 20 | * 16M(24BPP)色的显示模式就是使用24位的数据来表示一个像素的颜色 16M = 2^20 * 2^4,每种原色使用8位 21 | ``` 22 | 4. `NC : not connect` 23 | 5. `调色板` 24 | ``` 25 | 调色板就是一块内存,可以对每个索引值设置其颜色,可以使用24BPP和16BPP 26 | ``` 27 | ## 调色板的作用 28 | ![调色板的作用](https://github.com/GalenDeng/Embedded-Linux/blob/master/16.%20LCD%E5%AE%9E%E9%AA%8C/%E8%B0%83%E8%89%B2%E6%9D%BF%E7%9A%84%E4%BD%9C%E7%94%A8.JPG) 29 | 6. `RGB:RED 、GREEN、BLUE` 30 | * frame buffer : 帧缓冲区 31 | ## 帧内存和视口 32 | ![帧内存和视口](https://github.com/GalenDeng/Embedded-Linux/blob/master/16.%20LCD%E5%AE%9E%E9%AA%8C/%E5%B8%A7%E5%86%85%E5%AD%98%E5%92%8C%E8%A7%86%E5%8F%A3.JPG) 33 | 7. `快捷清屏操作` 34 | * 设置LCD为某一种颜色 ==> TPAL ==> 2440(LCD控制器) ==> LCD 35 | 8.`ChangePalette` 36 | ``` 37 | void ChangePalette(UINT32 color) 38 | { 39 | int i; 40 | unsigned char red, green, blue; 41 | UINT32 *palette; 42 | 43 | /* 从0xRRGGBB格式的color变量中,提取8位红色值的高5位、8位绿色值的高6位、8位蓝色值的高5位*/ 44 | red = (color >> 19) & 0x1f; 45 | green = (color >> 10) & 0x3f; 46 | blue = (color >> 3) & 0x1f; 47 | // 组成 5:6:5 格式的16BPP颜色值 48 | color = (red << 11) | (green << 5) | blue; // 格式5:6:5 49 | ``` 50 | 9. `像素` 51 | * 对于16BPP模式,每个像素占据2字节;对于8BPP模式,每个像素占据1字节. -------------------------------------------------------------------------------- /5. u-boot、linux内核打补丁、编译以及sourceinsight的使用说明/u-boot、linux内核打补丁、编译以及sourceinsight的使用说明.md: -------------------------------------------------------------------------------- 1 | ## u-boot、linux内核打补丁、编译以及sourceinsight的使用说明 (2017.12.06) 2 | ## u-boot打补丁 3 | 1. 4 | ``` 5 | diff -urN u-boot-1.1.6/board/100ask24x0/100ask24x0.c u-boot-1.1.6_jz2440/board/100ask24x0/100ask24x0.c 6 | --- u-boot-1.1.6/board/100ask24x0/100ask24x0.c 1970-01-01 07:00:00.000000000 +0700 7 | +++ u-boot-1.1.6_jz2440/board/100ask24x0/100ask24x0.c 2010-11-26 12:54:37.034090906 +0800 8 | @@ -0,0 +1,96 @@ 9 | +/* 10 | + * (C) Copyright 2002 11 | + * Sysgo Real-Time Solutions, GmbH 12 | + * Marius Groeger 13 | + * 14 | ``` 15 | * `---` 原来的文件 16 | * `+++` 修改后的文件 17 | * `-` :去掉该内容 18 | * `+` :增加该内容 19 | 20 | 2. `diff 和 patch` 21 | ``` 22 | diff: 为逐行比较两个文本文件,列出其不同之处,可是 23 | 做成diff记录就是补丁 24 | * -u: 以统一格式创建补丁文件 25 | * -r: 递归选项,diff会将两个不通版本源代码目录中的所有对应的文件进行一次比较,包括子目录文件 26 | * -N:确保补丁文件将正确地处理已经创建或删除文件的情况 27 | patch : 利用diff制作的补丁来打到文件(夹),使其文件文件夹一致 28 | * -p1 : 省略从开始数来的第一个`/`之前的目录地址 29 | * $ cd u-boot-1.1.6 30 | * $ patch -p1 < ../u-boot-1.1.6_jz2440.patch // -p1省略了u-boot-1.1.6/ 31 | ``` 32 | 3. `备份` 33 | * cd .. 34 | * tar cjf u-boot-1.1.6_jz2440.tar.bz2 u-boot-1.1.6 35 | 4. `编译` 36 | * $ make 100ask24x0_config 37 | * $ make 38 | 5. 把生成的 u-boot.bin 通过 nor启动,在linux下使用 sudo dnw u-boot.bin 烧写到 nand flash中 39 | 6. 打补丁完成 40 | 41 | ## 内核打补丁即修复 42 | 1. tar xjf linux-2.6.22.6.tar.bz2 43 | 2. patch -p1 < ../linux-2.6.22.6_jz2440.patch 44 | 3. cp config_ok .config 45 | 4. cd .. 46 | 5. tar cjf linux-2.6.22.6_jz2440.tar.bz2 linux-2.6.22.6 47 | 6. make uImage 48 | 49 | ## sourceinsignt 50 | 1. 可以直接拖动文件进 sourceinsignt里面,其自动打开让你查看其源代码 51 | 2. 在要查看的源代码文件夹中新建一个文件夹,通过 sourceinsignt 的new project新建文件,synchronize file来产生目录文件 52 | 3. ctrl + 选中的字符, 软件会跳到文件的定义调用处 -------------------------------------------------------------------------------- /20. 构建根文件系统/busybox.md: -------------------------------------------------------------------------------- 1 | ## busybox -- 命令行的收集 (2017.12.14) 2 | 1. galen@HD66:/work/busybox-test$ tar jxf busybox-1.7.0.tar.bz2 3 | 2. cd busybox-1.7.0/ ; ls 4 | 3. `一般可以从 INSTALL or README 文件来查看编译的步骤` 5 | 4. `编译` 6 | ``` 7 | make menuconfig # This creates a file called ".config" 8 | // 这个是图形界面,如果在这个图形界面中search不到cross的字样(交叉编译工具),只能去Makefile中查找 9 | make # This creates the "busybox" executable 10 | make install # or make CONFIG_PREFIX=/path/from/root install // /path/from/root 安装目录 11 | ``` 12 | 5. `vim Makefile` 13 | * /^CROSS 14 | * CROSS_COMPILE ?= // 这个就是交叉编译工具 15 | * 我们看一下能不能在配置文件里面定义 -- 这里找不到 16 | * 我们只能直接定义 CROSS_COMPILE ?= arm-linux- 或者 在编译的时候执行 make CROSS_COMPILE=arm-linux- 17 | * :wq! 18 | 6. `make menuconfig 进行性能微调` 19 | * [*] Tab completion // 命令补全 位置 Busybox Settings ---> Busybox Library Tuning ---> 20 | * [] Build BusyBox a static binary (no shared libs) // 不选这个,不然使用glibc时,编译BusyBox会出错 --- 应使用动态连接的BusyBox 位置: Build Options ---> 21 | * 还有其他的配置 --- 详见:《嵌入式Linux应用开发》的 P348 - P349 22 | 6. `make` 23 | * 这个过程中可能会出现一些错误的信息,如果这些命令你不用的,可以执行`make menuconfig`,在弹出的 24 | * 菜单栏里面去掉这些配置 25 | 7. `因为我们现在使用的是交叉编译工具,如果我们此时执行 make install , busybox将会安装在我们的主机上面,这样是错误的` 26 | * galen@HD66:/work/busybox-test/busybox-1.7.0$ mkdir -p /work/nfs_root/first-fs 27 | * -p : 可以建立嵌套的目录文件啊,如果上一级的目录没有创建,会自动创建出来 28 | * galen@HD66:/work/busybox-test/busybox-1.7.0$ make CONFIG_PREFIX=/work/nfs_root/first-fs install 29 | * galen@HD66:/work/busybox-test/busybox-1.7.0$ cd /work/nfs_root/first-fs/ 30 | * galen@HD66:/work/nfs_root/first-fs$ ls -lt 31 | ``` 32 | total 12 33 | drwxrwxr-x 4 galen galen 4096 Dec 13 15:39 usr 34 | drwxrwxr-x 2 galen galen 4096 Dec 13 15:39 bin 35 | lrwxrwxrwx 1 galen galen 11 Dec 13 15:39 linuxrc -> bin/busybox 36 | drwxrwxr-x 2 galen galen 4096 Dec 13 15:39 sbin 37 | ``` 38 | ``` 39 | galen@HD66:/work/nfs_root/first-fs$ ls -l bin/ls 40 | lrwxrwxrwx 1 galen galen 7 Dec 13 15:39 bin/ls -> busybox 41 | galen@HD66:/work/nfs_root/first-fs$ ls -l linuxrc 42 | lrwxrwxrwx 1 galen galen 11 Dec 13 15:39 linuxrc -> bin/busybox 43 | ``` 44 | 8. `直到这里,我们完成了 init ===> busybox 的功能` 45 | 46 | -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/start.S: -------------------------------------------------------------------------------- 1 | // 从数据手册查看计算公式 2 * (92 +8)*12/((1+2)*2^2) =200 2 | #define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02)) 3 | #define MEM_CTL_BASE 0x48000000 4 | .text 5 | .global _start 6 | _start: 7 | 8 | /* 1. 关看门狗*/ 9 | ldr r0, =0x53000000 10 | mov r1, #0 11 | str r1, [r0] 12 | /* 2. 设置时钟*/ // CLKDIVN 分频配置 13 | ldr r0,=0x4C000014 14 | mov r1,#0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1 15 | str r1,[r0] 16 | 17 | /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */ 18 | // 数据手册有给出例子 19 | mrc p15,0,r1,c1,c0,0 20 | orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode”*/ 21 | mcr p15,0,r1,c1,c0,0 22 | 23 | /* MPLLCON = S3C2440_MPLL_200MHZ */ // FCLK = 200MHZ HCLK = 100MHZ PCLK = 50MHZ 24 | ldr r0, =0x4C000004 25 | ldr r1, =S3C2440_MPLL_200MHZ 26 | str r1,[r0] 27 | 28 | /* 3. SDRAM初始化 */ 29 | ldr r0, = MEM_CTL_BASE // 0X48000000 BWSCON 存储控制器 30 | adr r1, sdram_config // sdram_config的当前地址 31 | add r3, r0, #(13*4) 32 | 33 | 1: 34 | ldr r2, [r1], #4 35 | str r2, [r0], #4 36 | cmp r0, r3 37 | bne 1b 38 | 39 | 40 | /* 4. 重定位: 把bootloader本身的代码从flash复制到SDRAM中 */ 41 | // 因为打算用 C语言编写代码, 所以要设置栈 42 | ldr sp, = 0x34000000 43 | // 因为涉及到从nand flash中复制代码,所以要初始化 nand flash 44 | bl nand_init 45 | 46 | mov r0, #0 47 | ldr r1, =_start // 程序开始的位置 48 | ldr r2, =__bss_start // __bss_start - _start = 代码的大小len 49 | sub r2, r2, r1 50 | 51 | bl copy_code_to_sdram // 复制代码到sdram 52 | bl clear_bss // 清零 (bss:没被初始化的全局变量和初始化为0的全局变量) 53 | 54 | /* 5. 执行main */ 55 | ldr lr, =halt // lr存放跳转的返回值 56 | ldr pc, =main // 主函数 57 | 58 | halt: // 伪指令 59 | bl halt // 防止程序跑偏,设置死循环 60 | 61 | sdram_config: // 伪指令 : 设置存储管理器 62 | // 这项为 寄存器的设置值 63 | .long 0x22011110 //BWSCON // Bus width & wait status control register 64 | .long 0x00000700 //BANKCON0 // 存储控制器0 片选信号 65 | .long 0x00000700 //BANKCON1 // 存储控制器1 66 | .long 0x00000700 //BANKCON2 67 | .long 0x00000700 //BANKCON3 68 | .long 0x00000700 //BANKCON4 69 | .long 0x00000700 //BANKCON5 70 | .long 0x00018005 //BANKCON6 // sdram RAS to CAS delay :4clock 71 | .long 0x00018005 //BANKCON7 72 | .long 0x008C04F4 // REFRESH // SDRAM型号:K4S561632N 刷新频率 Refresh period = (2^11 -refresh_count+1)/HCLK period: 64ms 73 | .long 0x000000B1 //BANKSIZE 74 | .long 0x00000030 //MRSRB6 // Mode register set register bank6 75 | .long 0x00000030 //MRSRB7 // Mode register set register bank7 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /21. 字符设备驱动程序/21.2 点LED灯的驱动程序分析.md: -------------------------------------------------------------------------------- 1 | ## 点LED灯的驱动程序分析 (2017.12.16) 2 | * [first_drv.c源代码](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E9%A9%B1%E5%8A%A8led%E7%81%AF%E5%BC%80%E4%B8%8E%E9%97%AD%E7%9A%84%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90/first_drv.c) 3 | * [firstdrvtest.c源代码](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E9%A9%B1%E5%8A%A8led%E7%81%AF%E5%BC%80%E4%B8%8E%E9%97%AD%E7%9A%84%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90/firstdrvtest.c) 4 | * [Makefile](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E9%A9%B1%E5%8A%A8led%E7%81%AF%E5%BC%80%E4%B8%8E%E9%97%AD%E7%9A%84%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90/Makefile) 5 | ## 1. 写一个点LED驱动 6 | 1. 框架 7 | 2. 完善硬件的操作 8 | * 看原理图 9 | * 看2440手册 10 | * 写代码 11 | ``` 12 | 单片机与驱动的区别: 13 | * 单片机:操作物理地址 14 | * 驱动: 操作虚拟地址(不能操作物理地址) <== 通过 ioremap把物理地址映射为虚拟地址 15 | ``` 16 | * cd进内核的目录,grep "ioremap" * -nR 搜索 ioremap的参数意义 (开始地址,长度) 17 | ``` 18 | volatile unsigned long *gpfcon = NULL; 19 | volatile unsigned long *gpfdat = NULL; 20 | 21 | static int first_drv_open(struct inode *inode, struct file *file) 22 | { 23 | //printk(" first_drv_open\n"); 24 | /******配置GPF4 ,GPF5,GPF7为输出******/ 25 | *gpfcon &= ~((0x3 << (4 * 2)) | (0x3 << (5 * 2)) | (0x3 << (6 * 2))); // 良好习惯,先清0 26 | *gpfcon |= ((0x1 << (4 * 2)) | (0x1 << (5 * 2)) | (0x1 << (6 * 2))); // 置1 ,设置为输出的模式 27 | return 0; 28 | } 29 | 30 | static int first_drv_write(struct file *file, const __user * buf ,size_t count , loff_t * ppos) // buf : 这个是应用层传进来的buf 31 | { 32 | int val; 33 | copy_from_user(&val, buf, count); // 这种方式从应用层取值, 拷贝进val的地址里面 34 | // copy_to_user(void __user * to, const void * from, unsigned long n) 从内核空间复制内容到用户空间 35 | 36 | if (val == 1) 37 | { 38 | //点灯 39 | *gpfdat &= ~((1 << 4) | (1 << 5) |(1 << 6) ); 40 | } 41 | else 42 | { 43 | //灭灯 44 | *gpfdat |= ((1 << 4) | (1 << 5) |(1 << 6) ); 45 | } 46 | //printk(" first_drv_write\n"); 47 | return 0; 48 | } 49 | 50 | // 卸载驱动 51 | static void first_drv_exit(void) 52 | { 53 | unregister_chrdev(major, "first_drv"); 54 | 55 | class_device_unregister(firstdrv_class_dev); //删除设备 56 | class_destroy(firstdrv_class); // 删除类 57 | iounmap(gpfcon); // 删掉映射 58 | } 59 | ``` 60 | 61 | ## 2. 改进点LED驱动 --- 利用上次设备号 --- 参考代码:/work/nfs_root/drivers_and_test/leds 62 | * 次设备号是给我们用户自己用的(minor) -------------------------------------------------------------------------------- /2.GPIO实验/GPIO.md: -------------------------------------------------------------------------------- 1 | ## GPIO (2017.11.21) 2 | 1. `汇编代码` 3 | ``` 4 | galen@66:/work/hardware/gpio/led_on$ cat led_on.S 5 | @****************************************************************************** 6 | @ File:led_on.S 7 | @ 功能:LED点灯程序,点亮LED1 8 | @****************************************************************************** 9 | 10 | .text 11 | .global _start 12 | _start: 13 | LDR R0,=0x56000050 @ R0设为GPFCON寄存器。此寄存器 //让R0 = 0x56000050 14 | //LDR : LOAD register 加载寄存器 LDR伪指令 15 | //的形式是“LDR Rn,=expr” 16 | @ 用于选择端口B各引脚的功能: 17 | @ 是输出、是输入、还是其他 18 | MOV R1,#0x00000100 //赋值 19 | STR R1,[R0] @ 设置GPF4为输出口, 位[8:7]=0b01 //将R1的数据传给RO表示的地址中 20 | LDR R0,=0x56000054 @ R0设为GPBDAT寄存器。此寄存器 21 | @ 用于读/写端口B各引脚的数据 22 | MOV R1,#0x00000000 @ 此值改为0x00000010, 23 | @ 可让LED1熄灭 24 | STR R1,[R0] @ GPF4输出0,LED1点亮 25 | MAIN_LOOP: 26 | B MAIN_LOOP // B : 跳转 这里是个死循环 27 | galen@66:/work/hardware/gpio/led_on$ 28 | ``` 29 | ``` 30 | * STR{条件} 源寄存器,<存储器地址> 31 | STR指令用于从源寄存器中将一个32位的字数据传送到存储器中 [写内存的指令] 32 | * str r1, [r0] ;将r1寄存器的值,传送到地址值为r0的(存储器)内存中 33 | ``` 34 | 2. `Makefile文件` 35 | ``` 36 | galen@66:/work/hardware/gpio/led_on$ cat Makefile 37 | led_on.bin : led_on.S // led_on.S 汇编文件 38 | arm-linux-gcc -g -c -o led_on.o led_on.S //编译 39 | arm-linux-ld -Ttext 0x0000000 -g led_on.o -o led_on_elf //链接 把led_on.o链接为led_on_elf格式 -g : 可调 40 | 试 -T : 指定代码段、数据段、bss段的起始地址 这里是指定text(代码段)的起始地址为 0x0000000 41 | arm-linux-objcopy -O binary -S led_on_elf led_on.bin //把led_on_elf转化为二进制文件 -S : 不从源文件中复 42 | 制重定位信息和符号信息到目标文件中去 -O bfdname : 使用指定的格式来输出文件 这里是输出二进制文件,输出文件名为 43 | led_on.bin 格式为: binary 44 | clean: 45 | rm -f led_on.bin led_on_elf *.o 46 | 47 | ``` 48 | ``` 49 | * arm-linux-objcopy : 被用来复制一个目标文件的内容到另一个文件中, 50 | 可以使用不同于源文件的格式来输出目的文件 51 | ``` 52 | * `目标` 53 | * ![目标](https://github.com/GalenDeng/Embedded-Linux/blob/master/GPIO%E5%AE%9E%E9%AA%8C/%E7%9B%AE%E6%A0%87.PNG) 54 | * `点亮LED的操作原理` 55 | * ![点亮LED的操作原理](https://github.com/GalenDeng/Embedded-Linux/blob/master/GPIO%E5%AE%9E%E9%AA%8C/%E7%82%B9%E4%BA%AELED.PNG) -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/start.S: -------------------------------------------------------------------------------- 1 | // 从数据手册查看计算公式 2 * (92 +8)*12/((1+2)*2^2) =200 2 | #define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02)) 3 | #define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01)) 4 | #define MEM_CTL_BASE 0x48000000 5 | .text 6 | .global _start 7 | _start: 8 | 9 | /* 1. 关看门狗*/ 10 | ldr r0, =0x53000000 11 | mov r1, #0 12 | str r1, [r0] 13 | /* 2. 设置时钟*/ // CLKDIVN 分频配置 14 | ldr r0,=0x4C000014 15 | // mov r1,#0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1 16 | mov r1,#0x05; // FCLK:HCLK:PCLK=1:4:8, HDIVN=2,PDIVN=1 17 | str r1,[r0] 18 | 19 | /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */ 20 | // 数据手册有给出例子 21 | mrc p15,0,r1,c1,c0,0 22 | orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode”*/ 23 | mcr p15,0,r1,c1,c0,0 24 | 25 | /* MPLLCON = S3C2440_MPLL_200MHZ */ // FCLK = 200MHZ HCLK = 100MHZ PCLK = 50MHZ 26 | ldr r0, =0x4C000004 27 | // ldr r1, =S3C2440_MPLL_200MHZ 28 | ldr r1, =S3C2440_MPLL_400MHZ // FCLK = 400MHZ HCLK = 100MHZ PCLK = 50MHZ 29 | str r1,[r0] 30 | 31 | /* 启动ICACHE */ 32 | mrc p15, 0, r0, c1, c0, 0 @ read control reg 33 | orr r0, r0, #(1 << 12) 34 | mcr p15, 0, r0, c1, c0, 0 @ write it back 35 | 36 | /* 3. SDRAM初始化 */ 37 | ldr r0, = MEM_CTL_BASE // 0X48000000 BWSCON 存储控制器 38 | adr r1, sdram_config // sdram_config的当前地址 39 | add r3, r0, #(13*4) 40 | 41 | 1: 42 | ldr r2, [r1], #4 43 | str r2, [r0], #4 44 | cmp r0, r3 45 | bne 1b 46 | 47 | 48 | /* 4. 重定位: 把bootloader本身的代码从flash复制到SDRAM中 */ 49 | // 因为打算用 C语言编写代码, 所以要设置栈 50 | ldr sp, = 0x34000000 51 | // 因为涉及到从nand flash中复制代码,所以要初始化 nand flash 52 | bl nand_init 53 | 54 | mov r0, #0 55 | ldr r1, =_start // 程序开始的位置 56 | ldr r2, =__bss_start // __bss_start - _start = 代码的大小len 57 | sub r2, r2, r1 58 | 59 | bl copy_code_to_sdram // 复制代码到sdram 60 | bl clear_bss // 清零 (bss:没被初始化的全局变量和初始化为0的全局变量) 61 | 62 | /* 5. 执行main */ 63 | ldr lr, =halt // lr存放跳转的返回值 64 | ldr pc, =main // 主函数 65 | 66 | halt: // 伪指令 67 | bl halt // 防止程序跑偏,设置死循环 68 | 69 | sdram_config: // 伪指令 : 设置存储管理器 70 | // 这项为 寄存器的设置值 71 | .long 0x22011110 //BWSCON // Bus width & wait status control register 72 | .long 0x00000700 //BANKCON0 // 存储控制器0 片选信号 73 | .long 0x00000700 //BANKCON1 // 存储控制器1 74 | .long 0x00000700 //BANKCON2 75 | .long 0x00000700 //BANKCON3 76 | .long 0x00000700 //BANKCON4 77 | .long 0x00000700 //BANKCON5 78 | .long 0x00018005 //BANKCON6 // sdram RAS to CAS delay :4clock 79 | .long 0x00018005 //BANKCON7 80 | .long 0x008C04F4 // REFRESH // SDRAM型号:K4S561632N 刷新频率 Refresh period = (2^11 -refresh_count+1)/HCLK period: 64ms 81 | .long 0x000000B1 //BANKSIZE 82 | .long 0x00000030 //MRSRB6 // Mode register set register bank6 83 | .long 0x00000030 //MRSRB7 // Mode register set register bank7 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/boot.c: -------------------------------------------------------------------------------- 1 | #include "setup.h" 2 | extern void uart0_init(void); 3 | extern void nand_read(unsigned int addr,unsigned char *buf, unsigned int len); 4 | extern void puts(char *str); 5 | extern void puthex(unsigned int val); 6 | 7 | static struct tag *params; 8 | void setup_start_tag(void) 9 | { 10 | // 放置设置参数的地方 0x30000100 11 | params = (struct tag *)0x30000100; 12 | // tag_header内容: tag size 13 | params->hdr.tag = ATAG_CORE; // tag = 0x54410001 => 参数的开始 14 | params->hdr.size = tag_size (tag_core); 15 | 16 | params->u.core.flags = 0; 17 | params->u.core.pagesize = 0; 18 | params->u.core.rootdev = 0; 19 | 20 | params = tag_next (params); // 设置标记的末尾位置,即指向当前标记的末尾 21 | } 22 | void setup_memory_tags(void) 23 | { 24 | params->hdr.tag = ATAG_MEM; 25 | params->hdr.size = tag_size (tag_mem32); 26 | 27 | params->u.mem.start = 0x30000000; 28 | params->u.mem.size = 0x04000000; 29 | 30 | params = tag_next (params); 31 | } 32 | 33 | int strlen(char *str) 34 | { 35 | int i = 0; 36 | while (str[i]) 37 | { 38 | i++; 39 | } 40 | return i; 41 | } 42 | 43 | void strcpy(char *dest, char *src) 44 | { 45 | while ((*dest++ = *src++) != '\0'); 46 | } 47 | 48 | void setup_commandline_tag(char *cmdline) 49 | { 50 | int len = strlen(cmdline) + 1; 51 | 52 | params->hdr.tag = ATAG_CMDLINE; 53 | params->hdr.size = (sizeof (struct tag_header) + len + 3) >> 2; // 加3比加4好 54 | 55 | strcpy (params->u.cmdline.cmdline, cmdline); // 拷贝进tag列表中 56 | 57 | params = tag_next (params); 58 | } 59 | void setup_end_tag(void) 60 | { 61 | params->hdr.tag = ATAG_NONE; 62 | params->hdr.size = 0; 63 | } 64 | 65 | 66 | int main(void) 67 | { 68 | void (*theKernel)(int zero, int arch, unsigned int params); 69 | volatile unsigned int *p = (volatile unsigned int *)0x30008000; 70 | /* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口 */ 71 | uart0_init(); 72 | 73 | /* 1. 从NAND FLASH里把内核读入内存 */ 74 | puts("Copy kernel from nand\n\r"); 75 | nand_read(0x60000 + 64,(unsigned char *)0x30008000,0x200000); //src , dest , len 76 | puthex(0x1234ABCD); 77 | puts("\n\r"); 78 | puthex(*p); 79 | puts("\n\r"); 80 | /* 2. 设置参数 --- 通过tag的方式*/ 81 | puts("Set boot params\n\r"); 82 | setup_start_tag(); 83 | setup_memory_tags(); 84 | setup_commandline_tag("noinitrd root=/dev/nfs nfsroot=192.168.99.140:/work/nfs_root/app,rsize=1024,wsize=1024 ip=192.168.99.135:192.168.99.140:192.168.99.4:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0"); 85 | setup_end_tag(); 86 | /* 3. 跳转执行 */ 87 | puts("Boot kernel\n\r"); 88 | theKernel = (void (*)(int, int, unsigned int))0x30008000; // 跳转到0x30008000 89 | theKernel(0,362,0x30000100); 90 | /* 等同于 mov pc, #0x30008000 */ 91 | /* mov r0, #0 */ 92 | /* ldr r1, =362 */ 93 | /* ldr r2, =0x30000100 */ 94 | puts("Error!\n\r"); 95 | /* 如果一切正常,不会执行到这里 */ 96 | return -1; 97 | } 98 | -------------------------------------------------------------------------------- /1.嵌入式编程基础知识/1.5 leds.lds和makefile规则介绍/1.5 leds.lds和makefile介绍.md: -------------------------------------------------------------------------------- 1 | ## 1.5 leds.lds和makefile介绍 (2017.11.20) 2 | 1. `leds.lds介绍` 3 | * 此为链接脚本 (指定链接地址) 4 | ``` 5 | galen@66:/work/hardware/leds$ cat leds.lds 6 | SECTIONS { 7 | . = 0x00; //当前地址为0,即从0地址开始排放 8 | .text : { *(.text) } // * 表示所有文件 9 | .rodata ALIGN(4) : {*(.rodata)} 10 | .data ALIGN(4) : { *(.data) } 11 | .bss ALIGN(4) : { *(.bss) *(COMMON) } 12 | } 13 | ``` 14 | 2. `makefile` : `指定链接顺序` 15 | ``` 16 | galen@66:/work/hardware/leds$ cat Makefile 17 | CFLAGS := -Wall -Wstrict-prototypes -g -fomit-frame-pointer -ffreestanding 18 | all : crt0.S leds.c 19 | arm-linux-gcc $(CFLAGS) -c -o crt0.o crt0.S 20 | arm-linux-gcc $(CFLAGS) -c -o leds.o leds.c 21 | arm-linux-ld -Tleds.lds crt0.o leds.o -o leds_elf //指定链接顺序 22 | arm-linux-objcopy -O binary -S leds_elf leds.bin 23 | arm-linux-objdump -D -m arm leds_elf > leds.dis 24 | clean: 25 | rm -f leds.dis leds.bin leds_elf *.o 26 | ``` 27 | 3. `makefile规则` 28 | * `规则1` 29 | * ![规则1](https://github.com/GalenDeng/Embedded-Linux/blob/master/1.%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/1.5%20leds.lds%E5%92%8Cmakefile%E8%A7%84%E5%88%99%E4%BB%8B%E7%BB%8D/makefile%E8%A7%84%E5%88%99.PNG) 30 | * `规则2` 31 | * ![规则2](https://github.com/GalenDeng/Embedded-Linux/blob/master/1.%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/1.5%20leds.lds%E5%92%8Cmakefile%E8%A7%84%E5%88%99%E4%BB%8B%E7%BB%8D/makefile%E8%A7%84%E5%88%992.PNG) 32 | * `makefile中的链接与编译操作分离写法` 33 | * ![makefile中的链接与编译操作分离写法](https://github.com/GalenDeng/Embedded-Linux/blob/master/1.%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/1.5%20leds.lds%E5%92%8Cmakefile%E8%A7%84%E5%88%99%E4%BB%8B%E7%BB%8D/makefile%E4%B8%AD%E6%8A%8A%E9%93%BE%E6%8E%A5(link)%E5%92%8C%E7%BC%96%E8%AF%91(compile)%E5%88%86%E5%BC%80.PNG) 34 | * `makefile通配符写法` 35 | * ![makefile通配符写法](https://github.com/GalenDeng/Embedded-Linux/blob/master/1.%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/1.5%20leds.lds%E5%92%8Cmakefile%E8%A7%84%E5%88%99%E4%BB%8B%E7%BB%8D/%E9%80%9A%E9%85%8D%E7%AC%A6%E5%86%99%E6%B3%95%E7%9A%84makefile.png) 36 | ``` 37 | % : 通配符 // %.o : %.c 38 | $@ : 表示规则的目标文件名 // 这里指定 hello : hello.o a.o 中的hello 39 | $^ : 表示所有依赖的名字 // 这里指定 hello : hello.o a.o 中的hello.o a.o 40 | $< : 表示第一个依赖名 41 | // 这里指定 42 | hello.o : hello.c 43 | gcc -o hello.o -c hello.c 44 | a.o : a.c 45 | gcc -o a.o -c a.c 46 | ``` 47 | * 虚拟命令clean 48 | * ![clean](https://github.com/GalenDeng/Embedded-Linux/blob/master/1.%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/1.5%20leds.lds%E5%92%8Cmakefile%E8%A7%84%E5%88%99%E4%BB%8B%E7%BB%8D/make_clean%E8%99%9A%E6%8B%9F%E5%91%BD%E4%BB%A4.png) -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/boot.c: -------------------------------------------------------------------------------- 1 | #include "setup.h" 2 | extern void uart0_init(void); 3 | extern void nand_read(unsigned int addr,unsigned char *buf, unsigned int len); 4 | extern void puts(char *str); 5 | extern void puthex(unsigned int val); 6 | 7 | static struct tag *params; 8 | void setup_start_tag(void) 9 | { 10 | // 放置设置参数的地方 0x30000100 11 | params = (struct tag *)0x30000100; 12 | // tag_header内容: tag size 13 | params->hdr.tag = ATAG_CORE; // tag = 0x54410001 => 参数的开始 14 | params->hdr.size = tag_size (tag_core); 15 | 16 | params->u.core.flags = 0; 17 | params->u.core.pagesize = 0; 18 | params->u.core.rootdev = 0; 19 | 20 | params = tag_next (params); // 设置标记的末尾位置,即指向当前标记的末尾 21 | } 22 | void setup_memory_tags(void) 23 | { 24 | params->hdr.tag = ATAG_MEM; 25 | params->hdr.size = tag_size (tag_mem32); 26 | 27 | params->u.mem.start = 0x30000000; 28 | params->u.mem.size = 0x04000000; 29 | 30 | params = tag_next (params); 31 | } 32 | 33 | int strlen(char *str) 34 | { 35 | int i = 0; 36 | while (str[i]) 37 | { 38 | i++; 39 | } 40 | return i; 41 | } 42 | 43 | void strcpy(char *dest, char *src) 44 | { 45 | while ((*dest++ = *src++) != '\0'); 46 | } 47 | 48 | void setup_commandline_tag(char *cmdline) 49 | { 50 | int len = strlen(cmdline) + 1; 51 | 52 | params->hdr.tag = ATAG_CMDLINE; 53 | params->hdr.size = (sizeof (struct tag_header) + len + 3) >> 2; // 加3比加4好 54 | 55 | strcpy (params->u.cmdline.cmdline, cmdline); // 拷贝进tag列表中 56 | 57 | params = tag_next (params); 58 | } 59 | void setup_end_tag(void) 60 | { 61 | params->hdr.tag = ATAG_NONE; 62 | params->hdr.size = 0; 63 | } 64 | 65 | 66 | int main(void) 67 | { 68 | void (*theKernel)(int zero, int arch, unsigned int params); 69 | volatile unsigned int *p = (volatile unsigned int *)0x30008000; 70 | /* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口 */ 71 | uart0_init(); 72 | 73 | /* 1. 从NAND FLASH里把内核读入内存 */ 74 | puts("Copy kernel from nand\n\r"); 75 | nand_read(0x60000 + 64,(unsigned char *)0x30008000,0x200000); //src , dest , len 76 | puthex(0x1234ABCD); 77 | puts("\n\r"); 78 | puthex(*p); 79 | puts("\n\r"); 80 | /* 2. 设置参数 --- 通过tag的方式*/ 81 | puts("Set boot params\n\r"); 82 | setup_start_tag(); 83 | setup_memory_tags(); 84 | setup_commandline_tag("noinitrd root=/dev/nfs nfsroot=192.168.99.140:/work/nfs_root/app,rsize=1024,wsize=1024 ip=192.168.99.135:192.168.99.140:192.168.99.4:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0"); 85 | setup_end_tag(); 86 | /* 3. 跳转执行 */ 87 | puts("Boot kernel\n\r"); 88 | theKernel = (void (*)(int, int, unsigned int))0x30008000; // 跳转到0x30008000 89 | theKernel(0,362,0x30000100); 90 | /* 等同于 mov pc, #0x30008000 */ 91 | /* mov r0, #0 */ 92 | /* ldr r1, =362 */ 93 | /* ldr r2, =0x30000100 */ 94 | puts("Error!\n\r"); 95 | /* 如果一切正常,不会执行到这里 */ 96 | return -1; 97 | } 98 | -------------------------------------------------------------------------------- /4. 通过tftp、nfs进行uboot下载烧写步骤详情/通过tftp、nfs进行uboot下载烧写步骤详情.md: -------------------------------------------------------------------------------- 1 | ## 通过tftp进行uboot的下载步骤详情 (2017.12.6) 2 | 1. `下载tftpboot软件,并安装` 3 | 2. 打开`tftpd32软件`,`选择要下载的文件的地址`,选择`本电脑的IP地址` 4 | * ![tftp设置](https://github.com/GalenDeng/Embedded-Linux/blob/master/4.%E9%80%9A%E8%BF%87tftpboot%E4%B8%8B%E8%BD%BDuboot%E7%AD%89bin%E6%96%87%E4%BB%B6/tftpboot%E8%AE%BE%E7%BD%AE.JPG) 5 | 3. NOR flash启动单板,按空格进行u-boot的菜单栏,按 q 退出 menu 6 | 进入到 openjtag 中, 设置 ipaddr serverip ,其中 serverip要和电脑的IP相同,而 ipaddr可以随便设置,但要保证其和serverip在同一个网段下,最后 `save` 7 | * ![ip设置](https://github.com/GalenDeng/Embedded-Linux/blob/master/4.%E9%80%9A%E8%BF%87tftpboot%E4%B8%8B%E8%BD%BDuboot%E7%AD%89bin%E6%96%87%E4%BB%B6/%E8%AE%BE%E7%BD%AEIP%E5%B9%B6%E8%BF%9B%E8%A1%8C%E7%A8%8B%E5%BA%8F%E7%9A%84%E4%B8%8B%E8%BD%BD%E6%93%8D%E4%BD%9C.JPG) 8 | * openjtag > print //print可查看网络的设置情况 9 | * ![查看网络设置](https://github.com/GalenDeng/Embedded-Linux/blob/master/4.%E9%80%9A%E8%BF%87tftpboot%E4%B8%8B%E8%BD%BDuboot%E7%AD%89bin%E6%96%87%E4%BB%B6/u-boot%E7%9A%84%E8%8F%9C%E5%8D%95%E6%A0%8F%E6%93%8D%E4%BD%9C1.JPG) 10 | 4. 在u-boot菜单栏中 ping 一下 电脑的 IP 看是否 ping 通 11 | 5. `下载` 12 | * tftp 30000000 lcd.bin // 30000000:为烧写地址 lcd.bin 为 二进制程序 这里不用指定目录,因为tftpd32已经指定了目录的地址 13 | 6. `显示分区` 14 | ``` 15 | OpenJTAG> mtdpart 16 | 17 | device nand0 , # parts = 4 18 | #: name size offset mask_flags 19 | 0: bootloader 0x00040000 0x00000000 0 20 | 1: params 0x00020000 0x00040000 0 21 | 2: kernel 0x00200000 0x00060000 0 22 | 3: root 0x0fda0000 0x00260000 0 23 | 24 | active partition: nand0,0 - (bootloader) 0x00040000 @ 0x00000000 25 | 26 | defaults: 27 | mtdids : nand0=nandflash0 28 | mtdparts: mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root) 29 | ``` 30 | 31 | ## tftp烧写内核步骤 32 | 1. 打开tftpd32软件,设置本地IP、要下载的文件目录地址,准备进行网络下载 33 | 2. 进入到openJTAG > 中, 确保 tftp服务已打开 , 设置 ipaddr serverip , save 34 | 3. tftp 30000000 uImage //把取到的uImage下载到开发板的0x30000000中 35 | 4. mtdpart查看分区信息 36 | 5. nand erase kernel //擦除kernel分区 37 | 6. nand wirte.jffs2 30000000 kernel //之前我们下载的文件放在 0x30000000这个位置了,现在把它烧写在kernel里面 38 | 39 | ## tftp烧写fs_qtopia(文件系统)步骤 40 | 1. tftp 30000000 fs_qtopia.yaffs2 41 | 2. nand erase root 42 | 3. nand write.yaffs 30000000 00260000 $(filesize) 43 | //$(filesize) : 表示下载的文件的大小,我们可以直接查看下载的文件有多大,写具体的size上去 44 | 45 | ## NFS烧写内核步骤 46 | 1. nfs 30000000 192.168.99.140:/work/nfs_root/uImage 47 | // 这里的nfs_root必须是被支持挂载的,可以在 /etc/export查看,如: 48 | ![被支持的挂载文件目录](https://github.com/GalenDeng/Embedded-Linux/blob/master/4.%20%E9%80%9A%E8%BF%87tftp%E3%80%81nfs%E8%BF%9B%E8%A1%8Cuboot%E4%B8%8B%E8%BD%BD%E7%83%A7%E5%86%99%E6%AD%A5%E9%AA%A4%E8%AF%A6%E6%83%85/%E5%8F%AF%E4%BB%A5%E6%8C%82%E8%BD%BD%E7%9A%84%E7%9B%AE%E5%BD%95%E8%AE%BE%E7%BD%AE.JPG) 49 | * /work/nfs_root *(rw,sync,no_root_squash) // 在 /etc/exports 添加 然后重启 sudo /etc/init.d/nfs-kernel-server restart即可 50 | 2. nand erase kernel 51 | 3. nand write.yaffs2 30000000 kernel 52 | 53 | ## NFS烧写文件系统步骤 54 | 1. nfs 30000000 192.168.99.140:/work/nfs_root/fs_qtopia.yaffs2 55 | 2. nand erase root 56 | 3. nand write.yaffs 30000000 260000 2f76b40 // 2f76b40 为下载的文件大小 57 | -------------------------------------------------------------------------------- /8. 软件与硬件初始化/8. 软件与硬件初始化.md: -------------------------------------------------------------------------------- 1 | ## 软件与硬件初始化 (2017.12.08) 2 | ## `程序执行步骤` 3 | ![程序执行步骤](https://github.com/GalenDeng/Embedded-Linux/blob/master/8.%20%E8%BD%AF%E4%BB%B6%E4%B8%8E%E7%A1%AC%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96/%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C%E6%AD%A5%E9%AA%A4.JPG) 4 | ## `nand启动方式` 5 | ![nand启动](https://github.com/GalenDeng/Embedded-Linux/blob/master/8.%20%E8%BD%AF%E4%BB%B6%E4%B8%8E%E7%A1%AC%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96/nand%E5%90%AF%E5%8A%A8.JPG) 6 | ## `NOR启动与nand启动对比` 7 | ![NOR启动与nand启动对比](https://github.com/GalenDeng/Embedded-Linux/blob/master/8.%20%E8%BD%AF%E4%BB%B6%E4%B8%8E%E7%A1%AC%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96/NOR%E5%90%AF%E5%8A%A8%E5%92%8CNand%E5%90%AF%E5%8A%A8%E7%9A%84%E5%8C%BA%E5%88%AB.JPG) 8 | ## `main的调用与返回` 9 | ![main的调用与返回](https://github.com/GalenDeng/Embedded-Linux/blob/master/8.%20%E8%BD%AF%E4%BB%B6%E4%B8%8E%E7%A1%AC%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96/main%E7%9A%84%E8%B0%83%E7%94%A8%E4%B8%8E%E8%BF%94%E5%9B%9E.JPG) 10 | ## `初始化` 11 | ![初始化](https://github.com/GalenDeng/Embedded-Linux/blob/master/8.%20%E8%BD%AF%E4%BB%B6%E4%B8%8E%E7%A1%AC%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96/%E5%88%9D%E5%A7%8B%E5%8C%96.JPG) 12 | * SRAM : 片内RAM 不用设置栈 SDRAM : 要设置栈 13 | * `硬件初始化文件 crt0.S (汇编)` 14 | ``` 15 | galen@HD66:/work/nfs_root/hardware/led_on_c$ cat crt0.S 16 | @****************************************************************************** 17 | @ File:crt0.S 18 | @ 功能:通过它转入C程序 19 | @****************************************************************************** 20 | .text 21 | .global _start 22 | _start: 23 | ldr r0, =0x56000010 @ WATCHDOG寄存器地址 24 | mov r1, #0x0 25 | str r1, [r0] @ 写入0,禁止WATCHDOG,否则CPU会不断重启 26 | 27 | ldr sp, =1024*4 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K 28 | @ nand flash中的代码在复位后会移到内部ram中,此ram只有4K 29 | bl main @ 调用C程序中的main函数 //跳转到main函数,并把返回值保存到lr寄存器里面 30 | halt_loop: // 这句开始就是返回的清理工作,这里的处理是死循环 31 | b halt_loop 32 | ``` 33 | ## `*(volatile unsigned int *)0x56000050解释` 34 | ``` 35 | #define GPBCON (*(volatile unsigned long *)0x56000010) //这里的 volatile 的作用是让编译器不要优化代码 36 | #define GPBDAT (*(volatile unsigned long *)0x56000014) 37 | int main() 38 | { 39 | GPBCON = 0x00000400; // 设置GPB5为输出口, 位[11:10]=0b01 40 | GPBDAT = 0x00000000; // GPB5输出0,LED1点亮 41 | return 0; 42 | } 43 | ``` 44 | ![强制转换解释](https://github.com/GalenDeng/Embedded-Linux/blob/master/8.%20%E8%BD%AF%E4%BB%B6%E4%B8%8E%E7%A1%AC%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96/%E5%BC%BA%E5%88%B6%E8%BD%AC%E6%8D%A2%E8%A7%A3%E9%87%8A.JPG) 45 | 46 | ## arm-linux-objdump : 用于显示二进制文件信息 ---常用来查看反汇编代码 47 | * arm-linux-objdump -D -m arm led_on_c_elf > led_on_c.dis 48 | // -D :--disassembale-all 反汇编所有段 -m machine ; -m arm 指定反汇编目标文件时使用的架构 49 | // led_on_c.dis : 反汇编文件 50 | 51 | ## 清零和置位的常见操作方式 52 | * 置1 :a = a | (1 << 3) 53 | * 清零 :a = a & (~ (1 << 3)) 54 | ![置1/清0](https://github.com/GalenDeng/Embedded-Linux/blob/master/8.%20%E8%BD%AF%E4%BB%B6%E4%B8%8E%E7%A1%AC%E4%BB%B6%E5%88%9D%E5%A7%8B%E5%8C%96/%E6%B8%85%E9%9B%B6%E5%92%8C%E7%BD%AE%E4%BD%8D%E7%9A%84%E5%B8%B8%E8%A7%81%E6%93%8D%E4%BD%9C%E6%96%B9%E5%BC%8F.JPG) 55 | -------------------------------------------------------------------------------- /数码相框项目/字符编码方式/字符编码方式.md: -------------------------------------------------------------------------------- 1 | ## 字符编码方式 (2018.1.4) 2 | ## 字符编码注意事项 3 | ![字符编码注意事项](https://github.com/GalenDeng/Embedded-Linux/blob/master/%E6%95%B0%E7%A0%81%E7%9B%B8%E6%A1%86%E9%A1%B9%E7%9B%AE/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%E6%96%B9%E5%BC%8F/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9.jpg) 4 | 1. 国标 : GB 5 | 2. 国标扩展 : GBK 6 | 3. 字符编码 : 两个字节表示一个汉字 7 | 4. 港澳台: 繁体字 : BIG5 8 | # 字符编码解释链接 9 | [字符编码解释链接](http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html) 10 | * 字符 11 | ``` 12 | 数字 ==> 代表什么 ==> 显示为什么(字体:宋体、黑体等) 13 | 字符编码 : ASCII码 GBK BIG5 14 | ``` 15 | ## 字体文件包括 16 | ![字体文件包括](https://github.com/GalenDeng/Embedded-Linux/blob/master/%E6%95%B0%E7%A0%81%E7%9B%B8%E6%A1%86%E9%A1%B9%E7%9B%AE/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%E6%96%B9%E5%BC%8F/%E5%AD%97%E4%BD%93%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9.JPG) 17 | * 字符全世界统一 : unicode编码表 18 | * unicode的表示方法: (以abc中为例) 19 | * unicode编码表只是规定了 数值和字符/字间的映射,并没有规定其存储的方式,所以存储的方式有多种,如 utf-8,utf-16 20 | ![utf-8规则图片解释](https://github.com/GalenDeng/Embedded-Linux/blob/master/%E6%95%B0%E7%A0%81%E7%9B%B8%E6%A1%86%E9%A1%B9%E7%9B%AE/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%E6%96%B9%E5%BC%8F/utf-8%E7%BC%96%E7%A0%81%E8%A7%84%E5%88%99.JPG) 21 | ``` 22 | UTF-8 23 | EF BB BF 61 62 63 E4 B8 AD 24 | ``` 25 | E4 B8 AD 26 | 11100100 10111000 10101101 27 | 这里最前面连续三个111表示这个字符由三个字节构成 而 10 10 是固定的 28 | 0100 1000 1101 组成unicode码 4E 2D 29 | 30 | 规则: 31 | UTF-8 的编码规则很简单,只有二条: 32 | 1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。 33 | 因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。 34 | 2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0, 35 | 后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。 36 | ``` 37 | 38 | UTF-16LE left endian : 小端 FF FE : 表示小端 39 | FF FE 61 00 62 00 63 00 2D 4E 40 | UTE-16BE big endian : 大端 FE FF : 表示大端 41 | FE FF 00 61 00 62 00 63 4E 2D 42 | ansi: 43 | 61 62 63 D6 D0 44 | ``` 45 | ## 在linux系统中同一段的代码,由于保存文本的格式不一样,打印出来的信息也不一样 ---解决方法:charset 46 | ``` 47 | 源文件用不同的编码方式编写,会导致执行结果不一样。 48 | 怎么解决?编译程序时,要指定字符集 49 | man gcc , /charset 50 | -finput-charset=charset 表示源文件的编码方式, 默认以UTF-8来解析 51 | -fexec-charset=charset 表示可执行程序里的字时候以什么编码方式来表示,默认是UTF-8 52 | 53 | gcc -o a a.c // 54 | 55 | gcc -finput-charset=GBK -fexec-charset=UTF-8 -o utf-8_2 ansi.c 56 | ``` 57 | 1. `源文件的编码方式不一样,会导致执行结果不一样` 58 | ``` 59 | galen@HD66:/work/数码相框测试$ cat ansi.c 60 | #include 61 | 62 | int main(int argc, char **argv) 63 | { 64 | int i = 0; 65 | unsigned char *str="abc?"; 66 | 67 | while (str[i]) 68 | { 69 | printf("%02x ", str[i]); 70 | i++; 71 | } 72 | printf("\n"); 73 | return 0; 74 | }galen@HD66:/work/数码相框测试$ 75 | galen@HD66:/work/数码相框测试$ 76 | galen@HD66:/work/数码相框测试$ gcc -o ansi ansi.c 77 | galen@HD66:/work/数码相框测试$ gcc -o utf-8 utf-8.c 78 | galen@HD66:/work/数码相框测试$ 79 | galen@HD66:/work/数码相框测试$ 80 | galen@HD66:/work/数码相框测试$ ls 81 | ansi ansi.c utf-8 utf-8.c 82 | galen@HD66:/work/数码相框测试$ ./ansi 83 | 61 62 63 d6 d0 84 | galen@HD66:/work/数码相框测试$ ./utf-8 85 | 61 62 63 e4 b8 ad 86 | ``` 87 | 2. 88 | * man gcc 89 | * /charset // 查找字符集 90 | * -fexec-charset : 设置编译的字符集 91 | * -finput-charset: 设置输入的字符集 92 | ``` 93 | galen@HD66:/work/数码相框测试$ gcc -finput-charset=GBK -fexec-charset=UTF-8 -o ansi2 ansi.c 94 | galen@HD66:/work/数码相框测试$ ./ansi2 95 | 61 62 63 e4 b8 ad 96 | galen@HD66:/work/数码相框测试$ 97 | ``` 98 | -------------------------------------------------------------------------------- /11. Nand flash控制器/Nand flash控制器.md: -------------------------------------------------------------------------------- 1 | ## Nand flash控制器 (2017.12.18) 2 | ## 不同的寻址方式 3 | ![不同的寻址方式](https://github.com/GalenDeng/Embedded-Linux/blob/master/11.%20Nand%20flash%E6%8E%A7%E5%88%B6%E5%99%A8/Nand%20flash%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E4%B8%8D%E5%90%8C%E7%9A%84%E5%AF%BB%E5%9D%80%E6%96%B9%E5%BC%8F.JPG) 4 | * 凡是芯片的地址线和cpu的引脚直接相连的,这种连接方式是cpu统一编址的,cpu不经其他外设直接连接 5 | * Nand flash 和 s3c2440只有数据线相连,而没有任何地址线相连,所以不属于cpu统一编址系列 6 | ## Nand flash结构 7 | ![Nand flash结构](https://github.com/GalenDeng/Embedded-Linux/blob/master/11.%20Nand%20flash%E6%8E%A7%E5%88%B6%E5%99%A8/Nand%20flash%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/Nand%20flash%E7%BB%93%E6%9E%84.JPG) 8 | ## s3c2440访问Nand flash 9 | ![s3c2440访问Nand flash](https://github.com/GalenDeng/Embedded-Linux/blob/master/11.%20Nand%20flash%E6%8E%A7%E5%88%B6%E5%99%A8/Nand%20flash%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/s3c2440%E8%AE%BF%E9%97%AENand%20flash.JPG) 10 | ## 从nand那里读取led代码进SDRAM中并启动 11 | ![从nand那里读取led代码进SDRAM中并启动](https://github.com/GalenDeng/Embedded-Linux/blob/master/11.%20Nand%20flash%E6%8E%A7%E5%88%B6%E5%99%A8/Nand%20flash%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E4%BB%8Enand%E9%82%A3%E9%87%8C%E8%AF%BB%E5%8F%96led%E4%BB%A3%E7%A0%81%E8%BF%9BSDRAM%E4%B8%AD%E5%B9%B6%E5%90%AF%E5%8A%A8.JPG) 12 | * `nand.lds` 13 | ``` 14 | SECTIONS { 15 | firtst 0x00000000 : { head.o init.o nand.o} 16 | second 0x30000000 : AT(4096) { main.o } 17 | } 18 | ``` 19 | * `r0、r1、r2 : 分别对应第一个参数,第二个参数,第三个参数` 20 | ``` 21 | ldr r0, =0x30000000 @1. 目标地址=0x30000000,这是SDRAM的起始地址 22 | mov r1, #4096 @2. 源地址 = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处 23 | mov r2, #2048 @3. 复制长度= 2048(bytes),对于本实验的main.c,这是足够了 24 | bl nand_read @调用C函数nand_read 25 | ``` 26 | ``` 27 | /* 读函数 */ 28 | void nand_read(unsigned char *buf, unsigned long start_addr, int size) // nand_read的函数 29 | ``` 30 | * `即 r0 = buf ; r1 = start_addr ; r2 = size` 31 | 32 | 1. `Nand Flash介绍和 Nand Flash控制器` 33 | ``` 34 | * Nand Flash 在嵌入式系统中的地位与PC上的硬盘相类似,用于保存系统运行所必需的操作系统、应用程序、用户数据、运行过程中产生的各类数据。 35 | * 内存掉电后数据丢失,NAND FLASH中的数据在掉电后可永远保存 36 | ``` 37 | 2. `Nor Flash 和 Nand flash` 38 | * Nor Flash 支持XIP,即代码可以直接在Nor Flash上执行,无需复制到内存,因为其接口和RAM一样,可随机访问任意地址的数据 39 | * 通常用Nor Flash运行程序,Nand Flash存储数据 40 | * 在 Nor Flash上常用jffs2文件系统,在 Nand Flash上常用yaffs文件系统 41 | * Flash存储器件的可靠性考虑: 位反转 、 坏块 、可擦除次数 42 | * 位反转解决方式 : EDC/ECC 进行错误检测和恢复 43 | 3. `操作方法` 44 | ``` 45 | * 操作Nand Flash时,先传输命令,然后传输地址,最后读/写数据,期间要检查Flash的状态,对于K9F1208U0M,它的容量为 64M = 2^20 * 2^6,需要一个26位的地址,发出命令后,后面要紧跟着4个地址序列,比如读Flash的时候,发出读命令和4个地址序列后,后续的读操作就可以得到这个地址及其后续地址的数据 46 | ``` 47 | 4. `读地址操作` 48 | ## 读地址操作图片解释 49 | ![读地址操作图片解释](https://github.com/GalenDeng/Embedded-Linux/blob/master/11.%20Nand%20flash%E6%8E%A7%E5%88%B6%E5%99%A8/Nand%20flash%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E8%AF%BB%E5%9C%B0%E5%9D%80%E6%93%8D%E4%BD%9C%E5%9B%BE%E7%89%87%E8%A7%A3%E9%87%8A.JPG) 50 | * 代码 51 | ``` 52 | void nand_addr(unsigned int addr) 53 | { 54 | unsigned int col = addr % 2048; // 数据手册中页读写空间为2k = 2 * 2^10 列地址 55 | unsigned int page = addr / 2048; // 行地址 56 | volatile int i; 57 | 58 | NFADDR = col & 0xff; // 截取低字节8位 59 | for (i = 0; i < 10; i++); // 延时 60 | NFADDR = (col >> 8) & 0xff; 61 | for (i = 0; i < 10; i++); 62 | 63 | NFADDR = page & 0xff; 64 | for (i = 0; i < 10; i++); 65 | NFADDR = (page >> 8) & 0xff; 66 | for (i = 0; i < 10; i++); 67 | NFADDR = (page >> 16) & 0xff; 68 | for (i = 0; i < 10; i++); 69 | } 70 | ``` -------------------------------------------------------------------------------- /12. 中断控制器/12.1 中断控制器.md: -------------------------------------------------------------------------------- 1 | ## 中断控制器 (2017.12.19) 2 | * CRSR : Current Program Status Resgister 当前程序状态寄存器 3 | * SRSR : Saved Process Status Register 程序状态保存寄存器 4 | * 存在 CRSR 和 SRSR 是为了不同工作模式切换时的数据的拷贝 5 | * INTOFFSET : 查看当前使用哪个中断 6 | ## 1.ARM的7种中断模式 7 | ![ARM的7种中断模式](https://github.com/GalenDeng/Embedded-Linux/blob/master/12.%20%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8/%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/ARM%E7%9A%847%E7%A7%8D%E4%B8%AD%E6%96%AD%E6%A8%A1%E5%BC%8F.JPG) 8 | ## 2.ARM状态下各工作模式使用的寄存器 9 | ![ARM状态下各工作模式使用的寄存器](https://github.com/GalenDeng/Embedded-Linux/blob/master/12.%20%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8/%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/ARM%E7%8A%B6%E6%80%81%E4%B8%8B%E5%90%84%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F%E4%BD%BF%E7%94%A8%E7%9A%84%E5%AF%84%E5%AD%98%E5%99%A8.JPG) 10 | ## 3. head.S介绍 11 | ``` 12 | b Reset // 发送RESET事件后,跳转到这里执行RESET命令 13 | 14 | @ 0x04: 未定义指令中止模式的向量地址 15 | HandleUndef: 16 | b HandleUndef 17 | 18 | @ 0x18: 中断模式的向量地址 // 发生中断时,CPU进入中断模式,并跳到0x18地址开始执行 19 | b HandleIRQ 20 | 21 | Reset: 22 | ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈 23 | bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 24 | 25 | msr cpsr_c, #0xd2 @ 进入中断模式 // 这里是设置程序状态寄存器格式 进入异常事件也要设置栈 26 | ldr sp, =3072 @ 设置中断模式栈指针 27 | 28 | msr cpsr_c, #0xd3 @ 进入管理模式 29 | ldr sp, =4096 @ 设置管理模式栈指针, 30 | @ 其实复位之后,CPU就处于管理模式, 31 | @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略 32 | 33 | bl init_led @ 初始化LED的GPIO管脚 34 | bl init_irq @ 调用中断初始化函数,在init.c中 35 | msr cpsr_c, #0x5f @ 设置I-bit=0,开IRQ中断 // 总中断开关打开 36 | 37 | ldr lr, =halt_loop @ 设置返回地址 38 | ldr pc, =main @ 调用main函数 39 | halt_loop: 40 | b halt_loop 41 | 42 | HandleIRQ: 43 | sub lr, lr, #4 @ 计算返回地址 // lr寄存器的值等于被中断指令的地址加4,所以 // 返回地址为lr的值减去4 44 | stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器 45 | @ 注意,此时的sp是中断模式的sp 46 | @ 初始值是上面设置的3072 47 | 48 | ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址 49 | ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中 50 | int_return: 51 | ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr // spsr为备份寄存器,正常的状态寄存器是用cpsr 52 | ``` 53 | ## 4. 怎么用中断 54 | ![怎么用中断](https://github.com/GalenDeng/Embedded-Linux/blob/master/12.%20%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8/%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E6%80%8E%E4%B9%88%E7%94%A8%E4%B8%AD%E6%96%AD.JPG) 55 | ## 5. 中断触发方式 56 | * `低电平触发、高电平触发、下降沿触发、上升沿触发` 57 | ## 6. 程序状态寄存器格式 58 | ![程序状态寄存器格式](https://github.com/GalenDeng/Embedded-Linux/blob/master/12.%20%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8/%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E7%A8%8B%E5%BA%8F%E7%8A%B6%E6%80%81%E5%AF%84%E5%AD%98%E5%99%A8%E6%A0%BC%E5%BC%8F.JPG) 59 | ## 7. 中断清除顺序 60 | * EINTREND ===> SRCPND ===> INTPND 61 | ## 8. 中断执行过程 62 | ![中断执行过程](https://github.com/GalenDeng/Embedded-Linux/blob/master/12.%20%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8/%E4%B8%AD%E6%96%AD%E6%8E%A7%E5%88%B6%E5%99%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E4%B8%AD%E6%96%AD%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B.JPG) -------------------------------------------------------------------------------- /汇编指令.md: -------------------------------------------------------------------------------- 1 | ## 汇编指令 (2017.12.10) 2 | 1. `sub -- add` 3 | ``` 4 | sub ax,9 给ax减9,之后的结果赋值给ax 5 | sub ax,bx 语意是ax = bx - ax 6 | sub ax,[0] 将偏移地址为0的内存单元 - ax 再赋值给ax 7 | 8 | add r1,r2,#1 /* r1=r2+1 r2寄存器的值 + 1 赋给 r1 / 9 | sub r1,r2,#1 /* r1=r2+1 r2寄存器的值 - 1 赋给 r1 / 10 | ``` 11 | 2. `数据传送指令 mov` 12 | * mov r1, r2 /* r1=r2 把一个寄存器的值赋给另一个寄存器 */ 13 | * mov r1, #4096 /* r1=4096 把一个常数赋给寄存器 */ 14 | * mov指令传送的常数必须能用立即数来表示 15 | 16 | 3. `地址读取伪指令 ldr` : `load register 加载到寄存器中 --32位数据` 17 | * 当不知道一个数能否用“立即数”来表示时,常用 ldr命令来赋值 18 | * 伪指令 -- 不是真实存在的指令--编译器会把它扩展为真正的指令,若可用“立即数表示”,便用mov, 19 | 否则编译的时候把该常数保存在某个位置,使用内存读取指令读取 20 | * ldr r1, =4097 /* r1=4097 */ 21 | * ldr命令的第二个参数前面有`"="`时,表示伪指令,否则表示内存访问指令 22 | 23 | 4. `立即数` 24 | ``` 25 | 有# 立即数 就是 50 26 | 没有 # 表示内存地址为50中的值 27 | mov a,#50 ;将50这个数送到a中去 28 | mov a,50 ;将内存地址为50的内存单元中的数送到a中去 29 | ``` 30 | 5. `str : storage -- 把寄存器的值存储到内存中 -- 32位数据 ` 31 | ## 具体操作方式 32 | ![具体操作方式](https://github.com/GalenDeng/Embedded-Linux/blob/master/%E6%B1%87%E7%BC%96%E6%8C%87%E4%BB%A4%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/ldr%E5%92%8Cstr%E5%91%BD%E4%BB%A4.JPG) 33 | 34 | 6. `ldm和stm` 35 | ## 命令介绍 36 | ![命令介绍](https://github.com/GalenDeng/Embedded-Linux/blob/master/%E6%B1%87%E7%BC%96%E6%8C%87%E4%BB%A4%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/ldm%E5%92%8Cstm%E5%91%BD%E4%BB%A4.JPG) 37 | * ia : increase after ; ib : increase before ; da : decrease after ; db : decrease before 38 | * ldmia r0!, {r3-r10} // 把r0的地址开始,把数据copy到 r3-r10 39 | * stmia r1!, {r3-r10} // 把 r3-r10的数据copy地址[r1]处 40 | 41 | 7. `MSR和MRS` 42 | * cpsr: Program status register // 程序状态寄存器 --- 控制处理器的工作模式、设置中断的总开关 43 | ``` 44 | MRS指令的格式为: 45 | MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR) 46 | MRS指令用于将程序状态寄存器的内容传送到通用寄存器中 47 | Ⅰ.当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。 48 | Ⅱ.当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。 49 | 指令示例: 50 | MRS R0,CPSR @传送CPSR的内容到R0 51 | MRS R0,SPSR @传送SPSR的内容到R0 52 | ``` 53 | ``` 54 | MSR指令的格式为: 55 | MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操作数 56 | MSR指令用亍将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域: 57 | 位[31:24]为条件标志位域,用f表示; 58 | 位[23:16]为状态位域,用s表示; 59 | 位[15:8]为扩展位域,用x表示; 60 | 位[7:0]为控制位域,用c表示; 61 | 62 | 该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。 63 | 指令示例: 64 | MSR CPSR,R0 @传送R0的内容到CPSR 65 | MSR SPSR,R0 @传送R0的内容到SPSR 66 | MSR CPSR_c,R0 @传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域 67 | ``` 68 | 8. `其他伪指令` 69 | * .extern main // .extern 定义一个外部符号(变量 or 函数) 70 | * .text //表示下面的语句属于代码段 71 | * .global _start // 将本文件中的某个程序符号定义为全局的, _start : 全局函数 72 | 9. `参数传递规则` 73 | * r0 - r3 一般用来传递参数,参数超过四个,剩余的参数通过数据栈来传递 74 | * a0 - a3 一般用来返回结果 75 | ## 例子 76 | ![例子](https://github.com/GalenDeng/Embedded-Linux/blob/master/%E6%B1%87%E7%BC%96%E6%8C%87%E4%BB%A4%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92%E8%A7%84%E5%88%99%E4%BE%8B%E5%AD%90.JPG) 77 | 10. `bne 1b 与 beq 1f` 78 | * bne : bool not equal // A != B 时适用 79 | * beq : bool equal // A == B 时适用 80 | * b : before 81 | * f : after 82 | * 1 : 局部标号 83 | ``` 84 | head.S中初始化内存有以下一段程序: 85 | ENTRY(memsetup) 86 | @ initialise the static memory 87 | @ set memory control registers 88 | mov r1, #MEM_CTL_BASE 89 | adrl r2, mem_cfg_val 90 | add r3, r1, #52 91 | 1: ldr r4, [r2], #4 <----又跳到这 92 | str r4, [r1], #4 93 | cmp r1, r3 94 | bne 1b 95 | 当标号为0~9的数字时为局部标号,局部标号可以重复出现,使用方法如下: 96 |  标号f: 表示往前跳,顺序执行的话是没有运行过的程序 ,front的意思。 97 |  标号b: 表示跳转到以前执行过的语句,第一个1标号处 ,back的意思。 98 | 99 | head.S中还有很多这样的语句也不难理解 100 | 1: b 1b @ infinite loop 无限循环 101 | 只要想着 b 就是back,回去的意思,回到以前那个标号1处,这里即当前标号,即永远循环执行这个语句,相当于while(1)。 102 | ``` 103 | ``` 104 | 1: ;A 105 | cmp r0, #0 106 | beq 1f ; r0==0那么向前跳转到B处执行 107 | bne 1b ; 否则向后跳转到A处执行 108 | 1: ;B 109 | ``` -------------------------------------------------------------------------------- /6. 通过nfs进行下载烧写--配置NFS网络文件系统的挂载卸载--制作镜像文件--虚拟机和开发板的交叉编译操作(通过MFS共享目录/通过nfs进行下载烧写--配置NFS网络文件系统的挂载卸载--制作镜像文件--虚拟机和开发板的交叉编译操作(通过MFS共享目录.md: -------------------------------------------------------------------------------- 1 | ## 通过nfs进行下载烧写--配置NFS网络文件系统的挂载卸载--制作镜像文件--虚拟机和开发板的交叉编译操作(通过MFS共享目录) (2017.12.07) 2 | 1. `确保nfs服务已开启` 3 | 2. `进入到u-boot的菜单栏,按 q 进入到 openJTAG的模式下:` 4 | * nfs 30000000 192.168.99.140:/work/nfs_root/tmp/fs.yaffs2 5 | * 30000000 : 烧写地址 192.168.99.140 :文件所在的服务器IP /work/nfs_root/tmp/fs.yaffs2 : 文件地址位置 // nfs的操作和tftpboot的操作一样 6 | ``` 7 | OpenJTAG> nfs 30000000 192.168.99.140:/work/nfs_root/tmp/fs.yaffs2 8 | dm9000 i/o: 0x20000000, id: 0x90000a46 9 | DM9000: running in 16 bit mode 10 | MAC: 08:00:3e:26:0a:5b 11 | could not establish link 12 | File transfer via NFS from server 192.168.99.140; our IP address is 192.168.99.135 13 | Filename '/work/nfs_root/tmp/fs.yaffs2'. 14 | Load address: 0x30000000 15 | Loading: ################################################################# 16 | ########################################################### 17 | done 18 | Bytes transferred = 8952768 (889bc0 hex) 19 | ``` 20 | 3. `擦除` 21 | * nand erase root 22 | 4. `烧写` 23 | * OpenJTAG> nand write.yaffs 30000000 260000 $(filesize) 24 | 25 | ## 配置通过 nfs(网络文件系统)挂载 26 | 1. `仅用flash上的根文件系统启动后,手动MOUNT NFS` --- `挂载共享` 27 | * mount -t nfs -o nolock,vers=2 192.168.99.140:/work/nfs_root /mnt 28 | ``` 29 | result: 30 | # mount -t nfs -o nolock,vers=2 192.168.99.140:/work/nfs_root /mnt 31 | # ls -lt 32 | # cd /mnt/ 33 | # ls -lt 34 | drwxrwxr-x 3 1000 1000 4096 Dec 6 2017 tmp 35 | -rw-r--r-- 1 1000 1000 16446798 Dec 24 2010 fs_qtopia.tar.bz2 36 | -rw-r--r-- 1 1000 1000 27072948 Apr 15 2008 fs_xwindow.tar.bz2 37 | -rw-r--r-- 1 1000 1000 2748536 Apr 15 2008 fs_mini.tar.bz2 38 | -rw-r--r-- 1 1000 1000 2832504 Apr 15 2008 fs_mini_mdev.tar.bz2 39 | ``` 40 | //把服务器的文件挂载到本地的 /mnt 目录下 41 | * -t : 指定文件系统的类型 42 | * -o : .-o options 主要用来描述设备或档案的挂接方式。常用的参数有: 43 |   loop:用来把一个文件当成硬盘分区挂接上系统 44 |   ro:采用只读方式挂接设备 45 |   rw:采用读写方式挂接设备 46 |   iocharset:指定访问文件系统所用字符集 47 | 48 | ``` 49 | nfs mount 默认选项包括文件锁,依赖于portmap提供的动态端口分配功能。 50 | 解决方法:kill 文件锁(lockd)或者mount -o nolock 51 | ``` 52 | 2. `卸载` 53 | ``` 54 | # umount /mnt // /mnt 为挂载点 55 | # ls -lt /mnt 56 | # 57 | ``` 58 | 3. `nfs的挂载特征` 59 | ``` 60 | 在开发板命令行输入 mount -o nolock -t nfs 192.168.1.200:/home/kmart/test /mnt/nfs 61 | 这样就可以在开发板上访问宿主机192.168.1.200下的test目录啦! 62 | ``` 63 | 4. `相关内核文件路径` 64 | * // F:\嵌入式\u-boot_and_core\linux-2.6.22.6_jz2440\linux-2.6.22.6\Documentation\nfsroot 65 | * ip=:::::: 66 | * ip=192.168.99.135:192.168.99.140:192.168.99.4:255.255.255.0::eth0:off 67 | 5. `完整配置` --- `配置完后reset一下,会以NFS形式启动` 68 | * set bootargs noinitrd root=/dev/nfs nfsroot=192.168.99.140:/work/nfs_root/tmp/fs_mini_mdev ip=192.168.99.135:192.168.99.140:192.168.99.4:255.255.255.0::eth0:off 69 | init=/linuxrc console=ttySAC0 rootfstype=jffs2 70 | 71 | ## 制作镜像文件 72 | * mkyaffs2image /work/nfs_root/fs_qtopia /tmp/fs.yaffs2 73 | * /work/nfs_root/fs_qtopia : 目录名 /tmp/fs.yaffs2 : 生成的镜像文件名 74 | * mkyaffs2image 这个二进制可执行文件要放在 /usr/bin /bin等目录下,shell才能辨别出来 75 | 76 | ## 编译文件,通过nfs的挂载实现交叉编译处理 (/work/nfs_root为nfs实现的共享目录) 77 | 78 | ## 虚拟机环境下: 192.168.99.140 79 | 1. cd /work/nfs_root/drivers_and_test/first_drv 80 | 2. make 81 | 3. arm-linux-gcc -o firstdrvtest firstdrvtest.c 82 | 3. .ko是2.6内核使用的动态连接文件的后缀名,也就是模块文件 83 | 84 | ## 开发板环境下 (192.168.99.135) 85 | 1. `挂载` --- ` 86 | * mount -t nfs -o nolock,vers=2,rsize=1024,wsize=1024 192.168.99.140:/work/nfs_root /mnt 87 | 2. `若出现以下的问题,请添加参数` 88 | * nfs:server is not responding, still trying 89 | * 添加参数后命令为: mount -t nfs -o nolock,vers=2,rsize=1024,wsize=1024 192.168.99.140:/work/nfs_root /mnt 90 | * `rsize=1024,wsize=1024` : `具有较高的传送速率的NFS主机网卡和较低速率的目标机网卡之间不匹配,要解决此问题需要在挂载文件系统时添加额外的参数` 91 | 3. `insmod first_drv.ko` 92 | ``` 93 | 当前位置:首页 » 硬件·内核·Shell·监测 » insmod insmod命令内核与模块管理 insmod命令用于将给定的模块加载到内核中。 94 | Linux有许多功能是通过模块的方式,在需要时才载入kernel。如此可使kernel较为精简,进而提高效率,以及保有较大的弹性。 95 | 这类可载入的模块,通常是设备驱动程序 96 | ``` 97 | 4. `执行程序` 98 | * # ./firstdrvtest on //打开灯 99 | * # ./firstdrvtest off //关灯 -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之源码阶段.md: -------------------------------------------------------------------------------- 1 | ## u-boot分析之源码阶段 (2017.12.09) 2 | * bss : 没有初始化的静态变量或全局变量 + 初始值为0的静态变量或全局变量 3 | * svc : 管理模式 4 | * 移植 u-boot的主要工作在于对硬件的初始化、驱动 5 | ``` 6 | theKernel(0,bd->bi_arch_number,bd->bi_boot_params) : 用来调用内核 7 | theKernel : 指向内核存放的地址 ARM 通常为 0X30008000 8 | bd->bi_arch_number : board_init函数设置的机器类型ID 9 | bd->bi_boot_params : 标记列表的开始地址 10 | ``` 11 | ## u-boot内存使用情况 12 | ![u-boot内存使用情况](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%88%86%E6%9E%90%E4%B9%8B%E6%BA%90%E7%A0%81%E9%98%B6%E6%AE%B5%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/u-boot%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E6%83%85%E5%86%B5.JPG) 13 | ## u-boot分析 14 | ![u-boot分析](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%88%86%E6%9E%90%E4%B9%8B%E6%BA%90%E7%A0%81%E9%98%B6%E6%AE%B5%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/u-boot%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90--%E6%9D%A1%E4%BB%B6.JPG) 15 | ## u-boot启动的第一阶段 16 | ![u-boot启动的第一阶段](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%88%86%E6%9E%90%E4%B9%8B%E6%BA%90%E7%A0%81%E9%98%B6%E6%AE%B5%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/u-boot%E5%90%AF%E5%8A%A8%E7%9A%84%E7%AC%AC%E4%B8%80%E9%98%B6%E6%AE%B5.JPG) 17 | ## u-boot启动的第二阶段 18 | ![u-boot启动的第二阶段](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%88%86%E6%9E%90%E4%B9%8B%E6%BA%90%E7%A0%81%E9%98%B6%E6%AE%B5%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/u-boot%E5%90%AF%E5%8A%A8%E7%9A%84%E7%AC%AC%E4%BA%8C%E9%98%B6%E6%AE%B5.JPG) 19 | ## u-boot的核心 20 | ![u-boot的核心](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%88%86%E6%9E%90%E4%B9%8B%E6%BA%90%E7%A0%81%E9%98%B6%E6%AE%B5%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/u-boot%E7%9A%84%E6%A0%B8%E5%BF%83.JPG) 21 | 22 | 1. `cpu/arm920t/start.S` 23 | ``` 24 | ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot*/ // 设置地址 若为 0x33f80000 25 | sub r0, r0, #CFG_MALLOC_LEN /* malloc area*/ // 减地址 26 | ``` 27 | ![栈设置](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%88%86%E6%9E%90%E4%B9%8B%E6%BA%90%E7%A0%81%E9%98%B6%E6%AE%B5%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/sub%20%E4%B8%8E%20%E6%A0%88.JPG) 28 | * 栈设置好了才能调用C函数 29 | ``` 30 | /* configure UPLL */ 31 | clk_power->UPLLCON = S3C2440_UPLL_48MHZ; // USB的时钟 32 | 33 | /* configure MPLL */ 34 | clk_power->MPLLCON = S3C2440_MPLL_400MHZ; // 整个系统的时钟 35 | ``` 36 | ``` 37 | #ifndef CONFIG_SKIP_RELOCATE_UBOOT 38 | //作用:把代码从 flash 读到 SDRAM的链接地址里面 39 | relocate: /* relocate U-Boot to RAM */ 40 | adr r0, _start /* r0 <- current position of code */ 41 | ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ 42 | cmp r0, r1 /* don't reloc during debug */ 43 | beq clear_bss 44 | 45 | ldr r2, _armboot_start 46 | ldr r3, _bss_start 47 | sub r2, r3, r2 /* r2 <- size of armboot*/ 48 | #if 1 49 | bl CopyCode2Ram /* r0: source, r1: dest, r2: size*/ 50 | #else 51 | add r2, r0, r2 /* r2 <- source end address*/ 52 | 53 | copy_loop: 54 | ldmia r0!, {r3-r10} /* copy from source address [r0] */ 55 | stmia r1!, {r3-r10} /* copy to target address [r1] */ 56 | cmp r0, r2 /* until source end addreee [r2]*/ 57 | ble copy_loop 58 | #endif 59 | ``` 60 | ``` 61 | clear_bss: 62 | ldr r0, _bss_start /* find start of bss segment */ 63 | ldr r1, _bss_end /* stop here */ 64 | mov r2, #0x00000000 /* clear */ // r0 - r1 段 清零 65 | ``` 66 | ``` 67 | ldr pc, _start_armboot 68 | _start_armboot: .word start_armboot // 调用 C 函数 69 | ``` 70 | 71 | 2. `启动内核` 72 | * bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0 73 | // 在 nand flash 里面,把 kernel(分区) 读取到 0x30007FC0 这里 , 然后 boot 从 0x30007FC0 这里启动内核 74 | ## boot启动内核具体方式 75 | ![boot启动内核具体方式](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%88%86%E6%9E%90%E4%B9%8B%E6%BA%90%E7%A0%81%E9%98%B6%E6%AE%B5%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/boot%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E5%85%B7%E4%BD%93%E6%96%B9%E5%BC%8F.JPG) 76 | -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之u-boot命令.md: -------------------------------------------------------------------------------- 1 | ## u-boot分析之u-boot命令 (2017.12.10) 2 | ``` 3 | // Command.c (common) 4 | __u_boot_cmd_start //有时候定义不在.c,.h文件里面,有可能在链接文件里面(.dis) 5 | __u_boot_cmd_end 6 | ``` 7 | 1. `u-boot命令分析` 8 | ``` 9 | #define Struct_Section __attribute__ ((unused,section (".u_boot_cmd"))) 10 | 11 | bootcmd=nand read.jffs2 0x30007FC0 kernel; 12 | bootm 0x30007FC0 13 | 14 | U_BOOT_CMD( //宏 15 | bootm, CFG_MAXARGS, 1, do_bootm, 16 | "bootm - boot application image from memory\n", //usage 17 | //以下这段之间没有 , or ; 可作为一段字符串(help) 18 | "[addr [arg ...]]\n - boot application image stored in memory\n" 19 | "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" 20 | "\t'arg' can be the address of an initrd image\n" 21 | #ifdef CONFIG_OF_FLAT_TREE 22 | "\tWhen booting a Linux kernel which requires a flat device-tree\n" 23 | "\ta third argument is required which is the address of the of the\n" 24 | "\tdevice-tree blob. To boot that kernel without an initrd image,\n" 25 | "\tuse a '-' for the second argument. If you do not pass a third\n" 26 | "\ta bd_info struct will be passed instead\n" 27 | #endif 28 | ); 29 | 30 | #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \ 31 | cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help} 32 | 33 | cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd"))) = 34 | {"bootm", CFG_MAXARGS, 1, do_bootm, usage, help} 35 | /* 36 | __u_boot_cmd_bootm : 结构体 37 | __attribute__ : 结构体的属性,强制把section段属性设置为 .u_boot_cmd,跟 u-boot.dis的段属性对应起来 38 | # . = .; 39 | # __u_boot_cmd_start = .; 40 | # .u_boot_cmd : { *(.u_boot_cmd) } 41 | # __u_boot_cmd_end = .; 42 | */ 43 | ``` 44 | ## `创建一个hello的u-boot命令` 45 | 1. `新建cmd_hello.c 保存在 /common/下 ,内容如下:` 46 | ``` 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 57 | { 58 | int i; 59 | printf ("Hello world!, %d\n",argc); 60 | 61 | for (i =0 ; i < argc) 62 | { 63 | printf("argv[%d]: %s",i,argv[i]); 64 | } 65 | return 0; 66 | } 67 | U_BOOT_CMD( 68 | hello, CFG_MAXARGS, 1, do_hello, 69 | "hello - just for test\n", 70 | "hello,long help .............\n" 71 | ); 72 | ``` 73 | 2. `vim /work/system/u-boot-1.1.6/common/Makefile 添加 cmd_hello.o` 74 | * 注意这里的 cmd_hello 必须与添加到 /common/目录下的文件名相同(不包括后缀) 75 | * virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o cmd_hello.o 76 | 3. `cd /work/system/u-boot-1.1.6/` 77 | 4. `make distclean` 78 | ``` 79 | make clean与make distclean的区别 80 | make clean仅仅是清除之前编译的可执行文件及配置文件。 81 | 而make distclean要清除所有生成的文件。 82 | ``` 83 | 5. `make 100ask24x0_config ` 84 | 6. `make` 85 | 7. `选择 NAND flash 启动,进入到 u-boot的界面` 86 | ``` 87 | OpenJTAG> help 88 | hello - just for test 89 | 90 | OpenJTAG> hello 91 | Hello world!, 1 92 | argv[0]: helloOpenJTAG> hello 93 | Hello world!, 1 94 | argv[0]: helloOpenJTAG> help hello 95 | hello hello,long help ............. 96 | 97 | OpenJTAG> hello arg gag 98 | Hello world!, 3 99 | argv[0]: helloargv[1]: argargv[2]: gagOpenJTAG> 100 | ``` 101 | 8. `实现 hello 的 u-boot命令` 102 | ## u-boot命令图解 103 | ![u-boot命令图解](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%91%BD%E4%BB%A4%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/u-boot%E5%91%BD%E4%BB%A4%E5%9B%BE%E8%A7%A3.JPG) 104 | 9. `flinfo --- 查看 NOR flash 的信息` -- `flash information` 105 | * 可以查看 NOR flash 的型号、型号、各扇区的开始地址、是否只读等信息 106 | ``` 107 | OpenJTAG> flinfo 108 | 109 | Bank # 1: MXIC MX29LV160B FLASH (16 x 16) Size: 2 MB in 35 Sectors 110 | AMD Standard command set, Manufacturer ID: 0xC2, Device ID: 0x2249 111 | Erase timeout: 30000 ms, write timeout: 100 ms 112 | 113 | Sector Start Addresses: 114 | 00000000 RO 00004000 RO 00006000 RO 00008000 RO 00010000 RO 115 | 00020000 RO 00030000 RO 00040000 00050000 00060000 116 | 00070000 00080000 00090000 000A0000 000B0000 117 | 000C0000 000D0000 000E0000 000F0000 00100000 118 | 00110000 00120000 00130000 00140000 00150000 119 | 00160000 00170000 00180000 00190000 001A0000 120 | 001B0000 001C0000 001D0000 001E0000 001F0000 121 | OpenJTAG> 122 | ``` 123 | * MX29LV160B : NOR flash 的型号 124 | * Size: 2 MB : NOR flash 的 大小 125 | * RO : 只读 处于写保护状态 126 | * 对于只读的扇区,在擦除、烧写它之前,要先解除写保护, 127 | * 命令 : protect off all //解除所有的 NOR Flash 的写保护 128 | * erase : 擦除 129 | ``` 130 | erase start end : 擦除地址范围 start - end 131 | erase start + len : 擦除地址范围 start ~ start + tlen - 1 132 | erase all : 擦除所有 NOR Flash 133 | ``` 134 | * 这里若要擦除前五个分区,命令为: erase 0 0x2ffff ,而不是 erase 0 0x30000 135 | 10. `go 命令` 136 | ``` 137 | * tftp 0x30000000 test.bin or nfs 0x30000000 192.168.99.140:/work/nfs_root/test.bin // 下载可执行文件到内存中 138 | * go 0x30000000 // 直接执行程序 139 | ``` -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/init.c: -------------------------------------------------------------------------------- 1 | 2 | /* NAND FLASH控制器 */ 3 | #define NFCONF (*((volatile unsigned long *)0x4E000000)) 4 | #define NFCONT (*((volatile unsigned long *)0x4E000004)) 5 | #define NFCMMD (*((volatile unsigned char *)0x4E000008)) 6 | #define NFADDR (*((volatile unsigned char *)0x4E00000C)) 7 | #define NFDATA (*((volatile unsigned char *)0x4E000010)) 8 | #define NFSTAT (*((volatile unsigned char *)0x4E000020)) 9 | 10 | /* GPIO */ 11 | #define GPHCON (*(volatile unsigned long *)0x56000070) 12 | #define GPHUP (*(volatile unsigned long *)0x56000078) 13 | 14 | /* UART registers*/ 15 | #define ULCON0 (*(volatile unsigned long *)0x50000000) 16 | #define UCON0 (*(volatile unsigned long *)0x50000004) 17 | #define UFCON0 (*(volatile unsigned long *)0x50000008) 18 | #define UMCON0 (*(volatile unsigned long *)0x5000000c) 19 | #define UTRSTAT0 (*(volatile unsigned long *)0x50000010) 20 | #define UTXH0 (*(volatile unsigned char *)0x50000020) 21 | #define URXH0 (*(volatile unsigned char *)0x50000024) 22 | #define UBRDIV0 (*(volatile unsigned long *)0x50000028) 23 | 24 | #define TXD0READY (1<<2) 25 | 26 | 27 | void nand_read(unsigned int addr,unsigned char *buf, unsigned int len); 28 | 29 | int isBootFromNorFlash(void) 30 | { 31 | volatile int *p= (volatile int *)0; 32 | int val; 33 | val = *p; 34 | *p = 0x12345678; 35 | if (*p == 0x12345678) 36 | { 37 | /* 写成功,是nand flash启动 */ 38 | *p = val; // 恢复原来的值 39 | return 0; 40 | } 41 | else 42 | { 43 | /* nor flash不能像内存一样写 */ 44 | return 1; 45 | } 46 | } 47 | 48 | void copy_code_to_sdram(unsigned char *src,unsigned char *dest,unsigned int len) 49 | { 50 | int i=0; 51 | /* 如果是NOR FLASH启动 */ 52 | if(isBootFromNorFlash()) 53 | { 54 | while(i < len) 55 | { 56 | dest[i] = src[i]; 57 | i++; 58 | } 59 | } 60 | else 61 | { 62 | nand_read((unsigned int)src,dest,len); 63 | } 64 | } 65 | 66 | // 清理bss段 67 | void clear_bss(void) 68 | { 69 | extern int __bss_start ,__bss_end; 70 | int *p = &__bss_start; 71 | 72 | for(;p < &__bss_end;p++) //遍历 73 | { 74 | *p = 0; //清零 75 | } 76 | } 77 | 78 | void nand_init(void) 79 | { 80 | // 时序设置 根据数据手册 81 | #define TACLS 0 82 | #define TWRPH0 1 83 | #define TWRPH1 0 84 | NFCONF = ((TACLS << 12)|(TWRPH0 << 8)|(TWRPH1 << 4)); 85 | /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ 86 | NFCONT = ((1 << 4) | (1 << 1) | (1 << 0)); 87 | } 88 | 89 | /* Enable chip select */ 90 | void nand_select(void) 91 | { 92 | NFCONT &= ~(1 << 1); 93 | } 94 | 95 | /* Disable chip select */ 96 | void nand_deselect(void) 97 | { 98 | NFCONT |= (1 << 1); 99 | } 100 | 101 | // 发送命令 102 | void nand_cmd(unsigned char cmd) 103 | { 104 | volatile int i; 105 | NFCMMD = cmd; 106 | for(i=0;i<10;i++); 107 | } 108 | // 发送地址 109 | void nand_addr(unsigned int addr) 110 | { 111 | volatile int i; 112 | unsigned int col , row; // 列地址 行地址 113 | col = addr % 2048; 114 | row = addr / 2048; 115 | 116 | NFADDR = col & 0xff; 117 | for (i = 0; i < 10; i++); 118 | NFADDR = (col >> 8) & 0xff; 119 | for (i = 0; i < 10; i++); 120 | NFADDR = row & 0xff; 121 | for (i = 0; i < 10; i++); 122 | NFADDR = (row >> 8) & 0xff; 123 | for (i = 0; i < 10; i++); 124 | NFADDR = (row >> 16) & 0xff; 125 | for (i = 0; i < 10; i++); 126 | } 127 | 128 | // 状态检测 129 | void nand_read_ready(void) 130 | { 131 | while(!(NFSTAT & 0x01)); 132 | } 133 | 134 | // 这里定义返回值为unsigned char,是因为原理图中的传送数据只有8位I/O 135 | unsigned char nand_data(void) 136 | { 137 | return NFDATA; 138 | } 139 | 140 | // 读取 Nand FLASH的内容 141 | void nand_read(unsigned int addr,unsigned char *buf, unsigned int len) 142 | { 143 | int col = addr % 2048; 144 | int i = 0; 145 | /* 选中片选 */ 146 | nand_select(); 147 | while(i < len) 148 | { 149 | /* 2. 发出读命令 */ 150 | nand_cmd(0x00); 151 | /* 3. 发出地址(分5步发出) */ 152 | nand_addr(addr); 153 | /* 4. 发出读命令30h */ 154 | nand_cmd(0x30); 155 | /* 5. 判断状态 */ 156 | nand_read_ready(); 157 | /* 6. 读数据 */ 158 | for(;(col < 2048) && (i < len); col++) // 第一次处于寄存器的中间位置 159 | { 160 | buf[i] = nand_data(); 161 | i++; 162 | addr++; 163 | } 164 | col = 0; 165 | } 166 | /* 7. 取消选中 */ 167 | nand_deselect(); 168 | } 169 | 170 | #define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz 171 | #define UART_CLK PCLK // UART0的时钟源设为PCLK 172 | #define UART_BAUD_RATE 115200 // 波特率 173 | #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1) 174 | 175 | /* 1. 初始化UART0 */ 176 | /* 115200 8N1,无流控 */ 177 | void uart0_init() 178 | { 179 | GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0 180 | GPHUP = 0x0c; // GPH2,GPH3内部上拉 181 | 182 | ULCON0 = 0x03; // 8位,无校验,1个停止位 183 | UCON0 = 0x05; // 查询方式,uart的中断源为PCLK 184 | UFCON0 = 0x00; // 不使用FIFO 185 | UMCON0 = 0x00; // 不使用流控 186 | UBRDIV0 = UART_BRD; // 设置波特率为 115200 187 | } 188 | 189 | // 发送一个字节 190 | void putc(unsigned char c) 191 | { 192 | // UTRSTAT0 & TXD0READY = 1 表示发送缓冲区的数据已经全部发送出去 193 | while(!(UTRSTAT0 & TXD0READY)); 194 | /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */ 195 | UTXH0 = c; 196 | } 197 | 198 | void puts(char *str) 199 | { 200 | int i=0; 201 | while(str[i]) 202 | { 203 | putc(str[i]); 204 | i++; 205 | } 206 | } 207 | 208 | void puthex(unsigned int val) // 输出16进制的值 209 | { 210 | /* 0x1234abcd */ 211 | int i; 212 | int j; 213 | 214 | puts("0x"); 215 | 216 | for (i = 0; i < 8; i++) 217 | { 218 | j = (val >> ((7-i)*4)) & 0xf; 219 | if ((j >= 0) && (j <= 9)) 220 | putc('0' + j); 221 | else 222 | putc('A' + j - 0xa); 223 | 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/init.c: -------------------------------------------------------------------------------- 1 | 2 | /* NAND FLASH控制器 */ 3 | #define NFCONF (*((volatile unsigned long *)0x4E000000)) 4 | #define NFCONT (*((volatile unsigned long *)0x4E000004)) 5 | #define NFCMMD (*((volatile unsigned char *)0x4E000008)) 6 | #define NFADDR (*((volatile unsigned char *)0x4E00000C)) 7 | #define NFDATA (*((volatile unsigned char *)0x4E000010)) 8 | #define NFSTAT (*((volatile unsigned char *)0x4E000020)) 9 | 10 | /* GPIO */ 11 | #define GPHCON (*(volatile unsigned long *)0x56000070) 12 | #define GPHUP (*(volatile unsigned long *)0x56000078) 13 | 14 | /* UART registers*/ 15 | #define ULCON0 (*(volatile unsigned long *)0x50000000) 16 | #define UCON0 (*(volatile unsigned long *)0x50000004) 17 | #define UFCON0 (*(volatile unsigned long *)0x50000008) 18 | #define UMCON0 (*(volatile unsigned long *)0x5000000c) 19 | #define UTRSTAT0 (*(volatile unsigned long *)0x50000010) 20 | #define UTXH0 (*(volatile unsigned char *)0x50000020) 21 | #define URXH0 (*(volatile unsigned char *)0x50000024) 22 | #define UBRDIV0 (*(volatile unsigned long *)0x50000028) 23 | 24 | #define TXD0READY (1<<2) 25 | 26 | 27 | void nand_read(unsigned int addr,unsigned char *buf, unsigned int len); 28 | 29 | int isBootFromNorFlash(void) 30 | { 31 | volatile int *p= (volatile int *)0; 32 | int val; 33 | val = *p; 34 | *p = 0x12345678; 35 | if (*p == 0x12345678) 36 | { 37 | /* 写成功,是nand flash启动 */ 38 | *p = val; // 恢复原来的值 39 | return 0; 40 | } 41 | else 42 | { 43 | /* nor flash不能像内存一样写 */ 44 | return 1; 45 | } 46 | } 47 | 48 | void copy_code_to_sdram(unsigned char *src,unsigned char *dest,unsigned int len) 49 | { 50 | int i=0; 51 | /* 如果是NOR FLASH启动 */ 52 | if(isBootFromNorFlash()) 53 | { 54 | while(i < len) 55 | { 56 | dest[i] = src[i]; 57 | i++; 58 | } 59 | } 60 | else 61 | { 62 | nand_read((unsigned int)src,dest,len); 63 | } 64 | } 65 | 66 | // 清理bss段 67 | void clear_bss(void) 68 | { 69 | extern int __bss_start ,__bss_end; 70 | int *p = &__bss_start; 71 | 72 | for(;p < &__bss_end;p++) //遍历 73 | { 74 | *p = 0; //清零 75 | } 76 | } 77 | 78 | void nand_init(void) 79 | { 80 | // 时序设置 根据数据手册 81 | #define TACLS 0 82 | #define TWRPH0 1 83 | #define TWRPH1 0 84 | NFCONF = ((TACLS << 12)|(TWRPH0 << 8)|(TWRPH1 << 4)); 85 | /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ 86 | NFCONT = ((1 << 4) | (1 << 1) | (1 << 0)); 87 | } 88 | 89 | /* Enable chip select */ 90 | void nand_select(void) 91 | { 92 | NFCONT &= ~(1 << 1); 93 | } 94 | 95 | /* Disable chip select */ 96 | void nand_deselect(void) 97 | { 98 | NFCONT |= (1 << 1); 99 | } 100 | 101 | // 发送命令 102 | void nand_cmd(unsigned char cmd) 103 | { 104 | volatile int i; 105 | NFCMMD = cmd; 106 | for(i=0;i<10;i++); 107 | } 108 | // 发送地址 109 | void nand_addr(unsigned int addr) 110 | { 111 | volatile int i; 112 | unsigned int col , row; // 列地址 行地址 113 | col = addr % 2048; 114 | row = addr / 2048; 115 | 116 | NFADDR = col & 0xff; 117 | for (i = 0; i < 10; i++); 118 | NFADDR = (col >> 8) & 0xff; 119 | for (i = 0; i < 10; i++); 120 | NFADDR = row & 0xff; 121 | for (i = 0; i < 10; i++); 122 | NFADDR = (row >> 8) & 0xff; 123 | for (i = 0; i < 10; i++); 124 | NFADDR = (row >> 16) & 0xff; 125 | for (i = 0; i < 10; i++); 126 | } 127 | 128 | // 状态检测 129 | void nand_read_ready(void) 130 | { 131 | while(!(NFSTAT & 0x01)); 132 | } 133 | 134 | // 这里定义返回值为unsigned char,是因为原理图中的传送数据只有8位I/O 135 | unsigned char nand_data(void) 136 | { 137 | return NFDATA; 138 | } 139 | 140 | // 读取 Nand FLASH的内容 141 | void nand_read(unsigned int addr,unsigned char *buf, unsigned int len) 142 | { 143 | int col = addr % 2048; 144 | int i = 0; 145 | /* 选中片选 */ 146 | nand_select(); 147 | while(i < len) 148 | { 149 | /* 2. 发出读命令 */ 150 | nand_cmd(0x00); 151 | /* 3. 发出地址(分5步发出) */ 152 | nand_addr(addr); 153 | /* 4. 发出读命令30h */ 154 | nand_cmd(0x30); 155 | /* 5. 判断状态 */ 156 | nand_read_ready(); 157 | /* 6. 读数据 */ 158 | for(;(col < 2048) && (i < len); col++) // 第一次处于寄存器的中间位置 159 | { 160 | buf[i] = nand_data(); 161 | i++; 162 | addr++; 163 | } 164 | col = 0; 165 | } 166 | /* 7. 取消选中 */ 167 | nand_deselect(); 168 | } 169 | 170 | #define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz 171 | #define UART_CLK PCLK // UART0的时钟源设为PCLK 172 | #define UART_BAUD_RATE 115200 // 波特率 173 | #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1) 174 | 175 | /* 1. 初始化UART0 */ 176 | /* 115200 8N1,无流控 */ 177 | void uart0_init() 178 | { 179 | GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0 180 | GPHUP = 0x0c; // GPH2,GPH3内部上拉 181 | 182 | ULCON0 = 0x03; // 8位,无校验,1个停止位 183 | UCON0 = 0x05; // 查询方式,uart的中断源为PCLK 184 | UFCON0 = 0x00; // 不使用FIFO 185 | UMCON0 = 0x00; // 不使用流控 186 | UBRDIV0 = UART_BRD; // 设置波特率为 115200 187 | } 188 | 189 | // 发送一个字节 190 | void putc(unsigned char c) 191 | { 192 | // UTRSTAT0 & TXD0READY = 1 表示发送缓冲区的数据已经全部发送出去 193 | while(!(UTRSTAT0 & TXD0READY)); 194 | /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */ 195 | UTXH0 = c; 196 | } 197 | 198 | void puts(char *str) 199 | { 200 | int i=0; 201 | while(str[i]) 202 | { 203 | putc(str[i]); 204 | i++; 205 | } 206 | } 207 | 208 | void puthex(unsigned int val) // 输出16进制的值 209 | { 210 | /* 0x1234abcd */ 211 | int i; 212 | int j; 213 | 214 | puts("0x"); 215 | 216 | for (i = 0; i < 8; i++) 217 | { 218 | j = (val >> ((7-i)*4)) & 0xf; 219 | if ((j >= 0) && (j <= 9)) 220 | putc('0' + j); 221 | else 222 | putc('A' + j - 0xa); 223 | 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之u-boot启动内核.md: -------------------------------------------------------------------------------- 1 | ## u-boot分析之u-boot启动内核 (2017.12.10) 2 | ## 分区 3 | ![分区](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%88%86%E5%8C%BA.JPG) 4 | 1. `分区配置 -- 100ask24x0.h(include/configs)` 5 | ``` 6 | * 写死分区表 7 | #define MTDIDS_DEFAULT "nand0=nandflash0" 8 | #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \ //bootloader 9 | "128k(params)," \ // env 环境参数 10 | "2m(kernel)," \ // kernel -- 内核 11 | "-(root)" // 根文件系统 12 | ``` 13 | * openJTAG > mtd // 查看分区 14 | 15 | * nand read.jffs2 0x30007FC0 kernel 等价于 16 | nand read.jffs2 0x30007FC0 0x00200000 0x00060000 17 | * 因为 : 18 | ``` 19 | OpenJTAG> mtd 20 | device nand0 , # parts = 4 21 | #: name size offset mask_flags 22 | 0: bootloader 0x00040000 0x00000000 0 23 | 1: params 0x00020000 0x00040000 0 24 | 2: kernel 0x00200000 0x00060000 0 25 | 3: root 0x0fda0000 0x00260000 0 26 | 27 | active partition: nand0,0 - (bootloader) 0x00040000 @ 0x00000000 28 | 29 | defaults: 30 | mtdids : nand0=nandflash0 31 | mtdparts: mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root) 32 | ``` 33 | * `所以说分区的名字(kernel)不重要,重要的是它代表的起始地址和结束地址` 34 | ## u-boot启动内核原理分析 35 | ![u-boot启动内核原理分析](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/u-boot%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90.JPG) 36 | 37 | ## 内核加载 : uImage = header + 真正的内核(0x30008000) 38 | * header : hex : 40 ; DEC : 64 39 | * 我们设置的 bootm 0x30007FC0 40 | * 0x30007FC0 + header的size = 真正内核的地址 , 这样就能加快启动速率,免得重新设置 41 | ``` 42 | typedef struct image_header { 43 | uint32_t ih_magic; /* Image Header Magic Number */ 44 | uint32_t ih_hcrc; /* Image Header CRC Checksum */ 45 | uint32_t ih_time; /* Image Creation Timestamp */ 46 | uint32_t ih_size; /* Image Data Size */ 47 | uint32_t ih_load; /* Data Load Address */ // 内核加载的真正地址 48 | uint32_t ih_ep; /* Entry Point Address */ //程序入口地址 49 | uint32_t ih_dcrc; /* Image Data CRC Checksum */ 50 | uint8_t ih_os; /* Operating System */ 51 | uint8_t ih_arch; /* CPU architecture */ 52 | uint8_t ih_type; /* Image Type */ 53 | uint8_t ih_comp; /* Compression Type */ 54 | uint8_t ih_name[IH_NMLEN]; /* Image Name */ 55 | } image_header_t; 56 | ``` 57 | ``` 58 | switch (hdr->ih_comp) { 59 | case IH_COMP_NONE: 60 | if(ntohl(hdr->ih_load) == data) { 61 | printf (" XIP %s ... ", name); 62 | } else { 63 | #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) 64 | size_t l = len; 65 | void *to = (void *)ntohl(hdr->ih_load); 66 | void *from = (void *)data; 67 | 68 | printf (" Loading %s ... ", name); 69 | 70 | while (l > 0) { 71 | size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; 72 | WATCHDOG_RESET(); 73 | memmove (to, from, tail); 74 | to += tail; 75 | from += tail; 76 | l -= tail; 77 | } 78 | ``` 79 | ## do_bootm_linux的作用 80 | ![do_bootm_linux的作用](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/do_bootm_linux%E7%9A%84%E4%BD%9C%E7%94%A8.JPG) 81 | * `启动内核 : do_bootm_linux` 82 | ``` 83 | * theKernel (0, bd->bi_arch_number, bd->bi_boot_params); // Armlinux.c(lib_arm) 84 | * theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep); // hdr->ih_ep 头部->入口地址 85 | * bd->bi_arch_number 86 | // 机器ID 100ask24x0.c (board\100ask24x0): gd->bd->bi_arch_number = MACH_TYPE_S3C2440; 87 | ``` 88 | ## 启动内核分析各个TAG的作用 89 | ![启动内核分析各个TAG的作用](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E5%88%86%E6%9E%90%E5%90%84%E4%B8%AATAG%E7%9A%84%E4%BD%9C%E7%94%A8.JPG) 90 | * `TAG` 91 | ``` 92 | setup_start_tag (bd); 93 | setup_memory_tags (bd); 94 | setup_commandline_tag (bd, commandline); 95 | setup_end_tag (bd); 96 | ``` 97 | ``` 98 | static void setup_start_tag (bd_t *bd) 99 | { 100 | params = (struct tag *) bd->bi_boot_params; 101 | 102 | params->hdr.tag = ATAG_CORE; 103 | params->hdr.size = tag_size (tag_core); 104 | 105 | params->u.core.flags = 0; 106 | params->u.core.pagesize = 0; 107 | params->u.core.rootdev = 0; 108 | 109 | params = tag_next (params); 110 | } 111 | 112 | 100ask24x0.c (board\100ask24x0): gd->bd->bi_boot_params = 0x30000100; 113 | ``` 114 | ``` 115 | int dram_init (void) 116 | { 117 | gd->bd->bi_dram[0].start = PHYS_SDRAM_1; 118 | gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; 119 | 120 | return 0; 121 | } 122 | // 和视频有区别 123 | * Physical Memory Map 124 | */ 125 | #define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ 126 | #define PHYS_SDRAM_1 0xc0000000 /* SDRAM Bank #1 */ 127 | #define PHYS_SDRAM_1_SIZE 0x02000000 /* 32 MB */ 128 | 129 | #define CFG_FLASH_BASE 0x00000000 /* Flash Bank #1 */ 130 | ``` 131 | * `commandline` 132 | ``` 133 | #ifdef CONFIG_CMDLINE_TAG 134 | setup_commandline_tag (bd, commandline); 135 | #endif 136 | 137 | #ifdef CONFIG_CMDLINE_TAG // 在 Armlinux(lib_arm) 138 | char *commandline = getenv ("bootargs"); 139 | #endif 140 | 141 | * bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0 rootfstype=jffs2 142 | root=/dev/mtdblock3 // 根文件系统 相当于 windows的 C 盘 这里位于第四个分区 143 | init=/linuxrc // 第一个应用程序 144 | console=ttySAC0 // console : 内核的打印信息从哪里打出来 ttySAC0 : 串口0 145 | ``` -------------------------------------------------------------------------------- /bootloader编写步骤/code/1th/setup.h: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/include/asm/setup.h 3 | * 4 | * Copyright (C) 1997-1999 Russell King 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. 9 | * 10 | * Structure passed to kernel to tell it about the 11 | * hardware it's running on. See linux/Documentation/arm/Setup 12 | * for more info. 13 | * 14 | * NOTE: 15 | * This file contains two ways to pass information from the boot 16 | * loader to the kernel. The old struct param_struct is deprecated, 17 | * but it will be kept in the kernel for 5 years from now 18 | * (2001). This will allow boot loaders to convert to the new struct 19 | * tag way. 20 | */ 21 | #ifndef __ASMARM_SETUP_H 22 | #define __ASMARM_SETUP_H 23 | 24 | #define u8 unsigned char 25 | #define u16 unsigned short 26 | #define u32 unsigned long 27 | /* 28 | * Usage: 29 | * - do not go blindly adding fields, add them at the end 30 | * - when adding fields, don't rely on the address until 31 | * a patch from me has been released 32 | * - unused fields should be zero (for future expansion) 33 | * - this structure is relatively short-lived - only 34 | * guaranteed to contain useful data in setup_arch() 35 | */ 36 | #define COMMAND_LINE_SIZE 1024 37 | 38 | /* This is the old deprecated way to pass parameters to the kernel */ 39 | struct param_struct { 40 | union { 41 | struct { 42 | unsigned long page_size; /* 0 */ 43 | unsigned long nr_pages; /* 4 */ 44 | unsigned long ramdisk_size; /* 8 */ 45 | unsigned long flags; /* 12 */ 46 | #define FLAG_READONLY 1 47 | #define FLAG_RDLOAD 4 48 | #define FLAG_RDPROMPT 8 49 | unsigned long rootdev; /* 16 */ 50 | unsigned long video_num_cols; /* 20 */ 51 | unsigned long video_num_rows; /* 24 */ 52 | unsigned long video_x; /* 28 */ 53 | unsigned long video_y; /* 32 */ 54 | unsigned long memc_control_reg; /* 36 */ 55 | unsigned char sounddefault; /* 40 */ 56 | unsigned char adfsdrives; /* 41 */ 57 | unsigned char bytes_per_char_h; /* 42 */ 58 | unsigned char bytes_per_char_v; /* 43 */ 59 | unsigned long pages_in_bank[4]; /* 44 */ 60 | unsigned long pages_in_vram; /* 60 */ 61 | unsigned long initrd_start; /* 64 */ 62 | unsigned long initrd_size; /* 68 */ 63 | unsigned long rd_start; /* 72 */ 64 | unsigned long system_rev; /* 76 */ 65 | unsigned long system_serial_low; /* 80 */ 66 | unsigned long system_serial_high; /* 84 */ 67 | unsigned long mem_fclk_21285; /* 88 */ 68 | } s; 69 | char unused[256]; 70 | } u1; 71 | union { 72 | char paths[8][128]; 73 | struct { 74 | unsigned long magic; 75 | char n[1024 - sizeof(unsigned long)]; 76 | } s; 77 | } u2; 78 | char commandline[COMMAND_LINE_SIZE]; 79 | }; 80 | 81 | 82 | /* 83 | * The new way of passing information: a list of tagged entries 84 | */ 85 | 86 | /* The list ends with an ATAG_NONE node. */ 87 | #define ATAG_NONE 0x00000000 88 | 89 | struct tag_header { 90 | u32 size; 91 | u32 tag; 92 | }; 93 | 94 | /* The list must start with an ATAG_CORE node */ 95 | #define ATAG_CORE 0x54410001 96 | 97 | struct tag_core { 98 | u32 flags; /* bit 0 = read-only */ 99 | u32 pagesize; 100 | u32 rootdev; 101 | }; 102 | 103 | /* it is allowed to have multiple ATAG_MEM nodes */ 104 | #define ATAG_MEM 0x54410002 105 | 106 | struct tag_mem32 { 107 | u32 size; 108 | u32 start; /* physical start address */ 109 | }; 110 | 111 | /* VGA text type displays */ 112 | #define ATAG_VIDEOTEXT 0x54410003 113 | 114 | struct tag_videotext { 115 | u8 x; 116 | u8 y; 117 | u16 video_page; 118 | u8 video_mode; 119 | u8 video_cols; 120 | u16 video_ega_bx; 121 | u8 video_lines; 122 | u8 video_isvga; 123 | u16 video_points; 124 | }; 125 | 126 | /* describes how the ramdisk will be used in kernel */ 127 | #define ATAG_RAMDISK 0x54410004 128 | 129 | struct tag_ramdisk { 130 | u32 flags; /* bit 0 = load, bit 1 = prompt */ 131 | u32 size; /* decompressed ramdisk size in _kilo_ bytes */ 132 | u32 start; /* starting block of floppy-based RAM disk image */ 133 | }; 134 | 135 | /* describes where the compressed ramdisk image lives (virtual address) */ 136 | /* 137 | * this one accidentally used virtual addresses - as such, 138 | * its depreciated. 139 | */ 140 | #define ATAG_INITRD 0x54410005 141 | 142 | /* describes where the compressed ramdisk image lives (physical address) */ 143 | #define ATAG_INITRD2 0x54420005 144 | 145 | struct tag_initrd { 146 | u32 start; /* physical start address */ 147 | u32 size; /* size of compressed ramdisk image in bytes */ 148 | }; 149 | 150 | /* board serial number. "64 bits should be enough for everybody" */ 151 | #define ATAG_SERIAL 0x54410006 152 | 153 | struct tag_serialnr { 154 | u32 low; 155 | u32 high; 156 | }; 157 | 158 | /* board revision */ 159 | #define ATAG_REVISION 0x54410007 160 | 161 | struct tag_revision { 162 | u32 rev; 163 | }; 164 | 165 | /* initial values for vesafb-type framebuffers. see struct screen_info 166 | * in include/linux/tty.h 167 | */ 168 | #define ATAG_VIDEOLFB 0x54410008 169 | 170 | struct tag_videolfb { 171 | u16 lfb_width; 172 | u16 lfb_height; 173 | u16 lfb_depth; 174 | u16 lfb_linelength; 175 | u32 lfb_base; 176 | u32 lfb_size; 177 | u8 red_size; 178 | u8 red_pos; 179 | u8 green_size; 180 | u8 green_pos; 181 | u8 blue_size; 182 | u8 blue_pos; 183 | u8 rsvd_size; 184 | u8 rsvd_pos; 185 | }; 186 | 187 | /* command line: \0 terminated string */ 188 | #define ATAG_CMDLINE 0x54410009 189 | 190 | struct tag_cmdline { 191 | char cmdline[1]; /* this is the minimum size */ 192 | }; 193 | 194 | /* acorn RiscPC specific information */ 195 | #define ATAG_ACORN 0x41000101 196 | 197 | struct tag_acorn { 198 | u32 memc_control_reg; 199 | u32 vram_pages; 200 | u8 sounddefault; 201 | u8 adfsdrives; 202 | }; 203 | 204 | /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */ 205 | #define ATAG_MEMCLK 0x41000402 206 | 207 | struct tag_memclk { 208 | u32 fmemclk; 209 | }; 210 | 211 | struct tag { 212 | struct tag_header hdr; 213 | union { 214 | struct tag_core core; 215 | struct tag_mem32 mem; 216 | struct tag_videotext videotext; 217 | struct tag_ramdisk ramdisk; 218 | struct tag_initrd initrd; 219 | struct tag_serialnr serialnr; 220 | struct tag_revision revision; 221 | struct tag_videolfb videolfb; 222 | struct tag_cmdline cmdline; 223 | 224 | /* 225 | * Acorn specific 226 | */ 227 | struct tag_acorn acorn; 228 | 229 | /* 230 | * DC21285 specific 231 | */ 232 | struct tag_memclk memclk; 233 | } u; 234 | }; 235 | 236 | struct tagtable { 237 | u32 tag; 238 | int (*parse)(const struct tag *); 239 | }; 240 | 241 | 242 | #define tag_member_present(tag,member) \ 243 | ((unsigned long)(&((struct tag *)0L)->member + 1) \ 244 | <= (tag)->hdr.size * 4) 245 | 246 | #define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) 247 | #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) 248 | 249 | #define for_each_tag(t,base) \ 250 | for (t = base; t->hdr.size; t = tag_next(t)) 251 | 252 | /* 253 | * Memory map description 254 | */ 255 | #define NR_BANKS 8 256 | 257 | struct meminfo { 258 | int nr_banks; 259 | unsigned long end; 260 | struct { 261 | unsigned long start; 262 | unsigned long size; 263 | int node; 264 | } bank[NR_BANKS]; 265 | }; 266 | 267 | extern struct meminfo meminfo; 268 | 269 | #endif 270 | -------------------------------------------------------------------------------- /bootloader编写步骤/code/2th-改进版/setup.h: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/include/asm/setup.h 3 | * 4 | * Copyright (C) 1997-1999 Russell King 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. 9 | * 10 | * Structure passed to kernel to tell it about the 11 | * hardware it's running on. See linux/Documentation/arm/Setup 12 | * for more info. 13 | * 14 | * NOTE: 15 | * This file contains two ways to pass information from the boot 16 | * loader to the kernel. The old struct param_struct is deprecated, 17 | * but it will be kept in the kernel for 5 years from now 18 | * (2001). This will allow boot loaders to convert to the new struct 19 | * tag way. 20 | */ 21 | #ifndef __ASMARM_SETUP_H 22 | #define __ASMARM_SETUP_H 23 | 24 | #define u8 unsigned char 25 | #define u16 unsigned short 26 | #define u32 unsigned long 27 | /* 28 | * Usage: 29 | * - do not go blindly adding fields, add them at the end 30 | * - when adding fields, don't rely on the address until 31 | * a patch from me has been released 32 | * - unused fields should be zero (for future expansion) 33 | * - this structure is relatively short-lived - only 34 | * guaranteed to contain useful data in setup_arch() 35 | */ 36 | #define COMMAND_LINE_SIZE 1024 37 | 38 | /* This is the old deprecated way to pass parameters to the kernel */ 39 | struct param_struct { 40 | union { 41 | struct { 42 | unsigned long page_size; /* 0 */ 43 | unsigned long nr_pages; /* 4 */ 44 | unsigned long ramdisk_size; /* 8 */ 45 | unsigned long flags; /* 12 */ 46 | #define FLAG_READONLY 1 47 | #define FLAG_RDLOAD 4 48 | #define FLAG_RDPROMPT 8 49 | unsigned long rootdev; /* 16 */ 50 | unsigned long video_num_cols; /* 20 */ 51 | unsigned long video_num_rows; /* 24 */ 52 | unsigned long video_x; /* 28 */ 53 | unsigned long video_y; /* 32 */ 54 | unsigned long memc_control_reg; /* 36 */ 55 | unsigned char sounddefault; /* 40 */ 56 | unsigned char adfsdrives; /* 41 */ 57 | unsigned char bytes_per_char_h; /* 42 */ 58 | unsigned char bytes_per_char_v; /* 43 */ 59 | unsigned long pages_in_bank[4]; /* 44 */ 60 | unsigned long pages_in_vram; /* 60 */ 61 | unsigned long initrd_start; /* 64 */ 62 | unsigned long initrd_size; /* 68 */ 63 | unsigned long rd_start; /* 72 */ 64 | unsigned long system_rev; /* 76 */ 65 | unsigned long system_serial_low; /* 80 */ 66 | unsigned long system_serial_high; /* 84 */ 67 | unsigned long mem_fclk_21285; /* 88 */ 68 | } s; 69 | char unused[256]; 70 | } u1; 71 | union { 72 | char paths[8][128]; 73 | struct { 74 | unsigned long magic; 75 | char n[1024 - sizeof(unsigned long)]; 76 | } s; 77 | } u2; 78 | char commandline[COMMAND_LINE_SIZE]; 79 | }; 80 | 81 | 82 | /* 83 | * The new way of passing information: a list of tagged entries 84 | */ 85 | 86 | /* The list ends with an ATAG_NONE node. */ 87 | #define ATAG_NONE 0x00000000 88 | 89 | struct tag_header { 90 | u32 size; 91 | u32 tag; 92 | }; 93 | 94 | /* The list must start with an ATAG_CORE node */ 95 | #define ATAG_CORE 0x54410001 96 | 97 | struct tag_core { 98 | u32 flags; /* bit 0 = read-only */ 99 | u32 pagesize; 100 | u32 rootdev; 101 | }; 102 | 103 | /* it is allowed to have multiple ATAG_MEM nodes */ 104 | #define ATAG_MEM 0x54410002 105 | 106 | struct tag_mem32 { 107 | u32 size; 108 | u32 start; /* physical start address */ 109 | }; 110 | 111 | /* VGA text type displays */ 112 | #define ATAG_VIDEOTEXT 0x54410003 113 | 114 | struct tag_videotext { 115 | u8 x; 116 | u8 y; 117 | u16 video_page; 118 | u8 video_mode; 119 | u8 video_cols; 120 | u16 video_ega_bx; 121 | u8 video_lines; 122 | u8 video_isvga; 123 | u16 video_points; 124 | }; 125 | 126 | /* describes how the ramdisk will be used in kernel */ 127 | #define ATAG_RAMDISK 0x54410004 128 | 129 | struct tag_ramdisk { 130 | u32 flags; /* bit 0 = load, bit 1 = prompt */ 131 | u32 size; /* decompressed ramdisk size in _kilo_ bytes */ 132 | u32 start; /* starting block of floppy-based RAM disk image */ 133 | }; 134 | 135 | /* describes where the compressed ramdisk image lives (virtual address) */ 136 | /* 137 | * this one accidentally used virtual addresses - as such, 138 | * its depreciated. 139 | */ 140 | #define ATAG_INITRD 0x54410005 141 | 142 | /* describes where the compressed ramdisk image lives (physical address) */ 143 | #define ATAG_INITRD2 0x54420005 144 | 145 | struct tag_initrd { 146 | u32 start; /* physical start address */ 147 | u32 size; /* size of compressed ramdisk image in bytes */ 148 | }; 149 | 150 | /* board serial number. "64 bits should be enough for everybody" */ 151 | #define ATAG_SERIAL 0x54410006 152 | 153 | struct tag_serialnr { 154 | u32 low; 155 | u32 high; 156 | }; 157 | 158 | /* board revision */ 159 | #define ATAG_REVISION 0x54410007 160 | 161 | struct tag_revision { 162 | u32 rev; 163 | }; 164 | 165 | /* initial values for vesafb-type framebuffers. see struct screen_info 166 | * in include/linux/tty.h 167 | */ 168 | #define ATAG_VIDEOLFB 0x54410008 169 | 170 | struct tag_videolfb { 171 | u16 lfb_width; 172 | u16 lfb_height; 173 | u16 lfb_depth; 174 | u16 lfb_linelength; 175 | u32 lfb_base; 176 | u32 lfb_size; 177 | u8 red_size; 178 | u8 red_pos; 179 | u8 green_size; 180 | u8 green_pos; 181 | u8 blue_size; 182 | u8 blue_pos; 183 | u8 rsvd_size; 184 | u8 rsvd_pos; 185 | }; 186 | 187 | /* command line: \0 terminated string */ 188 | #define ATAG_CMDLINE 0x54410009 189 | 190 | struct tag_cmdline { 191 | char cmdline[1]; /* this is the minimum size */ 192 | }; 193 | 194 | /* acorn RiscPC specific information */ 195 | #define ATAG_ACORN 0x41000101 196 | 197 | struct tag_acorn { 198 | u32 memc_control_reg; 199 | u32 vram_pages; 200 | u8 sounddefault; 201 | u8 adfsdrives; 202 | }; 203 | 204 | /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */ 205 | #define ATAG_MEMCLK 0x41000402 206 | 207 | struct tag_memclk { 208 | u32 fmemclk; 209 | }; 210 | 211 | struct tag { 212 | struct tag_header hdr; 213 | union { 214 | struct tag_core core; 215 | struct tag_mem32 mem; 216 | struct tag_videotext videotext; 217 | struct tag_ramdisk ramdisk; 218 | struct tag_initrd initrd; 219 | struct tag_serialnr serialnr; 220 | struct tag_revision revision; 221 | struct tag_videolfb videolfb; 222 | struct tag_cmdline cmdline; 223 | 224 | /* 225 | * Acorn specific 226 | */ 227 | struct tag_acorn acorn; 228 | 229 | /* 230 | * DC21285 specific 231 | */ 232 | struct tag_memclk memclk; 233 | } u; 234 | }; 235 | 236 | struct tagtable { 237 | u32 tag; 238 | int (*parse)(const struct tag *); 239 | }; 240 | 241 | 242 | #define tag_member_present(tag,member) \ 243 | ((unsigned long)(&((struct tag *)0L)->member + 1) \ 244 | <= (tag)->hdr.size * 4) 245 | 246 | #define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) 247 | #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) 248 | 249 | #define for_each_tag(t,base) \ 250 | for (t = base; t->hdr.size; t = tag_next(t)) 251 | 252 | /* 253 | * Memory map description 254 | */ 255 | #define NR_BANKS 8 256 | 257 | struct meminfo { 258 | int nr_banks; 259 | unsigned long end; 260 | struct { 261 | unsigned long start; 262 | unsigned long size; 263 | int node; 264 | } bank[NR_BANKS]; 265 | }; 266 | 267 | extern struct meminfo meminfo; 268 | 269 | #endif 270 | -------------------------------------------------------------------------------- /9. 存储控制器/存储控制器.md: -------------------------------------------------------------------------------- 1 | ## 存储控制器 (2017.12.08) 2 | ## 存储控制器作用 3 | ![存储控制器作用](https://github.com/GalenDeng/Embedded-Linux/blob/master/9.%20%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8/%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8%E4%BD%9C%E7%94%A8.JPG) 4 | * cpu不管外设是啥东西,它是通过存储管理器和外设(如:SDRAM,网卡DM9000)进行沟通的,存储管理 5 | * 器根据配置文件知道外设的各个地址,进而分辨他们,这时外设应该:发送片选信号 => 发送bank选择信号 => 发送列地址 => 发送行地址 => ... 6 | ## SDRAM的结构图 7 | * bank0,bank1这些我们可以理解为不同的块 8 | * bank => 行地址(row) => 列地址(column) 9 | ![SDRAM的结构图](https://github.com/GalenDeng/Embedded-Linux/blob/master/9.%20%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8/SDRAM%E7%9A%84%E7%BB%93%E6%9E%84%E5%9B%BE.JPG) 10 | ## 访问一个芯片需要的条件 11 | ![访问一个芯片需要的条件](https://github.com/GalenDeng/Embedded-Linux/blob/master/9.%20%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8/%E8%AE%BF%E9%97%AE%E4%B8%80%E4%B8%AA%E8%8A%AF%E7%89%87%E9%9C%80%E8%A6%81%E7%9A%84%E6%9D%A1%E4%BB%B6.JPG) 12 | * 地址线、数据线、时钟/频率、相关芯片信息、刷新周期、数据位宽 13 | * 位宽 : 看原理图 14 | * 刷新周期、行地址、列地址、bank : 看内存芯片手册 15 | * 从 S3C2440的芯片手册查看,确定使用哪个port来和内存芯片(K4S561632N)的bank连接 16 | ## s3c2440的cpu和内存芯片K4S561632N的连接方式 17 | ![s3c2440和内存芯片的连接方式](https://github.com/GalenDeng/Embedded-Linux/blob/master/9.%20%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8/s3c2440%E5%92%8C%E5%86%85%E5%AD%98%E8%8A%AF%E7%89%87%E7%9A%84%E8%BF%9E%E6%8E%A5%E6%96%B9%E5%BC%8F.JPG) 18 | * 相对应的s3c2440芯片手册介绍 19 | * ![s3c2440的内存地址总线连接方式](https://github.com/GalenDeng/Embedded-Linux/blob/master/9.%20%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8/s3c2440%E7%9A%84%E5%86%85%E5%AD%98%E5%9C%B0%E5%9D%80%E6%80%BB%E7%BA%BF%E8%BF%9E%E6%8E%A5%E6%96%B9%E5%BC%8F.JPG) 20 | * 网卡和nor flash 术语上叫做 RAM like 21 | * SRAM : 贵,操作简单,直接读写 ; SDRAM : 需要 bank地址、行地址、列地址、刷新频率 22 | * 网卡,nor flash 可以用bank0-bank5 ; SDRAM bank6-bank7 23 | 24 | ## head.S (SDRAM实验) 25 | ``` 26 | @************************************************************************* 27 | @ File:head.S 28 | @ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行 29 | @************************************************************************* 30 | 31 | .equ MEM_CTL_BASE, 0x48000000 32 | .equ SDRAM_BASE, 0x30000000 33 | 34 | .text 35 | .global _start 36 | _start: 37 | bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 38 | bl memsetup @ 设置存储控制器 // bl 指令会把返回值放在lr寄存器中 39 | bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中 // steppingstone 为片内RAM,它的资源 40 | // 完全来自于一上电,nand flash把前// 4k的代码复制到片内RAM里面 41 | ldr pc, =on_sdram @ 跳到SDRAM中继续执行 42 | on_sdram: 43 | ldr sp, =0x34000000 @ 设置堆栈 我们这里我把堆栈设置成 SDRAM的顶端 44 | bl main // 调用C函数的之前,必须要设置好堆栈 45 | halt_loop: 46 | b halt_loop 47 | 48 | disable_watch_dog: 49 | @ 往WATCHDOG寄存器写0即可 50 | mov r1, #0x53000000 51 | mov r2, #0x0 52 | str r2, [r1] // 往这个地址写0 53 | mov pc, lr @ 返回 // bl 指令会把返回值放在lr寄存器里面 54 | 55 | copy_steppingstone_to_sdram: 56 | @ 将Steppingstone的4K数据全部复制到SDRAM中去 57 | @ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000 58 | 59 | mov r1, #0 // r1 的值为 0 60 | ldr r2, =SDRAM_BASE 61 | mov r3, #4*1024 // 4k 62 | 1: 63 | ldr r4, [r1],#4 @ 从Steppingstone读取4字节的数据,并让源地址加4 [r1] :内存单位为 0 地址(地 @ 址为r2) 64 | str r4, [r2],#4 @ 将此4字节的数据复制到SDRAM中,并让目地地址加4 65 | cmp r1, r3 @ 判断是否完成:源地址等于Steppingstone的未地址? 66 | bne 1b @ 若没有复制完,继续 67 | mov pc, lr @ 返回 68 | 69 | memsetup: 70 | @ 设置存储控制器以便使用SDRAM等外设 71 | 72 | mov r1, #MEM_CTL_BASE @ 存储控制器的13个寄存器的开始地址 // 0x48000024 73 | adrl r2, mem_cfg_val @ 这13个值的起始存储地址 // 13个寄存器地址放在r2,一个寄存器地址是4个字节 74 | add r3, r1, #52 @ 13*4 = 52 // +偏移地址 75 | 1: // A 76 | ldr r4, [r2], #4 @ 读取设置值,并让r2加4 77 | str r4, [r1], #4 @ 将此值写入寄存器,并让r1加4 //str : storage 存储 78 | cmp r1, r3 @ 判断是否设置完所有13个寄存器 79 | bne 1b @ 若没有写成,继续 // r1 != r3时,往A跳转继续循环该局部标号标记的函数 80 | mov pc, lr @ 返回 // 通过lr寄存器存储的地址,将该地址返回给pc,即返回到 // bl copy_steppingstone_to_sdram 该函数执行 81 | 82 | 83 | .align 4 84 | mem_cfg_val: 85 | @ 存储控制器13个寄存器的设置值 86 | .long 0x22011110 @ BWSCON 87 | .long 0x00000700 @ BANKCON0 88 | .long 0x00000700 @ BANKCON1 89 | .long 0x00000700 @ BANKCON2 90 | .long 0x00000700 @ BANKCON3 91 | .long 0x00000700 @ BANKCON4 92 | .long 0x00000700 @ BANKCON5 93 | .long 0x00018005 @ BANKCON6 94 | .long 0x00018005 @ BANKCON7 95 | .long 0x008C07A3 @ REFRESH 96 | .long 0x000000B1 @ BANKSIZE 97 | .long 0x00000030 @ MRSRB6 98 | .long 0x00000030 @ MRSRB7 99 | ``` 100 | ## s3c2440的程序启动方式 101 | ![s3c2440的程序启动方式](https://github.com/GalenDeng/Embedded-Linux/blob/master/9.%20%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8/s3c2440%E7%9A%84%E7%A8%8B%E5%BA%8F%E5%90%AF%E5%8A%A8%E6%96%B9%E5%BC%8F.JPG) 102 | * 启动方式对比 103 | ``` 104 | nor flash启动 : s3c2440的cpu的0地址指向nor flash 的bank0 105 | nand flash启动: s3c2440的cpu的0地址指向片内RAM(SRAM)[steppingstone],nand flash 把前4k的代码复制到片内RAM,从0地址开始执行程序 106 | ``` 107 | * 链接地址 意义 : 运行时,程序应该位于哪里 108 | * head.S => 从片内RAM的代码复制到SDRAM中(0x30000000) 109 | 110 | ## 反汇编指令 111 | ``` 112 | galen@HD66:/work/nfs_root/hardware/sdram$ cat sdram.dis 113 | 114 | sdram_elf: file format elf32-littlearm 115 | 116 | Disassembly of section .text: 117 | 链接地址 机器码 118 | 30000000 <_start>: // 程序开始执行的地址 119 | 30000000: eb000005 bl 3000001c 120 | 30000004: eb000010 bl 3000004c 121 | 30000008: eb000007 bl 3000002c 122 | 3000000c: e59ff090 ldr pc, [pc, #144] ; 300000a4 123 | // arm里面 pc = 当前指令的地址 + 8 当前指令的地址: 0x0c 124 | // 所以 ldr pc, [pc, #144] 的意义是 : pc = pc + #144 = 0xc + 8 + 144 = 164 = 0xa4 ; 125 | // 即从0xa4里面取出一个值赋给pc 126 | // 该指令执行完后 pc = 30000010 // 跳到SDRAM里面去 127 | // 和 30000010 : 相对应 128 | 129 | 30000010 : 130 | 30000010: e3a0d30d mov sp, #872415232 ; 0x34000000 131 | 30000014: eb000032 bl 300000e4
132 | 133 | 30000018 : 134 | 30000018: eafffffe b 30000018 135 | 136 | 3000001c : 137 | 3000001c: e3a01453 mov r1, #1392508928 ; 0x53000000 138 | 30000020: e3a02000 mov r2, #0 ; 0x0 139 | 30000024: e5812000 str r2, [r1] 140 | 30000028: e1a0f00e mov pc, lr 141 | 142 | 3000002c : 143 | 3000002c: e3a01000 mov r1, #0 ; 0x0 144 | 30000030: e3a02203 mov r2, #805306368 ; 0x30000000 145 | 30000034: e3a03a01 mov r3, #4096 ; 0x1000 146 | 30000038: e4914004 ldr r4, [r1], #4 147 | 3000003c: e4824004 str r4, [r2], #4 148 | 30000040: e1510003 cmp r1, r3 149 | 30000044: 1afffffb bne 30000038 150 | 30000048: e1a0f00e mov pc, lr 151 | 152 | 3000004c : 153 | 3000004c: e3a01312 mov r1, #1207959552 ; 0x48000000 154 | 30000050: e28f2018 add r2, pc, #24 ; 0x18 155 | 30000054: e1a00000 nop (mov r0,r0) 156 | 30000058: e2813034 add r3, r1, #52 ; 0x34 157 | 3000005c: e4924004 ldr r4, [r2], #4 158 | 30000060: e4814004 str r4, [r1], #4 159 | 30000064: e1510003 cmp r1, r3 160 | 30000068: 1afffffb bne 3000005c 161 | 3000006c: e1a0f00e mov pc, lr 162 | 163 | 30000070 : 164 | 30000070: 22011110 andcs r1, r1, #4 ; 0x4 165 | 30000074: 00000700 andeq r0, r0, r0, lsl #14 166 | 30000078: 00000700 andeq r0, r0, r0, lsl #14 167 | 3000007c: 00000700 andeq r0, r0, r0, lsl #14 168 | 30000080: 00000700 andeq r0, r0, r0, lsl #14 169 | 30000084: 00000700 andeq r0, r0, r0, lsl #14 170 | 30000088: 00000700 andeq r0, r0, r0, lsl #14 171 | 3000008c: 00018005 andeq r8, r1, r5 172 | 30000090: 00018005 andeq r8, r1, r5 173 | 30000094: 008c07a3 addeq r0, ip, r3, lsr #15 174 | 30000098: 000000b1 streqh r0, [r0], -r1 175 | 3000009c: 00000030 andeq r0, r0, r0, lsr r0 176 | 300000a0: 00000030 andeq r0, r0, r0, lsr r0 177 | 300000a4: 30000010 andcc r0, r0, r0, lsl r0 178 | 300000a8: e1a00000 nop (mov r0,r0) 179 | 300000ac: e1a00000 nop (mov r0,r0) 180 | ``` 181 | ## 程序从Steppingstone到SDRAM的执行过程 182 | ![程序从Steppingstone到SDRAM的执行过程](https://github.com/GalenDeng/Embedded-Linux/blob/master/9.%20%E5%AD%98%E5%82%A8%E6%8E%A7%E5%88%B6%E5%99%A8/%E7%A8%8B%E5%BA%8F%E4%BB%8ESteppingstone%E5%88%B0SDRAM%E7%9A%84%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B.JPG) -------------------------------------------------------------------------------- /20. 构建根文件系统/构建根文件系统.md: -------------------------------------------------------------------------------- 1 | ## 构建根文件系统 (2017.12.14) 2 | ``` 3 | static int noinline init_post(void) 4 | { 5 | free_initmem(); 6 | unlock_kernel(); 7 | mark_rodata_ro(); 8 | system_state = SYSTEM_RUNNING; 9 | numa_default_policy(); 10 | 11 | if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) 12 | printk(KERN_WARNING "Warning: unable to open an initial console.\n"); 13 | 14 | (void) sys_dup(0); 15 | (void) sys_dup(0); 16 | 17 | if (ramdisk_execute_command) { 18 | run_init_process(ramdisk_execute_command); 19 | printk(KERN_WARNING "Failed to execute %s\n", 20 | ramdisk_execute_command); 21 | } 22 | 23 | /* 24 | * We try each of these until one succeeds. 25 | * 26 | * The Bourne shell can be used instead of init if we are 27 | * trying to recover a really broken machine. 28 | */ 29 | if (execute_command) { //命令行参数 init=/linuxrc 第一个程序 30 | run_init_process(execute_command); 31 | printk(KERN_WARNING "Failed to execute %s. Attempting " 32 | "defaults...\n", execute_command); 33 | } 34 | run_init_process("/sbin/init"); // 若 execute_command 没有传值,则优先执行 /sbin/init -- 死循环 35 | run_init_process("/etc/init"); // 若 /sbin/init 不存在 , 则执行 /etc/init 36 | run_init_process("/bin/init"); 37 | run_init_process("/bin/sh"); 38 | 39 | panic("No init found. Try passing init= option to kernel."); 40 | } 41 | ``` 42 | * printf : 标准输出 ; scanf : 标准输入 ; error : 错误输出 43 | ## 内核怎样启动第一个应用程序 44 | 1. open(/dev/console) // 串口 标准输出 fd1 45 | 2. 复制 : sys_dup(0) : 标准输入 ; sys_dup(0): 错误输出 // 这两者都数据都打印到标准输出里面 /dev/console 46 | 3. run_init_process 47 | * 命令行 init = /linuxrc等 (execute_command) 48 | * 若 execute_command 不存在 ,依次执行 /sbin/init /etc/init /bin/init /bin/sh等 49 | ## 具体 : 构建根文件系统之启动第一个程序的步骤 50 | ![构建根文件系统之启动第一个程序的步骤](https://github.com/GalenDeng/Embedded-Linux/blob/master/20.0%20%E6%9E%84%E5%BB%BA%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/%E6%9E%84%E5%BB%BA%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B9%8B%E5%90%AF%E5%8A%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E6%9E%84%E5%BB%BA%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B9%8B%E5%90%AF%E5%8A%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%AD%A5%E9%AA%A4.JPG) 51 | * 如果没有挂载根文件系统,启动开发板会出现以下的提示 52 | ``` 53 | Warning: unable to open an initial console. 54 | Failed to execute /linuxrc. Attempting defaults... 55 | Kernel panic - not syncing: No init found. Try passing init= option to kernel. 56 | ``` 57 | * 对应于 58 | ``` 59 | if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) 60 | printk(KERN_WARNING "Warning: unable to open an initial console.\n"); // 打印这句 61 | 62 | (void) sys_dup(0); 63 | (void) sys_dup(0); 64 | 65 | if (ramdisk_execute_command) { 66 | run_init_process(ramdisk_execute_command); 67 | printk(KERN_WARNING "Failed to execute %s\n", 68 | ramdisk_execute_command); 69 | } 70 | 71 | if (execute_command) { 72 | run_init_process(execute_command); 73 | printk(KERN_WARNING "Failed to execute %s. Attempting " // 打印这句 74 | "defaults...\n", execute_command); 75 | } 76 | run_init_process("/sbin/init"); 77 | run_init_process("/etc/init"); 78 | run_init_process("/bin/init"); 79 | run_init_process("/bin/sh"); 80 | 81 | panic("No init found. Try passing init= option to kernel."); // 打印这句 82 | } 83 | ``` 84 | * 这个时候通过 dnw(usb烧写方式)烧写 fs_qtopia.yaffs2 和 fs_qtopia.jffs2 , 设置 fs_qtopia.jffs2的参数,烧写成功后按 b , 尝试进入根文件系统 85 | 1. set bootargs noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0 rootfstype=jffs2 86 | 2. `出现下面这种情况是:没有MTD分区,没有增加对yaffs文件系统的支持` 87 | ``` 88 | Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes 89 | empty_blocks 1958, bad_blocks 6, c->nr_blocks 2029 90 | VFS: Cannot open root device "mtdblock3" or unknown-block(31,3) 91 | Please append a correct "root=" boot option; here are the available partitions: 92 | 1f00 256 mtdblock0 (driver?) 93 | 1f01 128 mtdblock1 (driver?) 94 | 1f02 2048 mtdblock2 (driver?) 95 | 1f03 259712 mtdblock3 (driver?) 96 | Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,3) 97 | ``` 98 | ## busybox 99 | * busybox : `ls cd cp 等命令(其实每一个命令都是一个应用程序)的组合` 100 | ``` 101 | * ls ==> busybox ls 102 | * cp ==> busybox cp 103 | * cd ==> busybox cd 104 | 105 | # ls -l /bin/ls 106 | lrwxrwxrwx 1 0 0 7 Dec 24 2010 /bin/ls -> busybox 107 | # ls -l /bin/cp 108 | lrwxrwxrwx 1 0 0 7 Dec 24 2010 /bin/cp -> busybox 109 | 110 | # busybox ls 111 | bin etc linuxrc opt root sys usr 112 | dev lib mnt proc sbin tmp 113 | 114 | # ls -l /sbin/init 115 | lrwxrwxrwx 1 0 0 14 Dec 24 2010 /sbin/init -> ../bin/busybox 116 | // 所以要分析 /sbin/init 就要找到busybox的源码,去分析 117 | // busybox 源码在 /work/system/busybox-1.7.0.tar.bz2 118 | ``` 119 | * `内核的最终目的` :`启动客户的应用程序` 120 | * `init程序做的事情` 121 | 1. 读取配置文件 122 | 2. 解析配置文件 123 | 3. 执行用户程序 124 | 125 | ## 构造配置文件(没有配置文件的时候) 126 | * `构造配置文件代码` 127 | ``` 128 | file = fopen(INITTAB, "r"); 129 | if (file == NULL) { 130 | /* No inittab file -- set up some default behavior */ 131 | #endif 132 | /* Reboot on Ctrl-Alt-Del */ 133 | new_init_action(CTRLALTDEL, "reboot", ""); 134 | /* Umount all filesystems on halt/reboot */ 135 | new_init_action(SHUTDOWN, "umount -a -r", ""); 136 | /* Swapoff on halt/reboot */ 137 | if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", ""); 138 | // 内存不够的时候会把旧的程序挂载到硬盘,新的程序放在内存中, ENABLE_SWAPONOFF 这个没啥用 139 | 140 | /* Prepare to restart init when a HUP is received */ 141 | new_init_action(RESTART, "init", ""); 142 | /* Askfirst shell on tty1-4 */ 143 | new_init_action(ASKFIRST, bb_default_login_shell, ""); 144 | new_init_action(ASKFIRST, bb_default_login_shell, VC_2); 145 | new_init_action(ASKFIRST, bb_default_login_shell, VC_3); 146 | new_init_action(ASKFIRST, bb_default_login_shell, VC_4); 147 | /* sysinit */ 148 | new_init_action(SYSINIT, INIT_SCRIPT, ""); 149 | 150 | return; 151 | #if ENABLE_FEATURE_USE_INITTAB 152 | } 153 | ``` 154 | * `根据 inittab 构造` 155 | ``` 156 | # Format for each entry: ::: 157 | 158 | # : WARNING: This field has a non-traditional meaning for BusyBox init! 159 | If this 160 | # field is left blank, it is completely ignored. 161 | 162 | # : The runlevels field is completely ignored. 163 | ``` 164 | ## `构造结果` 165 | ![构造配置文件(没有配置文件的时候)](https://github.com/GalenDeng/Embedded-Linux/blob/master/20.0%20%E6%9E%84%E5%BB%BA%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/%E6%9E%84%E5%BB%BA%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B9%8B%E5%90%AF%E5%8A%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E6%9E%84%E9%80%A0%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6(%E6%B2%A1%E6%9C%89%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E6%97%B6%E5%80%99).JPG) 166 | 167 | ## init程序的工作原理 168 | ![init程序的工作原理](https://github.com/GalenDeng/Embedded-Linux/blob/master/20.0%20%E6%9E%84%E5%BB%BA%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/%E6%9E%84%E5%BB%BA%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B9%8B%E5%90%AF%E5%8A%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/init%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86.JPG) 169 | 170 | ## init程序解析 171 | ![init程序解析](https://github.com/GalenDeng/Embedded-Linux/blob/master/20.0%20%E6%9E%84%E5%BB%BA%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/%E6%9E%84%E5%BB%BA%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B9%8B%E5%90%AF%E5%8A%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/init%E7%A8%8B%E5%BA%8F%E8%A7%A3%E6%9E%90.JPG) 172 | 173 | ## 174 | ``` 175 | busybox-> init_main 176 | parse_inittab 177 | file = fopen(INITTAB, "r"); // 打开配置文件 /etc/inittab 178 | new_init_action(int action, const char *command, const char *cons) // 创建一个 // init_action结构,填充 179 | // 把这个结构体放入init_action_list链表 180 | --- 运行时机 181 | run_actions(SYSINIT); 182 | waitfor(a, 0); // 执行应用程序,等待它执行完毕 183 | runpid = (NULL == a)? pid : run(a); // 创建process子进程 184 | wpid = waitpid(runpid, &status, 0); // 等待它结束 185 | delete_init_action(a); // 在init_action_list链表里删除 186 | run_actions(WAIT); 187 | waitfor(a, 0); // 执行应用程序,等待它执行完毕 188 | runpid = (NULL == a)? pid : run(a); // 创建process子进程 189 | wpid = waitpid(runpid, &status, 0); // 等待它结束 190 | delete_init_action(a); // 在init_action_list链表里删除 191 | run_actions(ONCE); 192 | run(a); // 创建process子进程,不会等待子进程执行完毕再进行删除 193 | delete_init_action(a); // 在init_action_list链表里删除 194 | ``` 195 | } else if (a->action & ONCE) { 196 | run(a); 197 | delete_init_action(a); 198 | ``` 199 | while (1) { 200 | run_actions(RESPAWN); 201 | /* Only run stuff with pid==0. If they have 202 | * a pid, that means it is still running */ 203 | if (a->pid == 0) { 204 | a->pid = run(a); 205 | } 206 | run_actions(ASKFIRST); 207 | /* Only run stuff with pid==0. If they have 208 | * a pid, that means it is still running */ 209 | if (a->pid == 0) { 210 | a->pid = run(a); 211 | // 打印:"\nPlease press Enter to activate this console. " 212 | // 等待回车 不然一直停留在这里 213 | // 创建子进程 214 | ``` 215 | full_write(1, press_enter, sizeof(press_enter) - 1); 216 | while (read(0, &c, 1) == 1 && c != '\n') 217 | ``` 218 | } 219 | wpid = wait(NULL); // 等待子进程退出 220 | while (wpid > 0) { 221 | a->pid = 0; // 退出之后就设置pid=0 222 | } 223 | } 224 | 225 | 从默认的new_init_action反推出默认的配置文件: 226 | 227 | ## inittab格式 228 | # ::: 229 | 230 | # id => /dev/id , 用作终端:stdin stdout stderr : printf ,scanf , err 231 | ``` 232 | for (a = actions; a->name != 0; a++) { 233 | if (strcmp(a->name, action) == 0) { 234 | if (*id != '\0') { 235 | if (strncmp(id, "/dev/", 5) == 0) 236 | id += 5; 237 | strcpy(tmpConsole, "/dev/"); 238 | safe_strncpy(tmpConsole + 5, id, 239 | sizeof(tmpConsole) - 5); 240 | id = tmpConsole; 241 | } 242 | ``` 243 | ``` 244 | if (*id == '#' || *id == '\n') 245 | continue; // 忽略 246 | ``` 247 | # runlevel : 忽略 248 | # : The runlevels field is completely ignored. 249 | # action : 执行时机 250 | # : Valid actions include: sysinit, respawn, askfirst, wait, once, 251 | # restart, ctrlaltdel, and shutdown. 252 | # process : 应用程序或脚本 253 | ``` 254 | ``` 255 | struct init_action { 256 | struct init_action *next; 257 | int action; 258 | pid_t pid; 259 | char command[INIT_BUFFS_SIZE]; 260 | char terminal[CONSOLE_NAME_SIZE]; 261 | }; 262 | 263 | /* Static variables */ 264 | static struct init_action *init_action_list = NULL; 265 | ``` 266 | ## 最小的文件系统所必须的项 [五项] 267 | * /dev/console /dev/null -- 不指定id的话,标准输入、标准输出、错误输出定位到 /dev/null 268 | * /etc/inittab 269 | * 配置文件里指定的应用程序 270 | * C库 (如 printf fopen等函数都是通过C库实现的) 271 | * init本身,即busybox init => busybox 272 | 273 | ## 根文件系统分析总结 274 | ![根文件系统分析总结](https://github.com/GalenDeng/Embedded-Linux/blob/master/20.0%20%E6%9E%84%E5%BB%BA%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/%E6%9E%84%E5%BB%BA%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B9%8B%E5%90%AF%E5%8A%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%88%86%E6%9E%90%E6%80%BB%E7%BB%93.JPG) 275 | -------------------------------------------------------------------------------- /10. 内存管理单元MMU/10.1 内存管理单元MMU.md: -------------------------------------------------------------------------------- 1 | ## 10.1 内存管理单元MMU (2017.12.18) 2 | * VA : virtual address (cpu核) 3 | * MVA: modified virtual address 变换后的虚拟地址 (caches和MMU看不到VA,而是用MVA转换成PA) 4 | * PA : physical address 5 | * 利用PID生成MVA的目的 : 减少切换进程时的代价 6 | * MVA ===> PA 的方式:1. 数学公式 2. 表格 7 | 1. `MMU作用` 8 | * 权限管理: 如: 内核程序占用a地址,b程序占用b地址,c程序占用c地址,b程序不能修改内核的东西,内核不能修改b程序的东西,b程序想访问内核的程序的时候会发生崩溃的现象,这就权限管理, 9 | * 地址映射 : 虚拟地址 ===> 物理地址 10 | ## MMU的地址映射作用 11 | ![MMU的地址映射作用](https://github.com/GalenDeng/Embedded-Linux/blob/master/10.%20%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/MMU%E7%9A%84%E5%9C%B0%E5%9D%80%E6%98%A0%E5%B0%84%E4%BD%9C%E7%94%A8.JPG) 12 | ## cpu--MMU--存储管理器--SDRAM关系图 13 | ![cpu--MMU--存储管理器--SDRAM关系图](https://github.com/GalenDeng/Embedded-Linux/blob/master/10.%20%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/cpu--MMU--%E5%AD%98%E5%82%A8%E7%AE%A1%E7%90%86%E5%99%A8--SDRAM%E5%85%B3%E7%B3%BB%E5%9B%BE.JPG) 14 | * 写程序时的链接地址 : 也是没有物理地址和虚拟地址的概念的,链接地址是cpu看到的,是从cpu的角度说的 15 | * 1M = 2^20 = 0x100000 ; 0xa000050 / 0x100000 = 0xa00 =2560(DEC) ,所以我们就在2560这个段中填充 0x56000000 16 | ``` 17 | 0xa000 18 | ``` 19 | ## MMU实现步骤 20 | * 建映射表格(建虚拟地址到物理地址的映射) 21 | * b把表格地址告诉MMU 22 | * 启动MMU 23 | * head.S 24 | ``` 25 | @************************************************************************* 26 | @ File:head.S 27 | @ 功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU, 28 | @ 然后跳到SDRAM继续执行 29 | @************************************************************************* 30 | 31 | // 这里直接用C语言写的代码 32 | .text 33 | .global _start 34 | _start: 35 | ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈 // 指向片内内存的最顶部 36 | bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 37 | bl memsetup @ 设置存储控制器以使用SDRAM 38 | bl copy_2th_to_sdram @ 将第二部分代码复制到SDRAM //2048之后的代码拷贝到sdram中 39 | bl create_page_table @ 设置页表 40 | bl mmu_init @ 启动MMU 41 | ldr sp, =0xB4000000 @ 重设栈指针,指向SDRAM顶端(使用虚拟地址) 42 | ldr pc, =0xB0004000 @ 跳到SDRAM中继续执行第二部分代码 //相当于 ldr pc, = main 43 | halt_loop: 44 | b halt_loop 45 | ``` 46 | * init.c 47 | ``` 48 | /* 49 | * init.c: 进行一些初始化,在Steppingstone中运行 50 | * 它和head.S同属第一部分程序,此时MMU未开启,使用物理地址 51 | */ 52 | 53 | /* WATCHDOG寄存器 */ 54 | #define WTCON (*(volatile unsigned long *)0x53000000) 55 | /* 存储控制器的寄存器起始地址 */ 56 | #define MEM_CTL_BASE 0x48000000 57 | 58 | 59 | /* 60 | * 关闭WATCHDOG,否则CPU会不断重启 61 | */ 62 | void disable_watch_dog(void) 63 | { 64 | WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可 65 | } 66 | 67 | /* 68 | * 设置存储控制器以使用SDRAM 69 | */ 70 | void memsetup(void) 71 | { 72 | /* SDRAM 13个寄存器的值 */ 73 | unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON 74 | 0x00000700, //BANKCON0 75 | 0x00000700, //BANKCON1 76 | 0x00000700, //BANKCON2 77 | 0x00000700, //BANKCON3 78 | 0x00000700, //BANKCON4 79 | 0x00000700, //BANKCON5 80 | 0x00018005, //BANKCON6 81 | 0x00018005, //BANKCON7 82 | 0x008C07A3, //REFRESH 83 | 0x000000B1, //BANKSIZE 84 | 0x00000030, //MRSRB6 85 | 0x00000030, //MRSRB7 86 | }; 87 | int i = 0; 88 | volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE; 89 | for(; i < 13; i++) 90 | p[i] = mem_cfg_val[i]; // 直接赋值就可以了 91 | } 92 | ``` 93 | * mmu.lds 94 | ``` 95 | SECTIONS { 96 | firtst 0x00000000 : { head.o init.o } // 分了 first,second 两个段,这里是 first段 97 | // 把 head.S和init.c编译的内容head.o和init.o放在first这个段中 98 | second 0xB0004000 : AT(2048) { leds.o } // AT(20480) : 在偏移地址2048中 99 | // 0x00000000 0xB0004000 为链接时的运行地址(链接地址) 100 | } 101 | ``` 102 | ``` 103 | 链接脚本将程序分为两个段:first和second。前者由head.o和init.o组成,它的加载地址和运行地址都是0,所以在运行时不需要移动代码,后者由leds.o组成,它的加载地址为2048,重定位地址为0xB0004000,这表明段second存放在编译所得的映像文件的2048处,在运行前需要将它复制到地址0xB0004000(MMU映射),将编译所得的映像文件烧入到nand flash后,head.o和init.o依次从0x00000000处存放,而leds.o存放在2048处。从nand flash启动时,cpu收件将nand flash的前4KB复制到cpu自身的ram(steppingstone)中去,这样leds.o存放在地址为2048处,而运行的时候需要将steppingstone中2048 - 4096的内容复制到sdram中起始地址0xB0004000处,从而使用ldr跳转时才会正确执行下去。 104 | ``` 105 | ``` 106 | 1、运行地址<--->链接地址:他们两个是等价的,只是两种不同的说法。 107 | 2、加载地址<--->存储地址:他们两个是等价的,也是两种不同的说法。 108 | 109 | 运行地址:程序在SRAM、SDRAM中执行时的地址。就是执行这条指令时,PC应该等于这个地址,换句话说,PC等于这个地址时,这条指令应该保存在这个地址内。 110 | 加载地址:程序保存在Nand flash中的地址。 111 | ``` 112 | ## mmu.bin存放地址 113 | ![mmu.bin存放地址](https://github.com/GalenDeng/Embedded-Linux/blob/master/10.%20%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/mmu.bin%E5%AD%98%E6%94%BE%E5%9C%B0%E5%9D%80.JPG) 114 | * Makefile 115 | ``` 116 | objs := head.o init.o leds.o 117 | 118 | mmu.bin : $(objs) 119 | arm-linux-ld -Tmmu.lds -o mmu_elf $^ // 通过链接脚本来生成elf可执行文件 120 | arm-linux-objcopy -O binary -S mmu_elf $@ // $@ 指:mmu.bin 121 | arm-linux-objdump -D -m arm mmu_elf > mmu.dis 122 | 123 | %.o:%.c 124 | arm-linux-gcc -Wall -O2 -c -o $@ $< 125 | 126 | %.o:%.S 127 | arm-linux-gcc -Wall -O2 -c -o $@ $< 128 | 129 | clean: 130 | rm -f mmu.bin mmu_elf mmu.dis *.o 131 | ``` 132 | * 拷贝到SDRAM的代码 133 | ``` 134 | /* 135 | * 将第二部分代码复制到SDRAM 136 | */ 137 | void copy_2th_to_sdram(void) 138 | { 139 | unsigned int *pdwSrc = (unsigned int *)2048; 140 | unsigned int *pdwDest = (unsigned int *)0x30004000; 141 | 142 | while (pdwSrc < (unsigned int *)4096) 143 | { 144 | *pdwDest = *pdwSrc; 145 | pdwDest++; 146 | pdwSrc++; 147 | } 148 | } 149 | ``` 150 | * 段页表都是以 1M 为单位 151 | ## mmu的虚拟地址和物理地址的映射设置 152 | ![mmu的虚拟地址和物理地址的映射设置](https://github.com/GalenDeng/Embedded-Linux/blob/master/10.%20%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/mmu%E7%9A%84%E8%99%9A%E6%8B%9F%E5%9C%B0%E5%9D%80%E5%92%8C%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80%E7%9A%84%E6%98%A0%E5%B0%84%E8%AE%BE%E7%BD%AE.JPG) 153 | * 设置页表 154 | ``` 155 | /* 156 | * 设置页表 157 | */ 158 | void create_page_table(void) 159 | { 160 | 161 | /* 162 | * 用于段描述符的一些宏定义 163 | */ 164 | #define MMU_FULL_ACCESS (3 << 10) /* 访问权限 */ 165 | #define MMU_DOMAIN (0 << 5) /* 属于哪个域 */ 166 | #define MMU_SPECIAL (1 << 4) /* 必须是1 */ 167 | #define MMU_CACHEABLE (1 << 3) /* cacheable */ 168 | #define MMU_BUFFERABLE (1 << 2) /* bufferable */ 169 | #define MMU_SECTION (2) /* 表示这是段描述符 */ 170 | #define MMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \ 171 | MMU_SECTION) 172 | #define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \ 173 | MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION) 174 | #define MMU_SECTION_SIZE 0x00100000 175 | 176 | unsigned long virtuladdr, physicaladdr; 177 | unsigned long *mmu_tlb_base = (unsigned long *)0x30000000; 178 | 179 | /* 180 | * Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0, 181 | * 为了在开启MMU后仍能运行第一部分的程序, 182 | * 将0~1M的虚拟地址映射到同样的物理地址 183 | */ 184 | virtuladdr = 0; 185 | physicaladdr = 0; 186 | *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \ 187 | MMU_SECDESC_WB; 188 | 189 | /* 190 | * 0x56000000是GPIO寄存器的起始物理地址, 191 | * GPBCON和GPBDAT这两个寄存器的物理地址0x56000050、0x56000054, 192 | * 为了在第二部分程序中能以地址0xA0000050、0xA0000054来操作GPFCON、GPFDAT, 193 | * 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间 194 | */ 195 | virtuladdr = 0xA0000000; 196 | physicaladdr = 0x56000000; 197 | *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \ 198 | MMU_SECDESC; 199 | 200 | /* 201 | * SDRAM的物理地址范围是0x30000000~0x33FFFFFF, 202 | * 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上, 203 | * 总共64M,涉及64个段描述符 204 | */ 205 | virtuladdr = 0xB0000000; 206 | physicaladdr = 0x30000000; 207 | while (virtuladdr < 0xB4000000) 208 | { 209 | *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \ 210 | MMU_SECDESC_WB; 211 | virtuladdr += 0x100000; 212 | physicaladdr += 0x100000; 213 | } 214 | } 215 | ``` 216 | * 启动 mmu (ttb:页表地址) 217 | ``` 218 | /* 219 | * 启动MMU 220 | */ 221 | void mmu_init(void) 222 | { 223 | unsigned long ttb = 0x30000000; 224 | 225 | // 嵌入汇编 : 好书 linux内核完全注释 226 | __asm__( 227 | "mov r0, #0\n" 228 | "mcr p15, 0, r0, c7, c7, 0\n" /* 使无效ICaches和DCaches */ 229 | 230 | "mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer on v4 */ 231 | "mcr p15, 0, r0, c8, c7, 0\n" /* 使无效指令、数据TLB */ 232 | 233 | "mov r4, %0\n" /* r4 = 页表基址 */ 234 | "mcr p15, 0, r4, c2, c0, 0\n" /* 设置页表基址寄存器 */ 235 | 236 | "mvn r0, #0\n" 237 | "mcr p15, 0, r0, c3, c0, 0\n" /* 域访问控制寄存器设为0xFFFFFFFF, 238 | * 不进行权限检查 239 | */ 240 | /* 241 | * 对于控制寄存器,先读出其值,在这基础上修改感兴趣的位, 242 | * 然后再写入 243 | */ 244 | "mrc p15, 0, r0, c1, c0, 0\n" /* 读出控制寄存器的值 */ 245 | 246 | /* 控制寄存器的低16位含义为:.RVI ..RS B... .CAM 247 | * R : 表示换出Cache中的条目时使用的算法, 248 | * 0 = Random replacement;1 = Round robin replacement 249 | * V : 表示异常向量表所在的位置, 250 | * 0 = Low addresses = 0x00000000;1 = High addresses = 0xFFFF0000 251 | * I : 0 = 关闭ICaches;1 = 开启ICaches 252 | * R、S : 用来与页表中的描述符一起确定内存的访问权限 253 | * B : 0 = CPU为小字节序;1 = CPU为大字节序 254 | * C : 0 = 关闭DCaches;1 = 开启DCaches 255 | * A : 0 = 数据访问时不进行地址对齐检查;1 = 数据访问时进行地址对齐检查 256 | * M : 0 = 关闭MMU;1 = 开启MMU 257 | */ 258 | 259 | /* 260 | * 先清除不需要的位,往下若需要则重新设置它们 261 | */ 262 | /* .RVI ..RS B... .CAM */ 263 | "bic r0, r0, #0x3000\n" /* ..11 .... .... .... 清除V、I位 */ 264 | "bic r0, r0, #0x0300\n" /* .... ..11 .... .... 清除R、S位 */ 265 | "bic r0, r0, #0x0087\n" /* .... .... 1... .111 清除B/C/A/M */ 266 | 267 | /* 268 | * 设置需要的位 269 | */ 270 | "orr r0, r0, #0x0002\n" /* .... .... .... ..1. 开启对齐检查 */ 271 | "orr r0, r0, #0x0004\n" /* .... .... .... .1.. 开启DCaches */ 272 | "orr r0, r0, #0x1000\n" /* ...1 .... .... .... 开启ICaches */ 273 | "orr r0, r0, #0x0001\n" /* .... .... .... ...1 使能MMU */ 274 | 275 | "mcr p15, 0, r0, c1, c0, 0\n" /* 将修改的值写入控制寄存器 */ 276 | : /* 无输出 */ //第一个冒号表示要输出什么东西 277 | : "r" (ttb) ); // 第二个冒号表示要输入什么东西 ttb变量存在r里面 278 | } 279 | ``` 280 | ## 程序复制代码,设置页表、启动MMU的执行过程 281 | ![程序复制代码,设置页表、启动MMU的执行过程](https://github.com/GalenDeng/Embedded-Linux/blob/master/10.%20%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E5%8D%95%E5%85%83MMU%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E7%A8%8B%E5%BA%8F%E5%A4%8D%E5%88%B6%E4%BB%A3%E7%A0%81%EF%BC%8C%E8%AE%BE%E7%BD%AE%E9%A1%B5%E8%A1%A8%E3%80%81%E5%90%AF%E5%8A%A8MMU%E7%9A%84%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B.JPG) 282 | 283 | * TLB: translation Lookaside Buffers 转译查找缓存 284 | ``` 285 | TLB: 高速、容量相对较小的存储器,通过它来存储近期用到的页表条目(段/大页/小页/极小页描述符), 286 | 避免每次地址转换时都到主存去查找 287 | ``` -------------------------------------------------------------------------------- /19. 移植linux内核/sourceinsight分析内核代码.md: -------------------------------------------------------------------------------- 1 | ## sourceinsight分析内核代码 (2017.12.12) 2 | * `内核运行的最终目的` : `运行应用程序(根文件系统)` 3 | * `处理传入参数` : `/arch/arm/kernel/head.S` 4 | * `/arch/arm/kernel/head.S` 压缩为 `/arch/arm/boot/compressed`,要启动内核,需要添加`自解压代码`,即 5 | * `启动内核 = 自解压 + 压缩的内核` ,入口在 `自解压代码中` 6 | * `自解压代码作用` 7 | ``` 8 | 解压压缩的内核,启动内核 9 | ``` 10 | ## linux的启动过程包括两个阶段 11 | * `架构/开发板相关的引导过程` : `通常使用汇编语言编写` 12 | * `后续的通用启动过程` : `start kernel` `主要使用C语言编写` `仍然有部分架构/开发板相关的代码` --- `setup-arch函数` 13 | ## /arch/arm/kernel/head.S 分析 14 | ``` 15 | .section ".text.head", "ax" 16 | .type stext, %function 17 | ENTRY(stext) 18 | msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode 19 | @ and irqs disabled 20 | mrc p15, 0, r9, c0, c0 @ get processor id //读取寄存器,获取处理器ID,看是否能支持该处理器 21 | bl __lookup_processor_type @ r5=procinfo r9=cpuid 22 | movs r10, r5 @ invalid processor (r5=0)? 23 | beq __error_p @ yes, error 'p' //不能支持的处理器跳到这里处理 24 | bl __lookup_machine_type @ r5=machinfo //机器ID 相当于 u-boot的 bd->bi_arch_number的传入 r1 25 | movs r8, r5 @ invalid machine (r5=0)? 26 | beq __error_a @ yes, error 'a' 27 | bl __create_page_tables 28 | // 创建列表 因为 vmlinux.lds 的 . = (0xc0000000) + 0x00008000; 为虚拟地址,不是真正存在的内存, 29 | //所以要建列表,启动mmu 30 | 31 | ldr r13, __switch_data @ address to jump to after //使能mmu 32 | @ mmu has been enabled 33 | adr lr, __enable_mmu @ return (PIC) address 34 | 35 | .type __switch_data, %object 36 | __switch_data: 37 | .long __mmap_switched 38 | .long __data_loc @ r4 39 | .long __data_start @ r5 40 | .long __bss_start @ r6 41 | .long _end @ r7 42 | .long processor_id @ r4 43 | .long __machine_arch_type @ r5 44 | .long cr_alignment @ r6 45 | .long init_thread_union + THREAD_START_SP @ sp 46 | 47 | /* 48 | * The following fragment of code is executed with the MMU on in MMU mode, 49 | * and uses absolute addresses; this is not position independent. 50 | * 51 | * r0 = cp#15 control register 52 | * r1 = machine ID 53 | * r9 = processor ID 54 | */ 55 | .type __mmap_switched, %function // 跳到 start kernel,start kernel 为第一个 内核C函数 56 | // start kernel 来处理启动参数 57 | __mmap_switched: 58 | adr r3, __switch_data + 4 59 | 60 | b start_kernel 61 | 62 | ``` 63 | ``` 64 | * start kernel 65 | 66 | lock_kernel(); 67 | tick_init(); 68 | boot_cpu_init(); 69 | page_address_init(); 70 | printk(KERN_NOTICE); 71 | printk(linux_banner); // 输出一些内核信息 72 | setup_arch(&command_line); // 处理uboot传进来的启动参数 73 | setup_command_line(command_line); // 处理uboot传进来的启动参数 74 | unwind_setup(); 75 | setup_per_cpu_areas(); 76 | smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ 77 | ``` 78 | * `如` 79 | ``` 80 | Starting kernel ... 81 | 82 | Uncompressing Linux...................................................................................................................... done, booting the kernel. 83 | Linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #1 Sat May 11 15:09:41 CST 2013 84 | CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177 85 | Machine: SMDK2440 86 | Memory policy: ECC disabled, Data cache writeback 87 | CPU S3C2440A (id 0x32440001) 88 | ``` 89 | * 内核要处理的参数 90 | ![内核要处理的参数](https://github.com/GalenDeng/Embedded-Linux/blob/master/19.%20%E7%A7%BB%E6%A4%8Dlinux%E5%86%85%E6%A0%B8/linux%E5%86%85%E6%A0%B8%E5%90%AF%E5%8A%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%86%85%E6%A0%B8%E8%A6%81%E5%A4%84%E7%90%86%E7%9A%84%E5%8F%82%E6%95%B0.JPG) 91 | * parse : 解析 92 | * `start kernel后要挂载根文件系统`,这样才能使用应用程序 93 | * `内核第二阶段的启动流程` 94 | ``` 95 | * arch/arm/kernel/head.S 96 | start kernel 97 | setup_arch(&command_line); // 解析u-boot传入的启动参数 98 | setup_command_line(command_line); // 解析u-boot传入的启动参数 99 | rest_init() 100 | kernel_init 101 | prepare_namespace() 102 | mount_root() //挂载根文件系统 103 | init_post() //作用:打开/dev/console,执行应用程序 104 | ``` 105 | ## 内核第二阶段具体的启动流程 106 | ![内核第二阶段具体的启动流程](https://github.com/GalenDeng/Embedded-Linux/blob/master/19.%20%E7%A7%BB%E6%A4%8Dlinux%E5%86%85%E6%A0%B8/linux%E5%86%85%E6%A0%B8%E5%90%AF%E5%8A%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%86%85%E6%A0%B8%E7%AC%AC%E4%BA%8C%E9%98%B6%E6%AE%B5%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B.JPG) 107 | ``` 108 | static void noinline __init_refok rest_init(void) 109 | __releases(kernel_lock) 110 | { 111 | int pid; 112 | 113 | kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); // 创建内核的线程 这里调用 kernel_init的函数 114 | numa_default_policy(); 115 | pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); 116 | kthreadd_task = find_task_by_pid(pid); 117 | unlock_kernel(); 118 | 119 | /* 120 | * The boot idle thread must execute schedule() 121 | * at least one to get things moving: 122 | */ 123 | preempt_enable_no_resched(); 124 | schedule(); 125 | preempt_disable(); 126 | 127 | /* Call into cpu_idle with preempt disabled */ 128 | cpu_idle(); 129 | } 130 | ``` 131 | 1. `@ 为注释` 132 | ``` 133 | .type __lookup_machine_type, %function 134 | __lookup_machine_type: 135 | adr r3, 3b @ r3 = 3b 的地址 实际存在的地址 -- 物理地址 136 | /* 137 | 3: .long . // 3b的地址 138 | .long __arch_info_begin 139 | .long __arch_info_end 140 | */ 141 | 142 | ldmia r3, {r4, r5, r6} @ r4 = "." 这是3b的虚拟地址,取决于编译器编译到这里的地址是啥, 143 | @ r5 = __arch_info_begin , r6 = __arch_info_end 144 | // __arch_info_begin __arch_info_end 在内核里面找不到定义,只能在链接脚本里面找 145 | // vmlinux.lds 146 | /* 147 | __arch_info_begin = .; 148 | *(.arch.info.init) // 架构相关的初始化信息存放在这里 地址从 (0xc0000000) + 0x00008000 开始 149 | __arch_info_end = .; 150 | */ 151 | sub r3, r3, r4 @ get offset between virt&phys 152 | add r5, r5, r3 @ convert virt addresses to 153 | add r6, r6, r3 @ physical address space 154 | 1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type 155 | teq r3, r1 @ matches loader number? 156 | beq 2f @ found 157 | add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc 158 | cmp r5, r6 159 | blo 1b 160 | mov r5, #0 @ unknown machine 161 | 2: mov pc, lr 162 | ``` 163 | 2. `grep .arch.info.init` 164 | * galen@HD66:/work/linux-2.6-transplant/linux-2.6.22.6$ grep ".arch.info.init" * -nR 165 | ``` 166 | galen@HD66:/work/linux-2.6-transplant/linux-2.6.22.6$ grep ".arch.info.init" * -nR 167 | arch/arm/kernel/vmlinux.lds.S:39: *(.arch.info.init) 168 | arch/arm/kernel/vmlinux.lds:306: *(.arch.info.init) 169 | 170 | Binary file arch/arm/mach-s3c2443/mach-smdk2443.o matches 171 | Binary file arch/arm/mach-s3c2443/built-in.o matches 172 | Binary file arch/arm/mach-s3c2440/built-in.o matches 173 | Binary file arch/arm/mach-s3c2440/mach-smdk2440.o matches 174 | Binary file arch/arm/mach-s3c2412/built-in.o matches 175 | Binary file arch/arm/mach-s3c2412/mach-vstms.o matches 176 | Binary file arch/arm/mach-s3c2412/mach-smdk2413.o matches 177 | Binary file arch/arm/mach-s3c2410/built-in.o matches 178 | Binary file arch/arm/mach-s3c2410/mach-smdk2410.o matches 179 | Binary file arch/arm/mach-s3c2410/mach-qt2410.o matches 180 | 181 | include/asm-arm/mach/arch.h:53: __attribute__((__section__(".arch.info.init"))) = { \ 182 | include/asm/mach/arch.h:53: __attribute__((__section__(".arch.info.init"))) = { \ 183 | galen@HD66:/work/linux-2.6-transplant/linux-2.6.22.6$ 184 | ``` 185 | * `猜测支持 mach-s3c2443 mach-s3c2440 mach-s3c2412 mach-s3c2410 这些单板` 186 | ``` 187 | * include/asm-arm/mach/arch.h:53 188 | #define MACHINE_START(_type,_name) \ 189 | static const struct machine_desc __mach_desc_##_type \ 190 | __used \ 191 | __attribute__((__section__(".arch.info.init"))) = { \ 192 | .nr = MACH_TYPE_##_type, \ 193 | .name = _name, 194 | 195 | #define MACHINE_END \ 196 | }; 197 | ``` 198 | * sourceinsight中查找 MACHINE_START 这个宏谁在使用 199 | ``` 200 | * Mach-smdk2440.c(arch/arm/mach-s3c2440) 201 | MACHINE_START(S3C2440, "SMDK2440") // 估计是设置结构体 __attribute__((__section__(".arch.info.init"))) 202 | /* Maintainer: Ben Dooks */ 203 | .phys_io = S3C2410_PA_UART, 204 | .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, 205 | .boot_params = S3C2410_SDRAM_PA + 0x100, 206 | 207 | .init_irq = s3c24xx_init_irq, 208 | .map_io = smdk2440_map_io, 209 | .init_machine = smdk2440_machine_init, 210 | .timer = &s3c24xx_timer, 211 | MACHINE_END 212 | ``` 213 | * `所以: 这里的意思为:定义了一个结构体,类型为machine_desc,结构体的变量名称为:__mach_desc_S3C2440` 214 | ``` 215 | * include/asm-arm/mach/arch.h:53 216 | #define MACHINE_START(_type,_name) \ 217 | static const struct machine_desc __mach_desc_##_type \ 218 | // __mach_desc_##_type = __mach_desc_S3C2440 ##_type中的##仅仅为连词符号 219 | 220 | __used \ 221 | __attribute__((__section__(".arch.info.init"))) = { \ 222 | // 这里的 machine_desc 结构体被强制作为一个 .arch.info.init的段,并放在 __arch_info_begin = .; 和 //__arch_info_end = .;之间 223 | .nr = MACH_TYPE_##_type, \ 224 | // .nr = MACH_TYPE_S3C2440 225 | .name = _name, 226 | // .name = "SMDK2440" 227 | //然后把以下的东西写进来 228 | .phys_io = S3C2410_PA_UART, 229 | .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, 230 | .boot_params = S3C2410_SDRAM_PA + 0x100, 231 | 232 | .init_irq = s3c24xx_init_irq, 233 | .map_io = smdk2440_map_io, 234 | .init_machine = smdk2440_machine_init, 235 | .timer = &s3c24xx_timer, 236 | // #define MACHINE_END \ 237 | // }; 238 | }; 239 | ``` 240 | * `struct machine_desc` 241 | ``` 242 | struct machine_desc { 243 | /* 244 | * Note! The first four elements are used 245 | * by assembler code in head-armv.S 246 | */ 247 | unsigned int nr; /* architecture number */ 248 | unsigned int phys_io; /* start of physical io */ 249 | unsigned int io_pg_offst; /* byte offset for io 250 | * page tabe entry */ 251 | 252 | const char *name; /* architecture name */ 253 | unsigned long boot_params; /* tagged list */ 254 | 255 | unsigned int video_start; /* start of video RAM */ 256 | unsigned int video_end; /* end of video RAM */ 257 | 258 | unsigned int reserve_lp0 :1; /* never has lp0 */ 259 | unsigned int reserve_lp1 :1; /* never has lp1 */ 260 | unsigned int reserve_lp2 :1; /* never has lp2 */ 261 | unsigned int soft_reboot :1; /* soft reboot */ 262 | void (*fixup)(struct machine_desc *, 263 | struct tag *, char **, 264 | struct meminfo *); 265 | void (*map_io)(void);/* IO mapping function */ 266 | void (*init_irq)(void); 267 | struct sys_timer *timer; /* system tick timer */ 268 | void (*init_machine)(void); 269 | }; 270 | ``` 271 | ## ARM的linux内核vmlinux的启动过程(包括架构/开发板相关的引导过程 + 后续的通用启动过程) 272 | ![ARM的linux内核vmlinux的启动过程](https://github.com/GalenDeng/Embedded-Linux/blob/master/19.%20%E7%A7%BB%E6%A4%8Dlinux%E5%86%85%E6%A0%B8/linux%E5%86%85%E6%A0%B8%E5%90%AF%E5%8A%A8%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/ARM%E7%9A%84linux%E5%86%85%E6%A0%B8%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B.JPG) 273 | * zImage : 压缩格式的内核 --- 首先进行自解压得到vmlinux,然后执行vmlinux开始“正常的”的启动流程 274 | ## `搜索分区信息` 275 | * galen@HD66:/work/linux-2.6-transplant/linux-2.6.22.6$ grep "\"bootloader\"" * -nR 276 | ``` 277 | arch/arm/mach-omap1/board-osk.c:55: .name = "bootloader", 278 | arch/arm/mach-sa1100/assabet.c:110: .name = "bootloader", 279 | arch/arm/mach-sa1100/assabet.c:131: .name = "bootloader", 280 | arch/arm/mach-sa1100/collie.c:184: .name = "bootloader", 281 | arch/arm/plat-s3c24xx/common-smdk.c:120: .name = "bootloader", // 应该是在这个文件里面修改的 282 | arch/arm/mach-davinci/board-evm.c:42: .name = "bootloader", 283 | arch/arm/mach-omap2/board-h4.c:83: .name = "bootloader", 284 | drivers/mtd/maps/sa1100-flash.c:72: .name = "bootloader", 285 | drivers/mtd/maps/pq2fads.c:53: .name = "bootloader", 286 | drivers/mtd/maps/wr_sbc82xx_flash.c:39: .name = "bootloader", 287 | drivers/mtd/maps/wr_sbc82xx_flash.c:47: .name = "bootloader", 288 | ``` 289 | * 查看 `arch/arm/plat-s3c24xx/common-smdk.c` 290 | ``` 291 | * 可见分区信息被写死了 292 | static struct mtd_partition smdk_default_nand_part[] = { 293 | [0] = { 294 | .name = "bootloader", 295 | .size = 0x00040000, 296 | .offset = 0, 297 | }, 298 | [1] = { 299 | .name = "params", 300 | .offset = MTDPART_OFS_APPEND, // OFS_APPEND 表示紧接上一个分区的意思 301 | .size = 0x00020000, 302 | }, 303 | [2] = { 304 | .name = "kernel", 305 | .offset = MTDPART_OFS_APPEND, 306 | .size = 0x00200000, 307 | }, 308 | [3] = { 309 | .name = "root", 310 | .offset = MTDPART_OFS_APPEND, 311 | .size = MTDPART_SIZ_FULL, 312 | } 313 | }; 314 | ``` -------------------------------------------------------------------------------- /20. 构建根文件系统/20.3 创建完整的根文件系统.md: -------------------------------------------------------------------------------- 1 | ## 20.3 创建完整的根文件系统 (2017.12.14) 2 | 3 | ## `完成构建根文件系统的第一项 /dev/console /dev/null` 4 | 1. `首先根据 busybox.md 编译和安装 busybox` 5 | 2. `查看 /dev/console /dev/null` 6 | ``` 7 | galen@HD66:/work/nfs_root/first-fs$ ls /dev/console /dev/null -l 8 | crw------- 1 root root 5, 1 Dec 13 07:44 /dev/console // c : 字符设备 5 : 主设备号 1 : 次设备号 9 | crw-rw-rw- 1 root root 1, 3 Dec 13 07:44 /dev/null 10 | ``` 11 | 3. `mknod 命令建立一个目录项和一个特殊文件的对应索引节点。第一个参数是 Name 项设备的名称。选择一个描述性的设备名称` : `make node` 12 | * node --- 节点 13 | ``` 14 | * galen@HD66:/work/nfs_root/first-fs$ mkdir dev 15 | * galen@HD66:/work/nfs_root/first-fs$ cd dev 16 | * galen@HD66:/work/nfs_root/first-fs/dev$ sudo mknod console c 5 1 17 | * galen@HD66:/work/nfs_root/first-fs/dev$ sudo mknod null c 1 3 18 | * galen@HD66:/work/nfs_root/first-fs/dev$ ls -l 19 | total 0 20 | crw-r--r-- 1 root root 5, 1 Dec 13 16:00 console 21 | crw-r--r-- 1 root root 1, 3 Dec 13 17:32 null 22 | ``` 23 | 24 | ## `完成构建根文件系统的第三项 /etc/inittab` 25 | 1. galen@HD66:/work/nfs_root/first-fs/dev$ cd .. 26 | 2. galen@HD66:/work/nfs_root/first-fs$ mkdir etc 27 | 3. galen@HD66:/work/nfs_root/first-fs$ cd etc/ 28 | 4. galen@HD66:/work/nfs_root/first-fs/etc$ touch inittab 29 | 5. galen@HD66:/work/nfs_root/first-fs/etc$ vim inittab 30 | 6. 输入: console::askfirst:-bin/sh ; :wq! // 标准输入、标准输出、标准错误输出都定位到console这个终端里面 31 | 32 | ## `完成构建根文件系统的第四项 配置文件指定的程序` 33 | * 配置文件指定的程序 (现在还没有必要做) 34 | 35 | ## `完成构建根文件系统的第五项 C库` 36 | 1. galen@HD66:/work/nfs_root/first-fs/etc$ cd /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib 37 | 2. ls -l // .a 为静态库 .so 动态库 38 | 3. galen@HD66:/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib$ mkdir /work/nfs_root/first-fs/lib 39 | 4. galen@HD66:/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib$ cp *.so* /work/nfs_root/first-fs/lib -d 40 | * `-d : 链接文件保持为链接文件,若不加上 -d 选项,拷贝链接文件的时候实际上我们会拷贝链接文件所指向的原始文件,大大增加了文件的大小` 41 | 5. galen@HD66:/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib$ cd /work/nfs_root/first-fs/ 42 | 6. galen@HD66:/work/nfs_root/first-fs$ ls 43 | bin dev etc lib linuxrc sbin usr // 最小的文件系统 44 | 45 | ## 到目前为止已经制作了一个最小的文件系统,但是我们要把它烧进开发板中使用 46 | ## 就需要制作成镜像文件 47 | 1. galen@HD66:/work/system$ tar jxf yaffs_source_util_larger_small_page_nand.tar.bz2 48 | 2. galen@HD66:/work/system$ cd Development_util_ok/ 49 | 3. galen@HD66:/work/system/Development_util_ok$ cd yaffs2/utils/ 50 | 4. galen@HD66:/work/system/Development_util_ok/yaffs2/utils$ make 51 | * 执行make命令生成mkyaffs2image工具 52 | 5. galen@HD66:/work/system/Development_util_ok/yaffs2/utils$ sudo cp mkyaffs2image /usr/local/bin/ 53 | 6. galen@HD66:/work/system/Development_util_ok/yaffs2/utils$ sudo chmod +x /usr/local/bin/mkyaffs2image 54 | 7. galen@HD66:/work/system/Development_util_ok/yaffs2/utils$ cd /work/nfs_root/ 55 | 8. galen@HD66:/work/nfs_root$ mkyaffs2image 56 | mkyaffs2image: image building tool for YAFFS2 built Dec 13 2017 57 | usage: mkyaffs2image dir image_file [convert] // 用法 58 | dir the directory tree to be converted 59 | image_file the output file to hold the image 60 | 'convert' produce a big-endian image from a little-endian machine 61 | 9. galen@HD66:/work/nfs_root$ mkyaffs2image first-fs first_fs.yaffs2 // 制作镜像 62 | 10. galen@HD66:/work/nfs_root$ ls // first_fs.yaffs2 即为第一个文件系统镜像文件 63 | ``` 64 | drivers_and_test first-fs first_fs.yaffs2 fs_mini_mdev.tar.bz2 fs_mini.tar.bz2 fs_qtopia.tar.bz2 fs_xwindow.tar.bz2 hardware tmp uImage 65 | ``` 66 | 11. 通过 dnw(USB方式)烧写到开发板中 67 | 12. 启动开发板,进入系统,ps 68 | ``` 69 | * ps: can't open '/proc': No file or directory 70 | ``` 71 | * mkdir proc ; ps // `/proc/ : 内核提供的虚拟文件系统` 72 | ``` 73 | ps 74 | PID Uid VSZ Stat Command // 看不到进程 75 | ``` 76 | * mount -t proc none /proc // 即看到相关的进程信息 手工挂载 77 | ``` 78 | 如果不想手动挂载,我们可以把挂载命令(通过脚本)写在配置文件里面 79 | 80 | ::sysinit:/etc/init.d/rcS 81 | 82 | * vi /etc/inittab 83 | * 添加 ::sysinit:/etc/init.d/rcS // 脚本 84 | * :wq! 85 | * mkdir etc/init.d 86 | * vi /etc/init.d/rcS 87 | * 添加: mount -t proc none /proc 88 | * :wq! 89 | * chmod +x /etc init.d/rcS 90 | ``` 91 | * 法二: mount -a // 这个命令就是去读 /etc/fstab , 根据 /etc/fstab的内容来挂载文件内容 92 | ``` 93 | * vi /etc/init.d/rcS 94 | * 添加 mount -a 95 | * :wq! 96 | * vi /etc/fstab // 我们在 busybox的源码(windows下)文件中查找 fstab 97 | * 添加fstab内容 98 | ``` 99 | * fstab的内容 100 | #device mount-point type option-参数 dump fsck order 101 | proc /proc proc defaults 0 0 102 | ``` 103 | ``` 104 | ## fstab的格式说明 105 | ![fstab的格式说明](https://github.com/GalenDeng/Embedded-Linux/blob/master/20.%20%E6%9E%84%E5%BB%BA%E6%A0%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/%E6%9E%84%E5%BB%BA%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B9%8B%E5%90%AF%E5%8A%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/fstab%E7%9A%84%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E.JPG) 106 | * cat /proc/mounts // 查看当前挂载了哪些文件系统 107 | ``` 108 | # cat /proc/mounts 109 | rootfs / rootfs rw 0 0 110 | /dev/root / jffs2 rw 0 0 111 | proc /proc proc rw 0 0 112 | tmpfs /tmp tmpfs rw 0 0 113 | sysfs /sys sysfs rw 0 0 114 | tmpfs /dev tmpfs rw 0 0 115 | devpts /dev/pts devpts rw 0 0 116 | ``` 117 | 13. `udev机制 ===> 自动创建 /dev/目录下的设备节点` 118 | * busybox下面的 mdev 为 udev 的简化版本 // 我们在 busybox的源码(windows下)文件中查找 mdev 119 | ``` 120 | Here's a typical code snippet from the init script: 121 | [1] mount -t sysfs sysfs /sys 122 | [2] echo /sbin/mdev > /proc/sys/kernel/hotplug // 设置内核,当有设备拔插时调用 /sbin/mdev程序 123 | [3] mdev -s // 在 /dev 目录下生成内核支持的所有设备的节点 124 | 125 | Of course, a more "full" setup would entail executing this before the previous 126 | code snippet: 127 | [4] mount -t tmpfs mdev /dev 128 | [5] mkdir /dev/pts 129 | [6] mount -t devpts devpts /dev/pts 130 | 131 | The simple explanation here is that [1] you need to have /sys mounted before 132 | executing mdev. Then you [2] instruct the kernel to execute /bin/mdev whenever 133 | a device is added or removed so that the device node can be created or 134 | destroyed. Then you [3] seed /dev with all the device nodes that were created 135 | while the system was booting. 136 | 137 | For the "full" setup, you want to [4] make sure /dev is a tmpfs filesystem 138 | (assuming you're running out of flash). Then you want to [5] create the 139 | /dev/pts mount point and finally [6] mount the devpts filesystem on it. 140 | ``` 141 | * mkdir sys 142 | * 在 /etc/fstab 添加 143 | ``` 144 | sysfs /sys sysfs defaults 0 0 145 | tmpfs /dev tmpfs defaults 0 0 146 | ``` 147 | * 在 /etc/inittab中添加 148 | ``` 149 | mkdir /dev/pts 150 | mount -t devpts devpts /dev/pts 151 | echo /sbin/mdev > /proc/sys/kernel/hotplug // 热拔插 152 | mdev -s // 一开始就把原先的设备驱动节点都创建出来 153 | ``` 154 | * 使用mkyaffs2image 重新创建 .yaffs2镜像文件,烧写进开发板 155 | * ls dev 就会看到一大堆的设备节点 156 | ``` 157 | console ptyrf tty17 ttyq7 158 | dsp ptys0 tty18 ttyq8 159 | event0 ptys1 tty19 ttyq9 160 | loop5 ptysb tty28 ttyr3 161 | loop6 ptysc tty29 ttyr4 162 | loop7 ptysd tty3 ttyr5 163 | ``` 164 | * `现在开始我们这个最小的文件系统就比较完善了` 165 | * .jffs2 这种文件系统一般用在 Nor flash 上的,当然也可有用在 Nand flash 上 166 | 14. `编译jffs2文件系统` --- `需要zlib压缩包` --- `.jffs2为压缩的文件系统` 167 | * `安装压缩库 --- zlib` 168 | ``` 169 | galen@HD66:~$ cd /work/GUI/xwindow/X/deps/ 170 | galen@HD66:/work/GUI/xwindow/X/deps$ ls 171 | expat-2.0.1.tar.gz freetype-2.3.5.tar.bz2 libpng-1.2.23.tar.bz2 openssl-0.9.8g.tar.gz 172 | fontconfig-2.5.0.tar.gz libdrm-2.3.0.tar.bz2 libxml2-2.6.30.tar.gz zlib-1.2.3.tar.gz 173 | galen@HD66:/work/GUI/xwindow/X/deps$ tar zxf zlib-1.2.3.tar.gz 174 | galen@HD66:/work/GUI/xwindow/X/deps$ cd zlib-1.2.3/ 175 | galen@HD66:/work/GUI/xwindow/X/deps/zlib-1.2.3$ ./configure --shared --prefix=/usr/ // 配置 176 | * --shared : 编译成动态库 177 | * --prefix=/usr/ : 定义安装目录,这里安装在 /usr/ 中 178 | galen@HD66:/work/GUI/xwindow/X/deps/zlib-1.2.3$ sudo make install 179 | * 安装在 PC 机上 , 如果我们使用的是交叉编译工具(如:CROSS_COMPILE= arm-linux-)不能用这个方式,必须指定 180 | * 安装的目录路径 181 | ``` 182 | * `编译` 183 | ``` 184 | galen@HD66:/work/tools$ tar xjf mtd-utils-05.07.23.tar.bz2 185 | galen@HD66:/work/tools$ cd mtd-utils-05.07.23/util/ 186 | galen@HD66:/work/tools/mtd-utils-05.07.23/util$ sudo make install 187 | * 生成了 mkfs.jffs2 188 | -rwxrwxr-x 1 galen galen 171187 Dec 14 11:36 mkfs.jffs2 189 | galen@HD66:/work/nfs_root$ mkfs.jffs2 -n -s 2048 -e 128KiB -d first-fs -o first_fs.jffs2 190 | // 意义 : 把 first-fs目录制作为first_fs.jffs2映像文件 191 | * -n : 表示不要在每个擦除块上都加上清除标志 -s 2048 : 指明一页大小为2048字节, 192 | * -e 128KiB : 指明一个擦除块大小为128KB -d : 表示根文件系统目录 这里的系统为first-fs 193 | * -o : 输出文件 194 | ``` 195 | * `设置bootargs启动参数` 196 | ``` 197 | * set bootargs noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0 rootfstype=jffs2 198 | * save 199 | * boot // 重启 200 | ``` 201 | 202 | ## NFS -- 不用烧写的方式 203 | ## 法一 : 从flash上启动根文件系统,再用命令去挂接 204 | * 无论是yaffs2的文件系统还是jffs2的文件系统,当我们修改程序后,我们都要重新烧写一次文件系统进去开发板里面 205 | * NFS : 网络文件系统,这个文件系统是放在服务器上的 206 | ``` 207 | 内核启动的时候,直接识别出服务器上的这个目录,把它当作我们的根文件系统,我们自然就不用去烧写了 208 | ``` 209 | * ifconfig eth0 192.168.99.135 // 和服务器 192.168.99.140 处于同一个网段下 210 | * ping 192.168.99.140 // 看是否ping通 211 | * 挂载NFS的条件 212 | ``` 213 | a. 服务器允许那个目录可挂接 // 在NFS的配置文件 /etc/exports里面设置 214 | b. 开发板去挂接 215 | ``` 216 | 1. 服务器上执行 sudo vim /etc/exports,添加 /work/nfs_root/first-fs *(rw,sync,no_root_squash) 217 | 2. sudo /etc/init.d/nfs-kernel-server restart 218 | 3. 在服务器上自己挂接一下自己,看是否成功 219 | ``` 220 | sudo mount -t nfs 192.168.99.140:/work/nfs_root/first-fs /mnt 221 | 222 | result : 223 | galen@HD66:/work/nfs_root$ sudo mount -t nfs 192.168.99.140:/work/nfs_root/first-fs /mnt 224 | galen@HD66:/work/nfs_root$ ls -lt /mnt 225 | total 24 226 | drwxrwxr-x 2 galen galen 4096 Dec 13 18:09 lib 227 | drwxrwxr-x 2 galen galen 4096 Dec 13 17:48 etc 228 | drwxrwxr-x 2 galen galen 4096 Dec 13 17:32 dev 229 | drwxrwxr-x 4 galen galen 4096 Dec 13 15:39 usr 230 | drwxrwxr-x 2 galen galen 4096 Dec 13 15:39 bin 231 | lrwxrwxrwx 1 galen galen 11 Dec 13 15:39 linuxrc -> bin/busybox 232 | drwxrwxr-x 2 galen galen 4096 Dec 13 15:39 sbin 233 | galen@HD66:/work/nfs_root$ 234 | // 挂接成功 235 | ``` 236 | 4. 在开发板上挂载 237 | ``` 238 | * # mkdir /mnt 239 | * # mount -t nfs -o nolock,vers=2,rsize=1024,wsize=1024 192.168.99.140:/work/nfs_root/first-fs /mnt 240 | // vers : 使用的NFS版本号 这里必须要添加 241 | ``` 242 | 5. 测试 243 | ``` 244 | * 开发板上 245 | # echo "my name is galen" > /mnt/text.txt 246 | # echo "\nhello everyone!" >> /mnt/text.txt 247 | 248 | * 服务器上 249 | galen@HD66:/work/nfs_root/first-fs$ cat text.txt 250 | my name is galen 251 | galen@HD66:/work/nfs_root/first-fs$ cat text.txt 252 | my name is galen 253 | \nhello everyone! 254 | ``` 255 | ## 法二 : 直接从NFS启动 --- 开发阶段常用这种方法 256 | 1. `NFS启动参数设置` -- 网上搜 root=/dev/nfs 参数 257 | ``` 258 | galen@HD66:/work/nfs_root/first-fs$ cd /work/system/linux-2.6.22.6/ 259 | galen@HD66:/work/system/linux-2.6.22.6$ grep "nfsroot=" * -nR 260 | 得到 :Documentation/nfsroot.txt:52:nfsroot=[:][,] 261 | 此时我们可以直接打开文档查看 : Documentation/nfsroot.txt 262 | 263 | nfsroot=[:][,] // [ ] : 中括号里面的东西可以省略 ; < > : 尖括号里面的东西不可以省略 264 | ``` 265 | * 服务器IP,目录 266 | * 设置自己本地的IP 267 | * `设置启动参数` 268 | * set bootargs noinitrd root=/dev/nfs nfsroot=192.168.99.140:/work/nfs_root/first-fs,rsize=1024,wsize=1024 ip=192.168.99.135:192.168.99.140:192.168.99.4:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0 269 | * save 270 | * printenv 271 | * boot 272 | * 实现 nfs挂载根文件系统 273 | * `该方式的优点:在服务器上编辑好的文件系统,不用每次都烧写在单板里面,再来查看效果` 274 | * 测试 275 | ``` 276 | * 服务器上编译(192.168.99.140) 277 | drwxr-xr-x 2 galen galen 4096 Dec 14 18:34 test 278 | -rw-r--r-- 1 root root 35 Dec 14 17:47 text.txt 279 | drwxrwxr-x 2 galen galen 4096 Dec 13 18:09 lib 280 | drwxrwxr-x 2 galen galen 4096 Dec 13 17:48 etc 281 | drwxrwxr-x 2 galen galen 4096 Dec 13 17:32 dev 282 | drwxrwxr-x 4 galen galen 4096 Dec 13 15:39 usr 283 | drwxrwxr-x 2 galen galen 4096 Dec 13 15:39 bin 284 | lrwxrwxrwx 1 galen galen 11 Dec 13 15:39 linuxrc -> bin/busybox 285 | drwxrwxr-x 2 galen galen 4096 Dec 13 15:39 sbin 286 | galen@HD66:/work/nfs_root/first-fs$ cd test/ 287 | galen@HD66:/work/nfs_root/first-fs/test$ ls -lt 288 | total 4 289 | -rw-r--r-- 1 galen galen 70 Dec 14 18:34 hello.c 290 | galen@HD66:/work/nfs_root/first-fs/test$ chmod +x hello.c 291 | galen@HD66:/work/nfs_root/first-fs/test$ arm-linux-gcc -o hello hello.c 292 | galen@HD66:/work/nfs_root/first-fs/test$ ls 293 | hello hello.c 294 | 295 | * 开发板上执行可执行文件(192.168.99.135) 296 | # ./hello 297 | hello_yours! 298 | ``` 299 | 300 | -------------------------------------------------------------------------------- /21. 字符设备驱动程序/字符设备驱动程序之基本概念.md: -------------------------------------------------------------------------------- 1 | ## 字符设备驱动程序之基本概念 (2017.12.16) 2 | ## 字符设备驱动程序概念 3 | ![字符设备驱动程序概念](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E6%A6%82%E5%BF%B5.JPG) 4 | ## 字符设备驱动程序框架 5 | ![字符设备驱动程序框架](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E6%A1%86%E6%9E%B6.JPG) 6 | ## linux软件系统层次结构 7 | ![linux软件系统层次结构](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/linux%E8%BD%AF%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84.JPG) 8 | 9 | ## 10 | 1. source insignt --- new file --- 新建 first_drv.c 11 | 2. 参考 S3c24xx_leds.c(drivers/char) 12 | ``` 13 | static int s3c24xx_leds_open(struct inode *inode, struct file *file) 14 | 15 | // 通过 file_operations 查看 read write等的定义 16 | struct file_operations { 17 | struct module *owner; 18 | loff_t (*llseek) (struct file *, loff_t, int); 19 | ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 20 | ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 21 | ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); 22 | ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); 23 | int (*readdir) (struct file *, void *, filldir_t); 24 | ``` 25 | 26 | ## 驱动程序框架步骤 -- 以 led 为例 -- 第一个驱动程序 27 | * [first_drv.c源代码](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90%20--open--write/first_drv.c) 28 | * [firstdrvtest.c源代码](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90%20--open--write/firstdrvtest.c) 29 | * [Makefile](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90%20--open--write/Makefile) 30 | 1. 写出 led_open led_read 31 | ``` 32 | static int first_drv_open(struct inode *inode, struct file *file) 33 | { 34 | printk("s3c24xx_leds_open\n") 35 | return 0; 36 | } 37 | 38 | static int first_drv_write(struct file *file, const __user * buf ,size_t count , loff_t * ppos) 39 | { 40 | printk(" first_drv_write\n") 41 | return 0; 42 | } 43 | ``` 44 | 2. 告诉内核 45 | * 定义一个 file_operations 结构体 , 填充 46 | ``` 47 | static struct file_operations first_drv_fops = { 48 | .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 49 | .open = first_drv_open, 50 | .write = first_drv_write, 51 | }; 52 | ``` 53 | * 把这个结构体告诉内核 54 | ``` 55 | register_chrdev("major", first_drv, &first_drv_fops); 56 | // major : 主设备号 first_dev : 名字(可以随意命名) &first_drv_fops : 告诉内核的结构体 57 | ``` 58 | 3. 谁来驱动 register_chrdev --- 这个步骤过程称为驱动的入口函数 59 | ``` 60 | int first_drv_init(void) // 驱动的入口函数 61 | { 62 | register_chrdev("major", first_drv, &first_drv_fops); 63 | return 0; 64 | } 65 | ``` 66 | 4. 修饰,以便内核分辨出不同的驱动入口函数 // 所谓修饰,就是用宏来定义一个结构体 67 | * 对于驱动程序来说,我们是字符设备 , 首字符为 c 68 | ``` 69 | crw-rw---- 1 0 0 3, 173 Jan 1 00:00 ttyzd // 3 为主设备号 173 为次设备号 70 | ``` 71 | 5. 有入口函数就有出口函数,并进行修饰 72 | ``` 73 | // 卸载驱动 74 | void first_drv_exit(void) 75 | { 76 | unregister_chrdev(111, "first_drv"); 77 | } 78 | 79 | module_exit(first_drv_exit) // 修饰卸载函数 80 | ``` 81 | 6. 再添加头文件 82 | ``` 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | ``` 92 | 7. Makefile的创建 93 | ``` 94 | // 编译一个驱动程序依赖于一个内核目录 这个内核需要事先经过编译并通过 95 | KERN_DIR = /work/system/linux-2.6.22.6 // 内核目录 96 | 97 | all: 98 | make -C $(KERN_DIR) M=`pwd` modules 99 | // -C + 目录 make -C 目录 : 作用就是转到这个目录里面,用这个目录名的Makefile来进行编译 100 | // M=`pwd` : 表示当前的目录是什么 101 | // modules : 目标 这里是模组 102 | 103 | clean: 104 | make -C $(KERN_DIR) M=`pwd` modules clean 105 | rm -rf modules.order 106 | 107 | obj-m += first_drv.o // 这里是把 first_drv 编译成 可执行的模块 (.ko文件) 108 | ``` 109 | 8. make 110 | ``` 111 | galen@HD66:/work/nfs_root/first-fs/first_drv$ make 112 | make -C /work/system/linux-2.6.22.6 M=`pwd` modules 113 | make[1]: Entering directory `/work/system/linux-2.6.22.6' 114 | CC [M] /work/nfs_root/first-fs/first_drv/first_drv.o 115 | /work/nfs_root/first-fs/first_drv/first_drv.c:17: warning: type defaults to `int' in declaration of `buf' 116 | /work/nfs_root/first-fs/first_drv/first_drv.c:26: warning: initialization from incompatible pointer type 117 | Building modules, stage 2. 118 | MODPOST 1 modules 119 | CC /work/nfs_root/first-fs/first_drv/first_drv.mod.o 120 | LD [M] /work/nfs_root/first-fs/first_drv/first_drv.ko 121 | make[1]: Leaving directory `/work/system/linux-2.6.22.6' 122 | ``` 123 | 9. 开发板上 `cat /proc/devices ` 查看内核目前支持的设备 124 | ``` 125 | # cat /proc/devices 126 | Character devices: // 支持的字符设备 127 | 1 mem // 1 : 表示主设备号 ; 第二列是它的名字 128 | 2 pty 129 | 3 ttyp 130 | 4 /dev/vc/0 131 | 4 tty 132 | 4 ttyS 133 | 5 /dev/tty 134 | 5 /dev/console 135 | 5 /dev/ptmx 136 | 6 lp 137 | 7 vcs 138 | 10 misc 139 | 13 input 140 | 14 sound 141 | 29 fb 142 | 90 mtd 143 | 99 ppdev 144 | 111 first_drv 145 | 116 alsa 146 | 128 ptm 147 | 136 pts 148 | 180 usb 149 | 189 usb_device 150 | 204 s3c2410_serial 151 | 253 usb_endpoint 152 | 254 rtc 153 | 154 | Block devices: // 支持的块设备 155 | 1 ramdisk 156 | 7 loop 157 | 8 sd 158 | 31 mtdblock 159 | 65 sd 160 | 179 mmc 161 | ``` 162 | 10. 开发板上 `insmod first_drv.ko` 163 | ``` 164 | first_drv: module license 'unspecified' taints kernel. // 这个警告信息先不管 165 | ``` 166 | 11. 开发板上 `cat /proc/devices` 167 | ``` 168 | 111 first_drv // 看到主设备号: 111 表示设备已经注册进来了 169 | ``` 170 | 12. 服务器上新建一个测试程序文件 `firstdrvtest.c` 171 | * galen@HD66:/work/nfs_root/first-fs/first_drv$ vim firstdrvtest.c 172 | ``` 173 | #include 174 | #include 175 | #include 176 | #include 177 | 178 | int main(int argc,char **argv) 179 | { 180 | int fd; 181 | int val = 1; 182 | fd =open("/dev/xxx",O_RDWR); // 名字不重要 183 | if (fd < 0) 184 | printf("can't open!\n"); 185 | write(fd,&val,4); 186 | return 0; 187 | } 188 | ``` 189 | 13. 开发板上执行 190 | ``` 191 | # ./firstdrvtest 192 | can't open! // 表示不存在该设备这里指的是 /dev/xxx 此时要在开发板上创建设备节点 193 | 194 | # mknod /dev/xxx c 111 0 // 创建 /dev/xxx 设备节点 0: 系统自动给我们分配次设备号 195 | ``` 196 | * galen@HD66:/work/nfs_root/first-fs/first_drv$ arm-linux-gcc -o firstdrvtest firstdrvtest.c 197 | * # ./firstdrvtest 198 | first_drv_open 199 | first_drv_write //执行成功 200 | 14. 主设备号的定义 (如: 111) 201 | * 通过在开发板上 cat /proc/devices 查看空缺哪些主设备号,然后我们就可以选用这些空缺的主设备号做处理开发 202 | * 或者直接写 0 : 系统会自动给我们分配主设备号 ,改法如下 203 | ``` 204 | int major; 205 | int first_drv_init(void) // 驱动的入口函数 206 | { 207 | major = register_chrdev(0, first_drv, &first_drv_fops); 208 | return 0; 209 | } 210 | 211 | void first_drv_exit(void) 212 | { 213 | unregister_chrdev(major, "first_drv"); 214 | } 215 | ``` 216 | * # lsmod // 查看开发板上的挂载的module 217 | ``` 218 | Module Size Used by Tainted: P 219 | first_drv 1728 0 220 | ``` 221 | * # rmmod first_drv // 卸载module 222 | * 服务器上修改成自动分配主设备的形式, make clean ; make ; 223 | * 开发板上 insmod first_drv.ko ; lsmod ; ./firstdrvtest 224 | ``` 225 | can't open! 226 | ``` 227 | * ls -l /dev/xxx 228 | ``` 229 | # ls -l /dev/xxx 230 | crw-r--r-- 1 0 0 111, 0 Jan 1 02:10 /dev/xxx 231 | // 因为这里的主设备号还是 111 , 但我们现在安装的驱动程序(module)的主设备号为 252 232 | ``` 233 | * 执行以下的操作 234 | ``` 235 | # rm /dev/xxx // 删除该设备 236 | # mknod /dev/xxx c 252 0 // 重新新创建设备 237 | # ./firstdrvtest 238 | first_drv_open 239 | first_drv_write 240 | ``` 241 | ## 总结:第一个驱动程序--open--write驱动框架分析过程 242 | ![第一个驱动程序--open--write驱动框架分析过程](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F--open--write%E9%A9%B1%E5%8A%A8%E6%A1%86%E6%9E%B6%E5%88%86%E6%9E%90%E8%BF%87%E7%A8%8B.JPG) 243 | 244 | 245 | * insmod xxx.ko : install module xxx.ko 安装xxx.ko模组(驱动) 246 | * lsmod xxx.lo : list module xxx.ko 查看xxx.ko模组(驱动) 247 | * rmmod xxx.ko : remove module xxx.ko 卸载xxx.ko模组(驱动) 248 | ## 应用程序的open如何实现内核的open的操作的过程解析 249 | ![应用程序的open如何实现内核的open的操作的过程解析](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%9A%84open%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E5%86%85%E6%A0%B8%E7%9A%84open%E7%9A%84%E6%93%8D%E4%BD%9C%E7%9A%84%E8%BF%87%E7%A8%8B%E8%A7%A3%E6%9E%90.JPG) 250 | 251 | ## 驱动与应用 252 | ![驱动与应用](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E5%9B%BE%E7%89%87%E7%AC%94%E8%AE%B0/%E9%A9%B1%E5%8A%A8%E4%B8%8E%E5%BA%94%E7%94%A8.JPG) 253 | * 当我们注册一个设备(驱动程序)的时候,它会在 /sys 目录下生成一些信息 254 | * 而 mdev 会根据/sys系统信息自动创建设备节点 255 | * 所以我们若能在驱动程序里面提供系统信息,则mdev就会帮我们自动创建设备节点 256 | ``` 257 | # cd /sys 258 | # ls 259 | block class firmware kernel power 260 | bus devices fs module 261 | # cd devices/ 262 | # ls 263 | platform system 264 | ``` 265 | 266 | ## 第一个驱动程序中添加系统信息,以便mdev自动生成设备节点 267 | * 添加内容 --- first_drv.c 268 | ``` 269 | #include 270 | static struct class *firstdrv_class; // 类 271 | static struct class_device *firstdrv_class_devs; // 类里面再建一个设备 272 | 273 | int major; 274 | // 注册: major :主设备号 first_dev :名字(可以随便起 ) file_operations : 结构 ,把这个 275 | // 结构告诉内核 276 | int first_drv_init(void) 277 | { 278 | major = register_chrdev(0, "first_drv", &first_drv_fops); 279 | 280 | firstdrv_class = class_create(THIS_MODULE,"firstdrv"); // 创建一个类实例 281 | if (IS_ERR(firstdrv_class)) 282 | return PTR_ERR(firstdrv_class); 283 | 284 | // 类下创建一个设备 285 | firstdrv_class_devs = class_device_create(firstdrv_class, NULL, MKDEV(major,0), NULL, "xyz") 286 | // major;主设备号 0:次设备(系统之后会自动生成次设备号) "xyz" : 设备名字 287 | if (unlikely(IS_ERR(firstdrv_class_devs))) 288 | return PTR_ERR(firstdrv_class_devs); 289 | return 0; 290 | } 291 | // firstdrv 这个类下创建 xyz 这个设备 292 | // 创建 /*/dev/xyz 这个设备节点 293 | void first_drv_exit(void) 294 | { 295 | unregister_chrdev(major, "first_drv"); 296 | 297 | class_device_unregister(firstdrv_class_devs); //删除设备 298 | class_destroy(firstdrv_class ); // 删除类 299 | } 300 | 301 | MODULE_LICENSE("GPL"); // 方便查找到class_create这些 报没有license的问题 302 | ``` 303 | * make 304 | * 开发板上 rmmod first_drv ; insmod /first_drv/first_drv.ko ; lsmod ; 305 | * 开发板上 ls -l /dev/xyz 306 | ``` 307 | # ls -l /dev/xyz 308 | crw-rw---- 1 0 0 252, 0 Jan 1 00:17 /dev/xyz 309 | // 可看出 mdev 根据系统信息创建了 /dev/xyz 的设备节点 310 | ``` 311 | * 我们可以从 /sys/class 这个目录下看到各种类 312 | ``` 313 | # # cd /sys/class 314 | # cd /sys/class/ 315 | # cd firstdrv/ 316 | # ls 317 | xyz 318 | ``` 319 | ``` 320 | # cd xyz/ 321 | # ls 322 | dev subsystem uevent 323 | # cat dev 324 | 252:0 // 主设备 252 次设备 0 325 | ``` 326 | * 设备改变后,实时更改系统信息 327 | ``` 328 | # rmmod first_drv 329 | # ls /dev/xyz 330 | ls: /dev/xyz: No such file or directory 331 | # insmod /first_drv/first_drv.ko 332 | # ls /dev/xyz 333 | /dev/xyz 334 | ``` 335 | * 此时修改测试程序 firstdrvtest.c 336 | ``` 337 | #include 338 | #include 339 | #include 340 | #include 341 | 342 | int main(int argc,char **argv) 343 | { 344 | int fd; 345 | int val = 1; 346 | fd =open("/dev/xyz",O_RDWR); // 修改为我们要测试的设备 347 | if (fd < 0) 348 | printf("can't open!\n"); 349 | write(fd,&val,4); 350 | return 0; 351 | } 352 | ``` 353 | ## 第二个驱动程序例子 -- mdev检测系统信息自动创建硬件设备 354 | * [first_drv.c源代码](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E7%AC%AC%E4%BA%8C%E4%B8%AA%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90%20--mdev%E6%A3%80%E6%B5%8B%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E7%A1%AC%E4%BB%B6%E8%AE%BE%E5%A4%87/first_drv.c) 355 | * [firstdrvtest.c源代码](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E7%AC%AC%E4%BA%8C%E4%B8%AA%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90%20--mdev%E6%A3%80%E6%B5%8B%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E7%A1%AC%E4%BB%B6%E8%AE%BE%E5%A4%87/firstdrvtest.c) 356 | * [Makefile](https://github.com/GalenDeng/Embedded-Linux/blob/master/21.%20%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/%E7%AC%AC%E4%BA%8C%E4%B8%AA%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E4%BE%8B%E5%AD%90%20--mdev%E6%A3%80%E6%B5%8B%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E7%A1%AC%E4%BB%B6%E8%AE%BE%E5%A4%87/Makefile) 357 | * insmod 加载模块 --- init函数被调用 --- 用来向内核注册驱动程序 358 | * rmmod 卸载模块 --- exit函数被调用 --- 359 | ``` 360 | module_init(xxx); 361 | module_exit(xxx); 362 | ``` -------------------------------------------------------------------------------- /18. 移植u-boot/u-boot分析之编译体验.md: -------------------------------------------------------------------------------- 1 | ## u-boot分析之编译体验 (2017.12.08) 2 | * S3C2410/S3C2440的CPU为ARM920T 3 | * SOC : system on chip 4 | * u-boot : Universal Boot Loader 通用Bootloader 5 | ## u-boot的目录结构说明 6 | ![u-boot的目录结构说明](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E.JPG) 7 | ## U-Boot顶层目录的层次结构 8 | ![U-Boot顶层目录的层次结构](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/U-Boot%E9%A1%B6%E5%B1%82%E7%9B%AE%E5%BD%95%E7%9A%84%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84.JPG) 9 | ## bootloader与内核的交互方式 10 | ![bootloader与内核的交互方式](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/bootloader%E4%B8%8E%E5%86%85%E6%A0%B8%E7%9A%84%E4%BA%A4%E4%BA%92%E6%96%B9%E5%BC%8F.jpg) 11 | 12 | ## windows和linux系统启动过程的对比 13 | ![windows和linux系统启动过程的对比](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/windows%E5%92%8Clinux%E7%B3%BB%E7%BB%9F%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B%E7%9A%84%E5%AF%B9%E6%AF%94.JPG) 14 | 1. `打补丁文件解释(.patch)` 15 | ``` 16 | diff -urN u-boot-1.1.6/common/cmd_load.c u-boot-1.1.6_jz2440/common/cmd_load.c 17 | --- u-boot-1.1.6/common/cmd_load.c 2006-11-02 22:15:01.000000000 +0800 18 | +++ u-boot-1.1.6_jz2440/common/cmd_load.c 2010-11-26 12:54:38.142063808 +0800 19 | @@ -34,6 +34,8 @@ //原来 :从34行开始到之后的6行 --- 现在 :从34行开始到之后的8行 20 | DECLARE_GLOBAL_DATA_PTR; // 34--old // 34--new 21 | // 35--old // 35--new 22 | #if (CONFIG_COMMANDS & CFG_CMD_LOADB) // 36--old // 36--new 23 | +/* support xmodem, www.100ask.net */ // 37--new 24 | +static ulong load_serial_xmodem (ulong offset); // 38--new 25 | static ulong load_serial_ymodem (ulong offset); // 37--old // 39--new 26 | #endif // 38--old // 41--new 27 | // 40--old // 42--new 28 | @@ -53,355 +55,355 @@ 29 | ``` 30 | ## u-boot编译过程 31 | ![u-boot编译过程](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B.JPG) 32 | ## u-boot 为 bootloader的其中一种,其终极目的是启动内核 33 | ## 成功启动内核条件1 34 | ![u-boot要成功启动内核需要实现的功能列表](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E8%A6%81%E6%88%90%E5%8A%9F%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0%E7%9A%84%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8.JPG) 35 | ## 成功启动内核条件2 36 | ![u-boot要成功启动内核需要实现的功能列表](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/u-boot%E8%A6%81%E6%88%90%E5%8A%9F%E5%90%AF%E5%8A%A8%E5%86%85%E6%A0%B8%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0%E7%9A%84%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A82.JPG) 37 | 38 | ## `分析u-boot的目录结构情况以及怎样链接的最快捷的方法是---分析 Makefile` 39 | 1. 以 100ask24x0_config为例说明 40 | * make 100ask24x0_config : 配置 41 | 2. 打开 Makefile , 搜索 100ask24x0_config,得到以下情况 42 | ``` 43 | 100ask24x0_config : unconfig 44 | @$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0 45 | ``` 46 | 3. 搜索 MKCONFIG,得到 47 | * MKCONFIG := $(SRCTREE)/mkconfig 48 | //SRCTREE : source tree : 源文件目录下/源码树下 49 | 4. 查看一下 50 | ``` 51 | galen@HD66:/work/system/u-boot-1.1.6$ ls mkconfig 52 | mkconfig //确实存在该文件 53 | ``` 54 | 5. $(@:_config=) 55 | * @ --- 表示 100ask24x0_config 56 | * _config= //为空 , 表示把 100ask24x0_config 中的 _config 去掉 57 | * $(@:_config=) 等价于 100ask24x0 58 | 6. @$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0 等价于 59 | * mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0 60 | 7. `mkconfig源码分析`---`配置过程` 61 | ``` 62 | APPEND=no # Default: Create new config file 63 | BOARD_NAME="" # Name to print in make output 64 | 65 | while [ $# -gt 0 ] ; do // $# : 表示传入参数的个数 -gt : 大于 --- 参数个数大于0就执行 66 | case "$1" in // $1 : 表示第二个参数 67 | --) shift ; break ;; 68 | -a) shift ; APPEND=yes ;; 69 | -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;; 70 | *) break ;; 71 | esac 72 | done 73 | 74 | [ "${BOARD_NAME}" ] || BOARD_NAME="$1" // 如果 BOARD_NAME 定义了,就不执行 BOARD_NAME="$1" 75 | // 如果 BOARD_NAME 没定义(或为空),就执行 BOARD_NAME="$1 76 | // 该句等于 :BOARD_NAME=100ask24x0 77 | [ $# -lt 4 ] && exit 1 // 小于4会退出 78 | [ $# -gt 6 ] && exit 1 // 大于6会退出 79 | 80 | echo "Configuring for ${BOARD_NAME} board..." //程序能执行到此处,就会打印该信息到标准输出里(tty) 81 | 82 | # 83 | # Create link to architecture specific headers 84 | # 85 | if [ "$SRCTREE" != "$OBJTREE" ] ; then // Makefile中查找到 SRCTREE := $(CURDIR) 86 | // OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) 如果定义了 BUILD_DIR,则 OBJTREE=$(BUILD_DIR) 87 | // 否则 OBJTREE=$(CURDIR) 88 | // Makefile中查看 BUILD_DIR := $(O) 没定义 89 | mkdir -p ${OBJTREE}/include 90 | mkdir -p ${OBJTREE}/include2 91 | cd ${OBJTREE}/include2 92 | rm -f asm 93 | ln -s ${SRCTREE}/include/asm-$2 asm 94 | LNPREFIX="../../include2/asm/" 95 | cd ../include 96 | rm -rf asm-$2 97 | rm -f asm 98 | mkdir asm-$2 99 | ln -s asm-$2 asm 100 | else 101 | cd ./include 102 | rm -f asm 103 | ln -s asm-$2 asm // 软链接 实际为:ln -s asm-arm asm 即asm指向asm-arm 104 | // galen@HD66:/work/system/u-boot-1.1.6/include$ ls -l asm 105 | // lrwxrwxrwx 1 galen galen 7 Dec 8 05:40 asm -> asm-arm 这样做为了方便生成文件 #include 代替 106 | // 临时生成的各种架构的头文件 107 | //galen@HD66:/work/system/u-boot-1.1.6/include$ ls asm 108 | //arch arch-arm925t arch-imx arch-omap arch-s3c44b0 bitops.h global_data.h 109 | 110 | 111 | fi 112 | 113 | rm -f asm-$2/arch // rm -f asm-arm/arch 114 | 115 | if [ -z "$6" -o "$6" = "NULL" ] ; then // -z : 字符串为0则为真 -o : 或者 第七个参数为空或者为NULL的话就执行 then 的操作 116 | ln -s ${LNPREFIX}arch-$3 asm-$2/arch 117 | else 118 | ln -s ${LNPREFIX}arch-$6 asm-$2/arch // LNPREFIX 没定义,为空 源码为:ln -s arch-s3c24x0 asm-arm/arch 119 | // galen@HD66:/work/system/u-boot-1.1.6/include$ ls -l asm-arm/arch 120 | // lrwxrwxrwx 1 galen galen 12 Dec 8 05:40 asm-arm/arch -> arch-s3c24x0 121 | fi 122 | 123 | if [ "$2" = "arm" ] ; then 124 | rm -f asm-$2/proc 125 | ln -s ${LNPREFIX}proc-armv asm-$2/proc //建立链接文件 ln -s proc-armv asm-arm/proc 126 | fi 127 | 128 | # 129 | # Create include file for Make //生成一个配置文件 130 | # 131 | echo "ARCH = $2" > config.mk // 新建(或者是覆盖一个已有的config.md文件)一个文件 config.mk 132 | echo "CPU = $3" >> config.mk // 追加 CPU = $3 到 config.mk文件中 133 | echo "BOARD = $4" >> config.mk // 追加 BOARD = $4 到 config.mk文件中 134 | 135 | /* 136 | config.mk 里面的内容为: 137 | ARCH = arm 138 | CPU = arm920t 139 | BOARD = 100ask24x0 140 | */ 141 | 142 | [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk // 如果第6个参数存在,并且该参数不等于 // NULL,再追加内容 VENDOR =NULL 143 | 144 | [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk // 如果第6个参数存在,并且该参数不等于 145 | // NULL,再追加内容 SOC =s3c24x0 146 | /* 147 | galen@HD66:/work/system/u-boot-1.1.6/include$ cat config.mk 148 | ARCH = arm 149 | CPU = arm920t 150 | BOARD = 100ask24x0 151 | SOC = s3c24x0 152 | */ 153 | # 154 | # Create board specific header file // 创建单板相关的头文件 155 | # 156 | if [ "$APPEND" = "yes" ] # Append to existing config file // Makefile中查看 APPEND=no 157 | then 158 | echo >> config.h 159 | else 160 | > config.h # Create new config file // > : 表示新建文件 161 | fi 162 | echo "/* Automatically generated - do not edit */" >>config.h 163 | echo "#include " >>config.h // #include 164 | 165 | /* 166 | galen@HD66:/work/system/u-boot-1.1.6/include$ cat config.h 167 | /* Automatically generated - do not edit */ 168 | #include 169 | 170 | */ 171 | 172 | exit 0 173 | ``` 174 | ## $0 $1 $2 ... 175 | ``` 176 | mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0 177 | $0 $1 $2 $3 $4 $5 $6 178 | ``` 179 | ## 总结 180 | * 配置命令 make 100ask24x0_config 实际的作用是 ./mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0 181 | 8. `分析编译过程 --- make` 182 | ``` 183 | ######################################################################### 184 | # U-Boot objects....order is important (i.e. start must be first) 185 | 186 | OBJS = cpu/$(CPU)/start.o // echo "CPU = $3" >> config.mk $3 : arm920t 187 | ifeq ($(CPU),i386) 188 | OBJS += cpu/$(CPU)/start16.o 189 | OBJS += cpu/$(CPU)/reset.o 190 | endif 191 | ``` 192 | 193 | ``` 194 | LIBS = lib_generic/libgeneric.a 195 | LIBS += board/$(BOARDDIR)/lib$(BOARD).a // $(BOARDDIR) = 100ask24x0 196 | // 所以这里为:LIBS += board/100ask24x0/lib100ask24x0.a 197 | LIBS += cpu/$(CPU)/lib$(CPU).a // LIBS += cpu/arm920t/libarm920t.a 198 | 199 | LIBS += net/libnet.a // LIBS的作用 : 把net目录下的所有文件编译好了之后打包成libnet.a这样的库文件 200 | ``` 201 | * make // 如果我们不指定make的目标的话,它默认是生成Makefile中的第一个目标 202 | 203 | ``` 204 | ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) 205 | 206 | all: $(ALL) // all命令依赖于 $(ALL) 207 | 208 | $(obj)u-boot.hex: $(obj)u-boot 209 | $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ 210 | 211 | $(obj)u-boot.srec: $(obj)u-boot 212 | $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ 213 | 214 | $(obj)u-boot.bin: $(obj)u-boot // u-boot.bin(二进制可执行文件) 依赖于 u-boot(elf可执行文件) 215 | $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ 216 | 217 | $(obj)u-boot.img: $(obj)u-boot.bin 218 | ./tools/mkimage -A $(ARCH) -T firmware -C none \ 219 | -a $(TEXT_BASE) -e 0 \ 220 | -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \ 221 | sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \ 222 | -d $< $@ 223 | 224 | $(obj)u-boot.dis: $(obj)u-boot 225 | $(OBJDUMP) -d $< > $@ 226 | 227 | // (obj)u-boot的生成这部分可以通过执行make来查看具体的链接内容 228 | 229 | /* 230 | UNDEF_SYM=`arm-linux-objdump -x lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\ 231 | //进入目录 232 | cd /work/system/u-boot-1.1.6 && 233 | //链接脚本 : u-boot.lds 234 | arm-linux-ld -Bstatic -T /work/system/u-boot-1.1.6/board/100ask24x0/u-boot.lds -Ttext 0x33F80000 235 | 236 | $UNDEF_SYM cpu/arm920t/start.o \ 237 | --start-group 238 | // 原材料 239 | lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a --end-group -L /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5 -lgcc \ 240 | -Map u-boot.map -o u-boot 241 | 242 | */ 243 | 244 | $(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT) // SUBDIRS = tools \ 245 | UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\ 246 | cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ 247 | // LNDIR : 链接目录 LD :链接是否存在 LDFLAGS :链接参数 __OBJS : 所有的 .o文件 248 | --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ // __LIBS :所有的库 249 | -Map u-boot.map -o u-boot 250 | 251 | $(OBJS): 252 | echo $(OBJS) 253 | $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@)) 254 | 255 | $(LIBS): 256 | $(MAKE) -C $(dir $(subst $(obj),,$@) 257 | ``` 258 | ## 链接脚本说明 259 | ``` 260 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 261 | /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ 262 | OUTPUT_ARCH(arm) 263 | ENTRY(_start) 264 | SECTIONS 265 | { 266 | . = 0x00000000; // 当前地址为 0x00000000 267 | // 因为链接命令中 268 | // arm-linux-ld -Bstatic -T /work/system/u-boot-1.1.6/board/100ask24x0/u-boot.lds -Ttext 0x33F80000 269 | // 所以 后面的代码的地址从 0x00000000 + 0x33F80000 = 0x33F80000开始排放 270 | 271 | . = ALIGN(4); // 表示起始运行地址为4字节对齐 272 | .text : // 定义了一个名为 “.text” 的代码段,内容为 { }的内容 273 | { 274 | cpu/arm920t/start.o (.text) // 先排放 cpu/arm920t/start.o 的 代码段 (.text) 275 | // 因为 cpu/arm920t/start.o 放在了程序的最前面,所以u-boot的入口点在 cpu/arm920t/start.S 276 | board/100ask24x0/boot_init.o (.text) // 后排放 board/100ask24x0/boot_init.o 的 代码段 (.text) 277 | *(.text) // 其他文件的所有代码段 278 | } 279 | 280 | . = ALIGN(4); // 表示起始运行地址为4字节对齐 281 | .rodata : { *(.rodata) } // 定义了一个名为 “.rodata”的段,内容为所有文件的只读数据段 282 | 283 | . = ALIGN(4); // 表示起始运行地址为4字节对齐 284 | .data : { *(.data) } // 定义了一个名为 “.data”的段,内容为所有文件的数据段 285 | 286 | . = ALIGN(4); 287 | .got : { *(.got) } 288 | 289 | . = .; 290 | __u_boot_cmd_start = .; 291 | .u_boot_cmd : { *(.u_boot_cmd) } 292 | __u_boot_cmd_end = .; 293 | 294 | . = ALIGN(4); 295 | __bss_start = .; 296 | .bss : { *(.bss) } 297 | _end = .; 298 | } 299 | ``` 300 | 301 | ``` 302 | galen@HD66:/work/system/u-boot-1.1.6$ grep "33F80000" * -nR 303 | board/smdk2410/config.mk:25:TEXT_BASE = 0x33F80000 304 | board/100ask24x0/config.mk:25:TEXT_BASE = 0x33F80000 305 | board/mpl/vcma9/config.mk:24:TEXT_BASE = 0x33F80000 306 | board/sbc2410x/config.mk:23:TEXT_BASE = 0x33F80000 307 | u-boot.srec:2:S31533F80000170000EA14F09FE514F09FE514F09FE526 308 | u-boot.srec:12195:S31533FAF9F0E4F9FA33F8000000626F6F746172677371 309 | u-boot.srec:12400:S70533F80000CF 310 | ``` 311 | ``` 312 | config.mk:189:LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS) //定义了LDFLAGS 313 | //这句跟 314 | //arm-linux-ld -Bstatic -T /work/system/u-boot-1.1.6/board/100ask24x0/u-boot.lds -Ttext 0x33F80000 315 | // 吻合起来 316 | board/100ask24x0/config.mk:25:TEXT_BASE = 0x33F80000 // TEXT_BASE 的定义位置 317 | ``` 318 | ## Makefile分析步骤 319 | ![Makefile分析步骤](https://github.com/GalenDeng/Embedded-Linux/blob/master/18.%20%E7%A7%BB%E6%A4%8Du-boot/Makefile%E5%88%86%E6%9E%90%E6%AD%A5%E9%AA%A4.JPG) --------------------------------------------------------------------------------