回 顾.

Slides:



Advertisements
Similar presentations
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Advertisements

Linux 系统. 操作系统发展需求 1 没有操作系统 2 简单批处理操作系统 3 多道程序设计的批处理 4 多道程序设计的分时操作系统 5 多处理机并行系统 6 网络操作系统 7 分布式操作系统.
嵌入式系统简介 Introduction to Embedded System
课前回顾.
嵌入式系统与结构 —基于ARM的体系结构和应用开发
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
实用操作系统概念 张惠娟 副教授 1.
基于ARM和linux的开发 华中科技大学 武汉创维特 2017/3/20.
基于解释性语言的手机跨平台架构 Sloan Yi. Qt MTK.
Oracle数据库 Oracle 子程序.
在PHP和MYSQL中实现完美的中文显示
J2EE与中间件技术 ——Lab.
Linux Further.
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
第一章 嵌入式系统开发基础 本章介绍了嵌入式系统开发的基础知识,从嵌入式计算机的历史由来、嵌入式系统的定义、嵌入式系统的基本特点、嵌入式系统的分类及应用、嵌入式系统软硬件各部分组成、嵌入式系统的开发流程、嵌入式技术的发展趋势等方面进行了介绍,涉及到嵌入式系统开发的基本内容,使读者系统地建立起的嵌入式系统整体概念。
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
Hadoop I/O By ShiChaojie.
Bootloader技术分析.
嵌入式系统课程简介 宋健建 南京大学软件学院 2004/02/10.
第二讲 搭建Java Web开发环境 主讲人:孙娜
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
大学计算机基础 典型案例之一 构建FPT服务器.
SVN服务器的搭建(Windows) 柳峰
ARDUINO+BLUETOOTH Arduino实现蓝牙数据传输.
在專用的嵌入式板子運行 GNU/Linux 系統已經變得越來越流行。一個嵌入式 Linux 系統從軟體的角度看通常可以分為四個層次:
网络常用常用命令 课件制作人:谢希仁.
第11章:一些著名开源软件介绍 第12章:服务安装和配置 本章教学目标: 了解当前一些应用最广泛的开源软件项目 搭建一个网站服务器
大数据管理技术 --NoSQL数据库 HBase 陈 辉 大数据分析技术.
DM81X 视频采集处理 ——简单采集显示例程讲解 广州创龙电子科技有限公司
SPI驱动 广州创龙电子科技有限公司 Guangzhou Tronlong Electronic Technology Co., Ltd.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Windows网络操作系统管理 ——Windows Server 2008 R2.
嵌入式系统的Boot Loader技术 陈文智 浙江大学计算机学院 2009年5月.
逆向工程-汇编语言
《手把手教你学STM32》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司 淘宝店铺:
如何生成设备节点 广州创龙电子科技有限公司
CPU结构和功能.
中国科学技术大学计算机系 陈香兰(0551- ) Spring 2009
Windows 7 的系统设置.
三:基于Eclipse的集成开发环境搭建与使用
Unit 11.Operating System 11.1 What’s OS 11.2 Related Courses
程序设计工具实习 Software Program Tool
(第2版).
第二章 登录UNIX操作系统.
内容摘要 ■ 课程概述 ■ 教学安排 ■ 什么是操作系统? ■ 为什么学习操作系统? ■ 如何学习操作系统? ■ 操作系统实例
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
微机系统的组成.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
第四章 团队音乐会序幕: 团队协作平台的快速创建
嵌入式Linux开发流程 成都研究所操作系统团队.
VisComposer 2019/4/17.
Platform Builder使用介绍 WINCE系统应用开发流程说明 ACTION RDC 杨 涛 2005.Dec.3th
实验七 安全FTP服务器实验 2019/4/28.
计算机网络与网页制作 Chapter 07:Dreamweaver CS5入门
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
iSIGHT 基本培训 使用 Excel的栅栏问题
Python 环境搭建 基于Anaconda和VSCode.
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
Google的云计算 分布式锁服务Chubby.
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 UNIX文件系统.
FVX1100介绍 法视特(上海)图像科技有限公司 施 俊.
DSP技术与应用 电子与信息技术系.
一个实时嵌入式操作系统移植问题研究 报告人:荣峰华.
Presentation transcript:

回 顾

第四章 嵌入式操作系统开发 4.1 Intel基于PCA架构的嵌入式系统平台 4.2 为什么要用RTOS 4.3 操作系统的内核编译 4.4 什么是BootLoader 4.5 嵌入式操作系统的驱动开发 4.6 嵌入式操作系统的远程调试

4.1 Intel基于PCA架构的嵌入式系统平台

Intel 的PCA Intel 个人互联网用户架构(Personal Internet Client Architecture) 2000年9月推出,面向无线互联网的嵌入式系统架构。 开放式平台架构 应用子系统 通信子系统 内存子系统 各个子系统通过开发式接口相互隔离

Standard Bus Interface Intel PCA 构筑模块 Intel® PCA 软件 计算 / 应用 Intel® XScale™ Microarchitecture and SA-1110 w/ Intel® Integrated Performance Primitives Memory Intel® Flash Software Standard Bus Interface 通信 Intel® baseband chipsets with Intel® Micro Signal Architecture w/Intel® Integrated Performance Primitives Intel® Logic Process Volume Manufacturing Package Technology Wireless Competency Centers Intel® Flash Intel® IPPs XScale Core MSA Intel Value Proposition

Intel PCA 分层软件结构 纵向的, 任务导向的设计 模块化结构 开放接口 可扩展性 . . . . . . Platform Management APIs Mobile Applications Applications, Libraries, e.g., Intel® IPPs System Process 纵向的, 任务导向的设计 模块化结构 开放接口 可扩展性 Telephony Data Resource Authentication SIM Manager DSP Abstraction Other Bluetooth* Power Manager Services Wireless Modem Protocols Operating System(s) & OS APIs Calibration OS Message Driver 1 Services Passing Stack 1 Test Diag Download Driver 2 Stack 2 . . . . . . Memory Stack n Driver n System Manager Hardware Software

PCA应用子系统的开放式软件框架 1. 平台服务: 2. 操作系统: 3. 中间件: 4. 固有运行时程序库: 5. 用户应用: 多媒体服务 安全服务 平台管理 通信服务 3. 中间件: 软件组件提供应用新服务 4. 固有运行时程序库: Intel提供集成性能函数库(IPP) 5. 用户应用: 为用户提供各种最先进的功能。 加图。

Reference/Development Intel PCA 开发工具 Performance Analyzer Host Simulator C Libraries .exe Code (binary) IDE Compile Assembler Disassembler Linker Logic Analyzer Debugger Symbol Tables JTAG Trace Download Binary Results JTAG Tool Reference/Development Board Target 为开发者提供完整同一的开发工具

4.2 为什么要用 RTOS

1. 嵌入式操作系统的特点 嵌入式OS应该 嵌入式OS的分类 编码体积小 面向应用,可裁剪、可移植 实时性强 高可靠性 基于或与Windows兼容 Window CE 嵌入式Linux 工业与通信类 Vxworks 单片机类 μC/OS

2. RTOS需求背景 是指系统能及时(或即时)响应外部事件的请 求,在规定的时间内完成对该事件的处理, 并控制所有实时任务协调一致地运行。 实时系统应用需求 实时控制。 实时信息处理。

3. RTOS的特点 实时为其主要特征。 RTOS系统中必须支持优先级操作。实时系统下的每一个任务都必须有一个优先级 真正的实时系统是指基于优先级的抢占式操作系统。 非抢占调度方式(Non-preemptive Mode) 抢占调度方式(preemptive Mode)

4. 抢占调度方式 适用于紧急任务 要求立即执行。 抢占的原则有: 优先权原则。 短作业(进程)优先原则。 时间片原则。

5. RTOS 抢占型内核的调度 RTOS内核对进程的控制调度原则 抢占过程: 当有更高优先级的任务就绪时总能够得到一个CPU的控制权 当一个运行着的任务使一个比他的优先级高的任务进入到就绪状态时,当前任务的CPU使用权就立即被剥夺,或者叫挂起。而优先级高的进程立刻得到CPU的控制权。 如果是中断服务子程序使一个高优先级的任务进入到就绪态,当中断完成时,被中断的任务会被挂起,而让高优先级进程先运行。

1. linux操作系统的内核编译 2. Window CE的内核定制 4.3 操作系统的内核编译 1. linux操作系统的内核编译 2. Window CE的内核定制

4.3.1 linux操作系统的内核编译

1. Linux OS 的组成 Linux 内核 Linux Shell Linux 文件结构 Linux实用工具 实际上是从抽象资源操作到具体硬件操作细节之间的接口 Linux Shell 系统的用户界面,提供用户与内核进行交互的接口 Shell实际上是一个命令解释器。有如下主要Shell: Bourne Shell ----贝尔实验室开发; BASH-----GNU的OS默认的Shell; Korn Shell----兼容Bourne Shell 但有所发展 C Shell----Sun的Shell的BSD版本 Linux 文件结构 采用多级目录树结构 Linux实用工具

2. Linux操作系统结构图

2. Linux操作系统结构图 进程管理 虚拟文件管理 存储器 管理 网络 协议栈 设备驱动程序

3. Linux的内核编译方法 三条命令来进行配置内核: 文件系统 Jffs2与Extfs Make config (文本界面方式) Make menuconfig (文本界面 菜单驱动) Make xconfig (图形界面方式) 文件系统 Jffs2与Extfs Jffs2文件系统具有更好的崩溃恢复机制

3. Linux的内核编译方法 内核可以编译成三种形式: 映像文件的生成 Vmlinux (无压缩可执行文件) Image (压缩文件) zImage (自解压压缩文件) 映像文件的生成 Mkfs.jffs2工具

4.3.2 Window CE的内核定制

Windows CE 的内核模块组成

Windows CE 内核模块功能 内核 持久存储 图形与多媒体 进程间通信 通信服务 安全服务 用户界面服务 Internet服务 内核模块不可选,其它模块都为可选 内核 持久存储 图形与多媒体 进程间通信 通信服务 安全服务 用户界面服务 Internet服务

Windows CE 内核定制流程 1. 对操作系统进行裁剪,配置上述各个组件; 2. 建立定制WinCE的Image文件; 1. 对操作系统进行裁剪,配置上述各个组件; 2. 建立定制WinCE的Image文件; 3. 如果目标系统本身也是定制的,就需要开发OAL层(OEM适配层)和该系统的WinCE加载程序; 4. 将建立的Image文件下载到目标设备上,进行调试; 5. 重复上述过程直到达到要求。 6. 在定制OS基础上,可发布SDK供软件开发者使用。

4.4 什么是BootLoader

1. 系统的启动与引导 台式机 嵌入式系统 固件中的引导代码和Boot Loader两大部分; 引导装载程序装入主引导记录MBR中; 由BIOS将控制权移交给引导装载程序; 嵌入式系统 没有BIOS固件程序; 加载任务由Boot Loader唯一完成; 系统加电或复位都是从地址0x0开始运行,因此Boot Loader程序都是存放在该地址中。

2. 什么是Boot Loader Boot Loader是在OS内核之前运行的一段小程序。 Boot Loader是硬件专用的 可初始化硬件设备; 建立内存空间映射图; 为调用OS内核准备环境; 下载内核映像与文件系统。 Boot Loader是硬件专用的

3. 关于Boot Loader Boot Loader支持的硬件环境 Boot Loader的安装地址 多阶段启动 启动下载模式与下载模式 串口协议与TFTP协议

4. Linux下Boot Loader的结构 大多数Boot Loader分为阶段1和阶段2 阶段1依赖与CPU体系结构,如设备初始化代码等,一般采用汇编语言来实现; 阶段2 用C语言实现,可以完成一些复杂的功能,并且具有更好的可读性及可移植性。

可以通过修改PC寄存器为合适的地址来实现 5. Boot Loader阶段 1 1. 基本硬件初始化 2. 为加载阶段2准备RAM空间 3. 复制阶段2到RAM空间 4. 设置堆栈 嵌入式系统物理内存布局 5. 跳转到阶段2的C入口点 可以通过修改PC寄存器为合适的地址来实现

6. Boot Loader阶段 2 一个问题: Boot Loader 的C语言代码如何执行? 2. trampoline(蹦床)程序 汇编代码作为阶段2可执行映像的入口点; Trampoline作为main()函数的外部包裹程序;

6. Boot Loader阶段 2 4. 为内核设置启动参数 1. 初始化本阶段要使用的硬件设备 2. 检测系统的内存映射 1. 初始化至少一个串口,初始化计数器等; 2. 初始化之前,可重新点亮LED表明进入main函数运行。 1. 初始化本阶段要使用的硬件设备 2. 检测系统的内存映射 内存描述 内存映射的检测 3. 加载Kernel映像和根文 件系统映像。 规划内存占用布局 从Flash/ROM上复制 4. 为内核设置启动参数 内核用标记列表来传递启动参数 启动参数ATAG_CORE; ATAG_MEM; ATAG_CMDLINE; ATAG_RAMDISK; ATAG_INITRD. 5. 调用内核

7. 关于串口终端 1. 在BootLoader程序设计中,从串口收到正确的打印信息说明BootLoader程序引导系统正常执行 7. 关于串口终端 1. 在BootLoader程序设计中,从串口收到正确的打印信息说明BootLoader程序引导系统正常执行 串口的“booting the kernel …“ 内核启动信息才能说明BootLoader已经成功运行。 2. 串口终端常见问题解决

8. XSBase 的Boot Loader安装与使用 从www.tup.com.cn下载源码: Boot-XSBase255.tar.gz 1. Building xboot255 2. 下载Boot Loader 到目标板 使用与源码同时编译的烧写工具jflash-XSBase255进行烧写 Boot Loader提供了18条命令给用户使用 3. 熟悉使用Boot Loader指令

9. 2款常用的开源boot loader工具 Blob Blob是“Boot loader Object”的缩写,是一款嵌入式linux引导程序。最初是Jan-Derk Bakker和 ErikMouw针对LART目标板而设计的,同其他开源代码一样,很多人未blob的发展做出了自己的贡献。到现在为止,blob已经支持多种cpu,包括sa1100,sa1110,pxa255,pxa270等,用户可以根据目标板的特性进行定制。 它能实现以下功能: 引导嵌入式linux,它可以把linux、kernel等从flash中load到Ram中执行 命令行下在线更新blob、kernel和ramdisk。 命令行下可以直接对物理寻址空间进行查看和修改。 可见blob除了引导系统这个基本功能外,还具备BSP开发的功能,对于嵌入式开发前期,blob是一个非常有效的工具。

9. 2款常用的开源boot loader工具 Blob Blob实现功能: 是“Boot loader Object”的缩写。最初是Jan-Derk Bakker和 ErikMouw针对LART目标板而设计的, 到现在为止,blob已经支持多种cpu,包括sa1100,sa1110,pxa255,pxa270等,用户可以根据目标板的特性进行定制。 Blob实现功能: 引导嵌入式linux,从flash中load到Ram中执行 命令行下在线更新blob、kernel和ramdisk。 命令行下直接对物理寻址空间进行查看和修改。 除了引导系统外,还具备BSP开发的功能,对于嵌入式开发前期,blob是一个非常有效的工具。

9. 2款常用的开源boot loader工具 U-Boot U-Boot实现功能: 由德国工程师Wolfgang Denk从8XXROM代码发展而来 支持多种cpu,包括PowerPC,ARM,MIPS,x86. 源代码可在http://sourceforge.net 下载得到。 U-Boot实现功能: 在线读写Flash、IDE、EEROM、DOC、RTC ; 识别二进制、ELF32、uImage格式的Image; 单任务软件运行环境,可动态加载和运行独立的程序; 支持脚本语言; 支持MTD和文件系统; 支持中断。 支持WatchDog、LCD logo和状态指示功能。

设备驱动程序概述 Linux系统的驱动程序开发 WinCE系统的驱动程序开发 4.5 嵌入式操作系统的驱动开发 设备驱动程序概述 Linux系统的驱动程序开发 WinCE系统的驱动程序开发

4.5.1 设备驱动程序概述

OS中设备驱动程序主要功能 探测设备和初始化设备 从设备接收数据并提交内核 从内核接收数据送到设备 检测和处理设备错误

OS中设备驱动程序分类 Linux操作系统 字符类型设备 块设备 网络设备 WinCE系统设备驱动模型 流接口驱动 本地设备驱动

OS中设备驱动程序的特点 读/写 中断 时钟 每个驱动程序要复制本设备的读/写操作。OS定义好读/写接口,再由驱动程序完成具体的功能。

OS中设备驱动程序的调用 Linux WinCE 采用内核模块机制 驱动模块没有编译到内核模块中 模块的插入与卸载 Insmod rmmod WinCE 驱动程序通常被编译成动态链接库DLL,进行动态加载。 驱动的安装: 连接WinCE设备; 将设备驱动程序的dll文件拷贝到Windows目录下; 在注册表中创建相应的项,填入键值。

4.5.2 Linux系统的驱动程序开发

1. Linux的设备文件 硬件设备看作普通文件,用标准调用接口来完成文件的打开关闭、读写控制。 设备文件的设备号 都用open()打开,read()和write()读写; 驱动主要任务就是实现这些系统调用函数。 设备文件的设备号 主设备号: 次设备号: 已注册的硬件设备的主设备号在/proc/devices查看 标识设备种类,使用的驱动程序 标识同一驱动的不同硬件设备

1. Linux的设备文件 设备驱动源代码分布 应用对硬件设备调用 /drivers/block: /drivers/char: /drivers/cdrom: /drivers/pci: /drivers/scsi: /drivers/net: /drivers/sound: 应用对硬件设备调用 内核根据设备类型和主设备号调用相应的驱动 从用户态进入到内核态; 驱动判断此设备号,完成对相应硬件的操作。

2. Linux设备驱动程序结构 设备驱动的接口 与OS内核的接口 与系统引导的接口 与设备的接口 ./include/linux/fs.h中的file_operations数据结构来完成 与系统引导的接口 利用驱动程序对设备进行初始化; 与设备的接口 描述驱动如何与设备进行交互,与具体设备密切相关。

2. Linux设备驱动程序结构 设备驱动的功能 驱动的注册与注销 设备的打开与释放 设备的读写 设备的控制; 设备的中断和轮询处理

3. Linux设备驱动程序举例 (1) 基本字符设备驱动程序设计 确定主要数据结构 和全局变量 设计主要接口函数 设计模块加载方式 没有具体功能,仅实现驱动程序框架 实现4个基本操作 Xsbase_open() Xsbase_write() Xsbase_read() Xsbase_release() 设计主要接口函数 设计模块加载方式 驱动安装过程 驱动测试 结束

4. 设备驱动设计中涉及的具体问题 用户空间和内核空间 应用程序运行在用户空间,模块运行在内核空间 多用户OS的授权访问机制: Linux的ring0级和ring3级; Linux通过系统调用或者中断完成从用户空间到内核空间的转换。 Copy_to_user()和copy_from_user()函数调用 用户空间与内核空间之间的数据传输; 用来检查用户空间的指针是否有效;

4. 设备驱动设计中涉及的具体问题 Proc文件系统 是另一种内核和内核模块向进程传递信息的方法 Proc文件系统的目录结构举例 以文件系统方式为访问系统内核数据的操作提供接口; /proc下面每个文件都被绑定到一个内核函数,函数动态的生成文件的内容; 用户和应用程序可以通过Proc得到系统信息,并可以改变内核的某些参数。 Proc文件系统的目录结构举例

系统注册的中断信息在:中断号、收到的中断数、驱动器名; 4.1 Proc文件系统的目录结构举例 文件/目录名 描述 Device 系统字符和块设备编号与驱动程序名 Driver 组织了不同的驱动程序; Interrupts 系统注册的中断信息在:中断号、收到的中断数、驱动器名; IRQ 与CPU相关的中断掩码; Modules 系统正在使用的module信息 Net 网络信息目录 Scsi Scsi设备信息 Sys 可更改的内核数据的目录 tty 和终端相关的数据

4.2 /proc/sys下的文件和目录举例 文件/目录名 描述 Kernel/acct 进程帐号控制值 Kernel/domainname 机器域名 Kernel/hostname 主机名 Kernel/osrelease 内核版本号 Kernel/printk 内核消息日志级数 Net/core 通用网络参数 Net/ipv4 IP网络参数 vm/bdflush 磁盘缓冲区刷新参数 Vm/freepages 最小自由页数

4.6 嵌入式应用的远程调试 GNU GDB的远程调试功能

1. PC系统与嵌入式系统调试 调试环境上的区别 嵌入式调试环境带来的问题 调试器与被调试程序如何通信? 被调试程序产生异常如何及时通知调试器? 调试器如何控制、访问被调试程序? 调试器如何识别有关被调试程序的多任务信息并控制某一特定任务? 调试器如何处理目标平台的硬件信息?

2. 嵌入式系统的远程调试环境的创建 用插入Stub程序来解决上述 问题 调试器与被调试程序如何通信? 通过制定通信端口遵循远程调试协议进行通信。 http://rtos.ict.ac.cn/rtos/debugger/ 用插入Stub程序来解决上述 问题 调试器与被调试程序如何通信? 被调试程序产生异常如何及时通 知调试器? 调试器如何控制、访问被调试程 序? 调试器如何识别有关被调试程序 的多任务信息并控制某一特定任 务? 调试器如何处理目标平台的硬件 信息? 目标系统的异常处理专项通信模块通知调试器当前的异常号;调试器将异常告知用户。 控制请求转换成对目标程序地址空间或目标平台寄存器的访问。 由目标操作系统提供相关接口。目标系统根据请求,调用该接口提供信息或进行控制。 调试器能根据异常号识别目标平台产生异常的类型,可有调试器独立完成。

2. 嵌入式系统的远程调试环境的创建 远程调试环境示意图 目标平台桩模块: 支持远程调试协议的 通信模块; 多任务调试接口; 支持远程调试协议的 通信模块; 多任务调试接口; 修改异常处理程序; 断点设置函数。 运行调试器 指定调试通信接口 向目标系统发消息 目标系统初始化 至应用程序入口 主动触发异常 异常处理程序转入 调试端口通信 主机 目标平台 调试器的桩模块

2. 嵌入式系统的远程调试环境的创建 插桩的两种实现方式 插桩方法的使用特点 第一种:ROM Monitor; 第二种:通用操作系统实现。 打开嵌入式Linux OS的kgdb开关,就相当于插桩。 插桩方法的使用特点 实质上是用软件接管了目标系统的全部异常处理和部分中断处理; 一般适用于对应用程序的调试; 通常在调试版的目标系统上使用。

3. GDB的远程调试功能 什么情况下需要使用GDB的远程调试功能? GDB远程调试环境原理 内核 应用程序 Stub程序 远程主机 GDB/XGDB X-Win环境 本地主机 串口或TCP/IP链接

小 结

Boot Loader Stage 1—基本硬件初始化 1. 屏蔽所有中断 Boot Loader 不必响应中断,中断屏蔽可通过写ICMR寄存器来完成 2. 设置CPU的速度和时钟频率 RAM初始化 设置系统内存控制器的功能寄存器 3. 初始化LED 用GPIO来驱动LED,目的是表明系统的状态; 也可以初始化UART,向串口打印Logo字符的形式 4. 关闭CPU内部的指令/数据Cache。

Boot Loader Stage 1—为阶段2准备RAM 1. 为了加快执行速度,通常把阶段2的C代码加载到RAM空间执行 2. 准备RAM空间 地址范围可任意安排,如空间最低或最高端,一般不超过1MB; 要考虑可执行映像+堆栈空间; 空间大小最好是内存页大小(4KB)的整数倍 3. 确保所安排的地址范围是可读写RAM 对所安排地址进行测试; 4. 复制阶段2代码到RAM中 要确定可执行映像在Flash/ROM中的起始/终止地址 RAM空间的起始地址

Blob的RAM地址测试算法 1. 以Memory Page为单位进行测试,测试每个页的头两个字是否可读写。 2. 步骤: 2)向这两个字中写入任意数字,如0x55和0xaa; 3)立即读回,检查是否一致。如果不一致,则说明所分配不是一段有效RAM空间。 4)恢复头两个字的原始内容; 3. 为了得到一段干净的ARM空间,可以将分配的Ram空间进行清零处理。

Boot Loader Stage 1—设置堆栈指针sp 1. 堆栈指针的设置是为执行C语言代码做准备 2. 通常设置sp指针的值为 stage2-4 阶段2的RAM空间的最顶端; 堆栈向下生长。 3. 系统物理内存布局应该如图所示。

Boot Loader Stage 2—Trampoline示例 .text .globl _trampoline _ trampoline: B1 main /*如果main函数返回,就简单的再调用它*/ B _ trampoline

Boot Loader Stage 2—检测系统内存映射 将整个4GB的物理地址空间中那些地址范围分配用来寻址系统的RAM单元。 必须在内核映像读到RAM之前对整个系统内存映射进行检查。 描述RAM地址空间的连续地址范围 内存映射的检测

RAM地址空间连续地址范围描述 内存区域的基地址 内存区域的长度 Used=1:已映射; Used=0:未映射。 Typedef struct memory_area_struct { u32 start; u32 size; int used; } memory_area_t 内存区域的基地址 内存区域的长度 Used=1:已映射; Used=0:未映射。 Memory_area_t memory_map[NUM_MEM_AREAS]={ [0 … (NUM_MEM_AREAS-1)] = { .start = 0, .size = 0, .used = 0}, };

内存映射的检测 For(i=0;i<NUM_MEM_AREAS;i++) memory_map[i].used = 0; 数组初始化 For(i=0;i<NUM_MEM_AREAS;i++) memory_map[i].used = 0; For(addr=MEM_START;addr<MEM_END;addr+=PAGE_SIZE) *(u32 *) addr = 0; For(I = 0,addr=MEM_START;addr<MEM_END;addr+=PAGE_SIZE) { test_mp(); If(current memory page isnot a valid ram page){ if(memory_map[i].used) i++; continue; } If(* (u32 *)addr != 0){ if(memory_map[i].used) i++; 检测从基地址MEM_START+i* PAGE_SIZE开始,大小为PAGE_SIZE的地址空间是否是有效的RAM地址空间 当前页已经是一个被映射到RAM的有效地址范围; 但是还要看看当前页是否只是4GB地址空间中某个地址页的别名。

内存映射的检测 当前页已经是一个被映射到RAM的有效地址范围; 而且它也不是4GB地址空间中某个地址页的别名。 If (memory_map[i].used ==0) { memory_map[i].start = addr; memory_map[i].size = PAGE_SIZE; memory_map[i].used = 1; }else{ memory_map[i].size += PAGE_SIZE; }

规划内存占用布局 要考虑基地址和映像的大小两个方面 内核映像一般将其复制到从MEM_START+0x8000这个基地址开始的约1MB大小的内存范围内(Linux内核不超过1MB) MEM_START~MEM_START+0x8000之间存放全局数据结构,如启动参数和内核页表等信息。 根文件系统一般复制到MEM_START+0x100000开始的地方;

从Flash/ROM上复制 统一编址,Flash寻址与RAM寻址的方法相同 可用一个循环来完成从Flash设备上复制映像的操作 While(count) { *dest++ = *src++; count -= 4; }

标记列表结构 struct tag { struct tag_header hdr; union { struct tag_core core; struct tag_mem32 mem; struct tag_videotext videotext; struct tag_ramdisk ramdisk; struct tag_initrd initrd; struct tag_serialnr serialnr; struct tag_revision revision; struct tag_videolfb videolfb; struct tag_cmdline cmdline; struct tag_acorn acorn; struct tag_memclk memclk; } u; }; struct tag_header { u32 size; u32 tag; };

ATAG_CORE 参数的设置 内核启动参数在内存中的起始基地址 tag_array = (struct tag*) Boot_params; tag_array->hdr.tag=ATAG_CORE; tag_array->hdr.size=tag_size(tag_core); tag_array->u.core.flags=1; tag_array->u.core.pagesize=4096; tag_array->u.core.rootdev=0x00100000; tag_array=tag_next(tag_array); 宏,计算下一个Tag起始地址。 根文件系统设备ID在这设置

每个有效内存段对应一个ATAG_MEM参数标记 For(I = 0;i< NUM_MEM_AREAS; i++){ If(memory_map[i].used){ tag_array->hdr.tag=ATAG_MEM; tag_array->hdr.size=tag_size(tag_mem32); tag_array->u.mem.size=0x04000000; tag_array->u.mem.start=0x20000000; tag_array=tag_next(tag_array); }

ATAG_CMDLINE 参数的设置 Linux内核在启动时可以命令行参数的形式接收信息 For(p=cmdline;*p==‘ ‘;p++){ If(*p==‘\0’ ) return; tag_array->hdr.tag=ATAG_CMDLINE; tag_array->hdr.size=tag_size(tag_cmdline); Strcpy(tag_array->u.cmdline.cmdline,p); tag_array=tag_next(tag_array); } 用命令行字符串: Console=ttyS0,11520n8 来通知内核用ttS0做控制台,串口采用1152bps,无校验位,8位数据位。

告诉Linux内核解压后的Ramdisk有多大KB ATAG_RAMDISK 参数的设置 告诉Linux内核解压后的Ramdisk有多大KB tag_array->hdr.tag=ATAG_RAMDISK; tag_array->hdr.size=tag_size(tag_ramdisk); tag_array->u.ramdisk.start = 0; tag_array->u.ramdisk.size = RAMDISK_SIZE; tag_array->u.ramdisk.flag = 1; tag_array=tag_next(tag_array); 自动调入ramdisk

告诉Linux内核在RAM中的什么地方可以找到initrd映像以及它的大小。 ATAG_INITRD 参数的设置 告诉Linux内核在RAM中的什么地方可以找到initrd映像以及它的大小。 tag_array->hdr.tag=ATAG_INITRD2; tag_array->hdr.size=tag_size(tag_initrd); tag_array->u.ramdisk.start = RAMDISK_RAM_BASE; tag_array->u.ramdisk.size = INITRD_LEN; tag_array=tag_next(tag_array); Initrd映像的长度

Boot Loader Stage 2—调用内核 直接跳转到内核的第一条指令处,即MEM_START+0x8000地址处。 跳转前要检查下列条件是否满足: CPU寄存器设置 CPU模式 Cache和MMU的设置 R0 = 0; R1 = 机器类型ID; R2 = 启动参数标记列表在 RAM中起始基地址 禁止中断IRQs和FIQs; CPU使用SVC模式。 MMU必须关闭; 指令cache可开可关; 数据cache必须关闭;

串口终端常见问题解决 1. 串口终端显示乱码或根本没有显示等问题的解决: Boot Loader对串口的初始化设置不正确; 运行在host端的终端程序对串口的设置不正确,如波特率、奇偶校验、数据位和停止位等设置。 2. Boot Loader运行时可正确输出,但内核启动后却无法看到内核的启动输出信息的问题解决: 首先确认编译内核时是否配置对串口终端的支持;驱动配置正确; Boot Loader与内核对CPU时钟频率配置不一致,也会导致该问题 确认Boot Loader使用的内核基地址与内核映像编译时所用的运行基地址相同。

Boot Loader指令 Help Memcpy Reload Memdump Bootp Hexdump Tftp Memcmp Flash Erase Lock Unlock Boot Memcpy Memdump Hexdump Memcmp Memset Write Read Status reboot

设备的注册与注销 注册 注销 为设备赋予一个主设备号; Fs/devices.c中的register_chrdev()函数,或 Fs/block_dev.c的register_blkdev()函数。 注销 释放主设备号; Fs/devices.c中的unregister_chrdev()函数,或 Fs/block_dev.c的unregister_blkdev()函数。

设备的打开与释放 用打开设备来完成设备的初始化准备 Open()完成的工作: 释放设备 Include/linux/fs.h中file_operation结构的open(); Open()完成的工作: 先检查设备错误,如设备未准备好等错误; 第一次打开要初始化硬件设备; 识别次设备号,更新读写操作当前位置指针f_ops; 分配和填写要放在file->private_data中断数据,计数器增1。 释放设备 file_operation结构的release(); Release()的操作与open() 相反。

block_read() / block_write() 设备的读写操作 字符设备的读写 直接使用函数read()/write(); 块设备的读写: 调用函数block_read() / block_write(); block_read() / block_write() 向设备请求表中增加读写请求,让内核可对请求进行优化; 块读写是对内存缓冲区进行读写; 如果需要真正的从/向设备读/写,要使用结构blk_dev_struct中的request_fn()来完成。

设备的控制操作 对设备除了读写,还需要控制; 设备驱动中的ioctl() 函数完成控制功能: Ioctl() 与设备密切相关,需具体分析

设备的轮询与中断 中断处理与轮询查询 中断是最有效的响应方法 不支持中断的硬件设备读写时要轮询设备状态; 内核定期查询对CPU资源是个浪费; 定时器轮询。 中断是最有效的响应方法 硬件在需要的时候想内核发出中断信号; 内核通过驱动注册过的中断,把硬件中断信息传递给相应的设备驱动; 对中断资源请求在驱动初始化时已完成; 如何将中断发送给CPU取决于体系结构。

驱动注册过的中断信息 中断例程与中断号通过注册已被记录,可在/proc/interrupts查询。

基本字符驱动主要数据结构和全局变量 Fs/device.c中的device_struct结构 Struct device_struct{ 是管理设备的主要数据结构,包含了设备接口fops。 当字符设备注册到内核,设备名字和相关操作被添加到chrdev[]全局数组中; Chrdev[]可组织最多255个device_struct结构。 Struct device_struct{ const char * name; struct file_operations * fops; } Static Struct device_struct chrdevs[MAX_CHRDEV];

基本字符驱动主要接口函数设计 只需实现驱动需要的接口 Static struct file_operations chr_fops = { read: xsbase_read; write: xsbase_write; open: xsbase_open; release: xsbase_release; } Static int xsbase_open (struct inode*inode,struct file *file){ MOD_INC_USE_COUNT; printk(“this chrdev is opened!”); return 0} Static int xsbase_release (struct inode*inode,struct file *file){ MOD_DEC_USE_COUNT; printk(“this chrdev is released!”);

基本字符驱动主要接口函数设计 从内核空间的数据队列中读取数据data Xsbase_write使用: Copy_from_uer() Static ssize_t xsbase_read (struct file *file, char *buf, size_t count,loff_t *f_pos) { Int len; If(count < 0) return –EINVAL; Len = strlen(data); If(len < count) count = len; Copy_to_user(buf,data,count+1); return count } Xsbase_write使用: Copy_from_uer()

基本字符驱动的模块加载 Int init_module(void) { Int res; Res = register_chrdev(0,”xsbase”,&chr_fops) If(res < 0) printk(“can’t get major name!”); return res; } If(xsbase_major == 0) xsbase_major = res; Return 0; Int cleanup_module(void) { unregister_chrdev(xsbase_major,”xsbase”) ;}

1. 新建xsbase.c文件实现主要的数据结构和函数接口; 2. 编译源文件: 3. 生成xsbase.o文件,并下载到开发板上 基本字符驱动的安装 1. 新建xsbase.c文件实现主要的数据结构和函数接口; 2. 编译源文件: $Arm-linux-gcc xsbase.c –c xsbase.c 3. 生成xsbase.o文件,并下载到开发板上 4. 登录minicom; 5. 在minicom下,使用命令加载驱动模块: $Insmod xsbase 6. 创建一个设备文件 $mknod /dev/xsbase c major minor

基本字符驱动的测试 #include<stdio.h> #include<sys/types.h> #include<fcntl.h> Int main( ) { Int fd,length,rlen; Int I; Char *buf = “hello,world”; Char readbuf[12] = {0}; Fd = open(“/dev/xsbase ”,O_RDWR); If(fd <= 0) { printf(“Error opening device for writing!”); exit(1); }

基本字符驱动的测试 length = write(fd, buf, strlen(buf)); If(length < 0) { printf(“Error writing to device!”); exit(1); } rlen = read(fd, readbuf, 12); If(rlen < 0) printf(“Error writing to device!”); printf(“The read result is %s\n”,readbuf”); close(fd); return 0;

固态存储舍不得典型空间分配 0x00000000 Bootloader Boot参数 内核 根文件系统