当前位置:文档之家› linux中platform_device与platform_driver小结

linux中platform_device与platform_driver小结

linux中platform_device与platform_driver小结
linux中platform_device与platform_driver小结

linux 内核驱动--Platform Device和Platform_driver注册过程

从Linux 2.6 起引入了一套新的驱动管理和注册机制:Platform_device 和Platform_driver 。

Linux 中大部分的设备驱动,都可以使用这套机制, 设备用Platform_device 表示,驱动用Platform_driver 进行注册。

Linux platform driver 机制和传统的device driver 机制( 通过driver_register 函数进行注册) 相比,一个十分明显的优势在于platform 机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device 提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性( 这些标准接口是安全的) 。

Platform 机制的本身使用并不复杂,由两部分组成:platform_device 和platfrom_driver 。

通过Platform 机制开发发底层驱动的大致流程为: 定义platform_add_devices 注册platform_device, 定义platform_add_driver 注册platform_driver 。

1、platform_device注册过程:

首先要确认的就是设备的资源信息,例如设备的地址,中断号等。

在 2.6 内核中platform 设备用结构体platform_device 来描述,该结构体定义在kernel/include/linux/platform_device.h 中,

struct platform_device {

const char * name;

int id;

struct device dev;

u32 num_resources;

struct resource * resource ;

struct platform_device_id *id_entry;

};

该结构一个重要的元素是resource ,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h 中,

struct resource {

resource_size_t start;

resource_size_t end;

const char *name;

unsigned long flags;

struct resource *parent, *sibling, *child;

};

下面举s3c6410 平台的i2c 驱动作为例子来说明:

static struct platform_device *smdk6410_devices [] __initdata = {

#ifdef CONFIG_SMDK6410_SD_CH0

&s3c_device_hsmmc0,

#endif

#ifdef CONFIG_SMDK6410_SD_CH1

&s3c_device_hsmmc1,

#endif

&s3c_device_i2c0 ,

&s3c_device_i2c1,

&s3c_device_fb,

&s3c_device_usb,

&s3c_device_usb_hsotg,

&smdk6410_lcd_powerdev,

&smdk6410_smsc911x,

};

把一个或几个设备资源放在一起,便于集中管理,其中IIC设备platform_device 如下:

struct platform_device s3c_device_i2c0 = {

.name = "s3c2410-i2c",

#ifdef CONFIG_S3C_DEV_I2C1

.id = 0,

#else

.id = -1,

#endif

.num_resources = ARRAY_SIZE(s3c_i2c_resource ),

.resource = s3c_i2c_resource,

};

具体resource如下:

static struct resource s3c_i2c_resource [] = {

[0] = {

.start = S3C_PA_IIC,

.end = S3C_PA_IIC + SZ_4K - 1,

.flags = IORESOURCE_MEM,

},

[1] = {

.start = IRQ_IIC,

.end = IRQ_IIC,

.flags = IORESOURCE_IRQ,

},

};

这里定义了两组resource ,它描述了一个I2C 设备的资源,第 1 组描述了这个I2C 设备所占用的总线地址范围,IORESOURCE_MEM 表示第 1 组描述的是内存类型的资源信息,第 2 组描述了这个I2C 设备的中断号,IORESOURCE_IRQ 表示第2 组描述的是中断资源信息。设备驱动会根据flags 来获取相应的资源信息。

定义好了platform_device 结构体后就可以调用函数platform_add_devices 向系统中添加该设备了,之后可以调用platform_driver_register() 进行设备注册。

s3c6410-i2c的platform_device是在系统启动时,在mach-smdk6410.c里的smdk6410_machine_init()函数里进行注册的,这个函数申明为arch_initcall的函数调用,arch_initcall的优先级高于module_init。所以会在Platform驱动注册之前调用。(详细参考imach-smdk6410.c)

static void __init smdk6410_machine_init(void)

{

s3c_i2c0_set_platdata(NULL);

s3c_i2c1_set_platdata(NULL);

s3c_fb_set_platdata(&smdk6410_lcd_pdata);

gpio_request(S3C64XX_GPN(5), "LCD power");

gpio_request(S3C64XX_GPF(13), "LCD power");

gpio_request(S3C64XX_GPF(15), "LCD power");

i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));

i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));

//添加多设备

}

int platform_add_devices(struct platform_device **devs, int num)

{

int i, ret = 0;

for (i = 0; i < num; i++) {

ret = platform_device_register(devs[i]);

if (ret) {

while (--i >= 0)

platform_device_unregister(devs[i]);

break;

}

}

return ret;

}

int platform_device_register(struct platform_device *pdev)

{

device_initialize(&pdev->dev);

return platform_device_add(pdev);

}

int platform_device_add(struct platform_device *pdev)

{

int i, ret = 0;

if (!pdev)

return -EINV AL;

if (!pdev->dev.parent)

pdev->dev.parent = &platform_bus;

pdev->dev.bus = &platform_bus_type;

if (pdev->id != -1)

dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);//如果有id 表示有多个同类设备用pdev->name和pdev->id标识该设备

else

dev_set_name(&pdev->dev, "%s", pdev->name);

//否则,只用pdev->name标识该设备

for (i = 0; i < pdev->num_resources; i++) {

struct resource *p, *r = &pdev->resource[i];

if (r->name == NULL)

r->name = dev_name(&pdev->dev);

p = r->parent;

if (!p) {

if (resource_type(r) == IORESOURCE_MEM)

p = &iomem_resource; // 作为IOMEM 资源分配

else if (resource_type(r) == IORESOURCE_IO)

p = &ioport_resource; // 作为IO PORT资源分配}

if (p && insert_resource(p, r)) { // 将新的resource 插入内核resource tree

printk(KERN_ERR

"%s: failed to claim resource %d/n",

dev_name(&pdev->dev), i);

ret = -EBUSY;

goto failed;

}

}

pr_debug("Registering platform device '%s'. Parent at %s/n",

dev_name(&pdev->dev), dev_name(pdev->dev.parent));

ret = device_add(&pdev->dev);//添加设备到设备树

if (ret == 0)

return ret;

failed:

while (--i >= 0) {

struct resource *r = &pdev->resource[i];

unsigned long type = resource_type(r);

if (type == IORESOURCE_MEM || type == IORESOURCE_IO)

release_resource(r);

}

return ret;

}

设备驱动加到Linux内核中

7.2.3 设备驱动加到Linux内核中 设备驱动程序编写完后将该驱动程序加到内核中。这需要修改Linux 的源代码,然后重新编译内核。 ①将设备驱动程序文件(比如mydriver.c)复制到/Linux/drivers/char目录下。该目录保存了Linux下字符设备的设备驱动程序。修改该目录下mem.c 文件,在int chr_dev_init()函数中增加如下代码: #ifdef CONFIG_MYDRIVER device_init(); #endif 其中CONFIG_MYDRIVER是在配置Linux内核时赋值。 ②在/linux/drivers/char目录下Makefile中增加如下代码: ifeq ($(CONFIG_MYDRIVER),y) L_OBJ + = mydriver.o endif 如果在配置Linux内核时选择了支持新定义的设备,则在编译内核时会编译mydriver.c生成mydriver.o文件。 ③修改/linux/drivers/char目录下config.in文件,在 comment Character devices 语句下面加上 bool suppot for mydriver CONFIG_MYDRIVER 这样,若编译内核,运行make config,make menuconfig或make xconfig,那么在配置字符设备时就会有选项: Support for mydriver 当选中这个设备时,设备驱动就加到了内核中了。 重新编译内核,在shell中将当前目录cd 到Linux目录下,然后执行以下代码: # make menuconfig # make dep # make 在配置选项时要注意选择支持用户添加的设备。这样得到的内核就包含用户的设备驱动程序。 Linux通过设备文件来提供应用程序和设备驱动的接口,应用程序通过标准的文件操作函数来打开、关闭、读取和控制设备。查看Linux文件系统下的/proc/devices,可以看到当前的设备信息。如果设备驱动程序已被成功加进,这里应该由该设备对应的项。/proc/interrupts纪录了当时中断情况,可以用来查看中断申请是否正常;对于DMA和I/O口的使用,在/proc下都有相应的文件进行记录;还可以在设备驱动程序中申请在/proc 文件系统下创建一个文件,该文件用来存放设备相关信息。这样通过查看该文件就可以了解设备的使用情况。总之,/proc文件系统为用户提供了查

Linux内核—文件系统模块的设计和开发

Linux内核—文件系统模块的设计和开发 郑小辉 摘要:目前,Linux技术已经成为IT技术发展的热点,投身于Linux技术研究的社区、研究机构和软件企业越来越多,支持Linux的软件、硬件制造商和解决方案提供商也迅速增加,Linux在信息化建设中的应用范围也越来越广,Linux产业链已初步形成,并正在得到持续的完善。随着整个Linux产业的发展,Linux技术也处在快速的发展过程中,形成了若干技术热点。 本文介绍了Linux的发展和特点,以及与其他文件系统的区别。文中主要是对Linux2.4.0内核文件系统源代码的分析,并参考其文件格式设计一个简洁的文件系统。源代码的分析主要介绍了VFS文件系统的结构,Linux自己的Ext2文件系统结构,以及文件系统中的主要函数操作。 在设计的简洁文件系统中,通过调用一些系统函数实现了用户的登录、浏览目录、创建目录、更改目录、创建文件以及退出系统功能。 关键字:Linux 源代码分析文件系统Ext2 Linux内核

Linux kernel -Design and development for the File System Module Zheng xiaohui Abstract: Currently, Linux IT technology has become a hot development technology. Participating in Linux technology research communities, research institutes and software enterprises are in support of Linux more and more, software and hardware manufacturers and solution providers have increased rapidly, In the development of the information industry the Linux application is also increasing, Linux industry chain has taken shape, and is sustained improvemently. With the entire industry in the development of Linux, and Linux is also at the rapid development process, formed a number of technical points. This paper presents the development of Linux and features, and with other file system differences. The main text of the document is Linux2.4.0 system kernel source code analysis, and I reference its file format to design a simple file system. The analysis of the source code mainly on the VFS file system structure, Linux Ext2 its own file system structures, file systems and the main function operation. In the design of the file simple system, some system function is used to achieve function such as: the user's login, browse catalogs, create directories, Change directory, create documents and withdraw from the system function and etc. Key words: Linux, the source code, file system, Ext2, Linux kernel

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Linux内核与跟文件系统的关系

Linux内核与根文件系统的关系 开篇题外话:对于Linux初学者来说,这是一个很纠结的问题,但这也是一个很关键的问题!一语破天机:“尽管内核是Linux 的核心,但文件却是用户与操作系统交互所采用的主要工具。这对Linux 来说尤其如此,这是因为在UNIX 传统中,它使用文件I/O 机制管理硬件 设备和数据文件。” 一.什么是文件系统 文件系统指文件存在的物理空间,linux系统中每个分区都是一个文件系统,都有自己的目 录层次结构。 Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其 中。这种机制有利于用户和操作系统的交互。 每个实际文件系统从操作系统和系统服务中分离出来,它们之间通过一个接口层:虚拟文件系统或VFS来通讯。VFS使得Linux可以支持多个不同的文件系统,每个表示一个VFS 的通用接口。由于软件将Linux 文件系统的所有细节进行了转换,所以Linux核心的其它部分及系统中运行的程序将看到统一的文件系统。Linux 的虚拟文件系统允许用户同时能透明地安装 许多不同的文件系统。 在Linux文件系统中,EXT2文件系统、虚拟文件系统、/proc文件系统是三个具有代表性的 文件系统。 二.什么是根文件系统 根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。 那么根文件系统在系统启动中到底是什么时候挂载的呢?先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后。切换根目录,再挂载具体的根文件系统.根文件系统执行完之后,也就是到了Start_kernel()函数的最后,执行init的进程,也就第一个用户进程。对系统进行各 种初始化的操作。 根文件系统之所以在前面加一个”根“,说明它是加载其它文件系统的”根“,既然是根的话,那么如果没有这个根,其它的文件系统也就没有办法进行加载的。它包含系统引导和使其他文件系统得以挂载(mount)所必要的文件。根文件系统包括Linux启动时所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在Linux挂载分区时Linux 一定会找/etc/fstab这个挂载文件等,根文件系统中还包括了许多的应用程序bin目录等,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。在Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt 目录上,/mnt目录下就有这个分区的各个目录,文件。

linux内核中Kconfig文档的作用以及Kconfig的语法

linux内核中Kconfig文档的作用以及Kconfig的语法 2.6内核的源码树目录下一般都会有两个文文:Kconfig 和Makefile。分布在各目录下的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。在内核配置make menuconfig(或xconfig等)时,从Kconfig中读出配置菜单,用户配置完后保存到.config(在顶层目录下生成)中。在内核编译时,主Makefile调用这个.config,就知道了用户对内核的配置情况。上面的内容说明:Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中,可以通过修改Kconfig来增加对我们驱动的配置菜单,这样就有途径选择我们的驱动,假如想使这个驱动被编译,还要修改该驱动所在目录下的Makefile。因此,一般添加新的驱动时需要修改的文件有两种(注意不只是两个)*Kconfig*Makefile要想知道怎么修改这两种文件,就要知道两种文档的语法结构。First: Kconfig每个菜单项都有一个关键字标识,最常见的就是config。语法:config symboloptions<!--[if !supportLineBreakNewLine]-->< ;!--[endif]-->symbol就是新的菜单项,options是在这个新的菜单项下的属性和选项其中options部分有:1、类型定义:每个config菜单项都要有类型定义,bool:布尔类型,tristate

三态:内建、模块、移除,string:字符串,hex:十六进制,integer:整型例如config HELLO_MODULEbool "hello test module"bool类型的只能选中或不选中,tristate类型的菜单项多了编译成内核模块的选项,假如选择编译成内核模块,则会在.config中生成一个 CONFIG_HELLO_MODULE=m的配置,假如选择内建,就是直接编译成内核影响,就会在.config中生成一个CONFIG_HELLO_MODULE=y的配置.2、依赖型定义depends on或requires指此菜单的出现是否依赖于另一个定义config HELLO_MODULEbool "hello test module"depends on ARCH_PXA 这个例子表明HELLO_MODULE这个菜单项只对XScale处理器有效,即只有在选择了ARCH_PXA,该菜单才可见(可配置)。3、帮助性定义只是增加帮助用关键字help或 ---help---<!--[if !supportLineBreakNewLine]--><!--[en dif]-->更多详细的Kconfigconfig语法可参考:Second: 内核的Makefile内核的Makefile分为5个组成部分:Makefile 最顶层的Makefile.config 内核的当前配置文档,编译时成为顶层Makefile的一部分arch/$(ARCH)/Makefile 和体系结构相关的Makefiles/ Makefile.* 一些Makefile的通用规则kbuild Makefile 各级目录下的大概约500个文档,编译时根据上层Makefile传下来的宏定义和其他编译

Linux内核启动流程分析(一)

很久以前分析的,一直在电脑的一个角落,今天发现贴出来和大家分享下。由于是word直接粘过来的有点乱,敬请谅解! S3C2410 Linux 2.6.35.7启动分析(第一阶段) arm linux 内核生成过程 1. 依据arch/arm/kernel/vmlinux.lds 生成linux内核源码根目录下的vmlinux,这个vmlinux属于未压缩, 带调试信息、符号表的最初的内核,大小约23MB; 命令:arm-linux-gnu-ld -o vmlinux -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o init/built-in.o --start-group arch/arm/mach-s3c2410/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o drivers/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o 2. 将上面的vmlinux去除调试信息、注释、符号表等内容,生成arch/arm/boot/Image,这是不带多余信息的linux内核,Image的大小约 3.2MB; 命令:arm-linux-gnu-objcopy -O binary -S vmlinux arch/arm/boot/Image 3.将 arch/arm/boot/Image 用gzip -9 压缩生成arch/arm/boot/compressed/piggy.gz大小约 1.5MB;命令:gzip -f -9 < arch/arm/boot/compressed/../Image > arch/arm/boot/compressed/piggy.gz 4. 编译arch/arm/boot/compressed/piggy.S 生成arch/arm/boot/compressed/piggy.o大小约1.5MB,这里实 际上是将piggy.gz通过piggy.S编译进piggy.o文件中。而piggy.S文件仅有6行,只是包含了文件piggy.gz; 命令:arm-linux-gnu-gcc -o arch/arm/boot/compressed/piggy.o arch/arm/boot/compressed/piggy.S 5. 依据arch/arm/boot/compressed/vmlinux.lds 将arch/arm/boot/compressed/目录下的文件head.o 、piggy.o 、misc.o链接生成arch/arm/boot/compressed/vmlinux,这个vmlinux是经过压缩且含有自解压代码的内核, 大小约1.5MB; 命 令:arm-linux-gnu-ld zreladdr=0x30008000 params_phys=0x30000100 -T arch/arm/boot/compressed/vmlinux.lds a rch/arm/boot/compressed/head.o arch/arm/boot/compressed/piggy.o arch/arm/boot/compressed/misc.o -o arch/arm /boot/compressed/vmlinux

《深入理解LINUX内核》阅读笔记全二十章

《深入理解LINUX内核》(Understanding The Linux Kernel)第三版 第一章 - 绪论 第一章是绪论。前三节内容很少,讲的都是一些内核边缘相关的东西,不是真正内核的内容,简单了解就好,不必深究。后三节,“操作系统基本概念”简单描述了几个“使用操作系统”要知道的概念;“Unix文件系统概述”也是从用户的角度讲了几个概念,并没有深入到内核;“Unix内核概述”这一节内容很多,最重要的是它在讲述一些内核的重要概念时引出了很多必须处理的问题,让读者带着疑问到本书的后续章节里去自己探寻答案。 第二章 - 内存寻址 这一章的内容都是很底层的,直接是一些硬件特性或者是内核中处理硬件的一些策略。 内存地址根据其组织特点的不同分为三个层次:逻辑地址(虚拟地址)、线性地址、物理地址。再细一层,有分段和分页两种。对这两种机制,书中分别详细描述了其80X86的硬件特性和Linux内核对应的处理。 其中分页是重点。常规分页机制中,页框是4KB;而扩张分页机制的页框是4MB。Linux 采用了4级分页模型,能适应不同的体系结构。本章还讲述了硬件高速缓存和TLB (Translation Lookaside Buffer),TLB的翻译有很多种:转换后援缓冲器、转换检测缓冲区、旁路转换缓冲、页表缓冲,我觉得直接叫页表缓冲就很好理解了,没有必要纠结于单个单词的意思。 第三章 - 进程 这一章讲进程,但没有涉及任何的算法相关的东西,都是那些跟数据有关的系统调用、函数、数据结构,这跟前一章很像。 进程的静态特性:进程描述符,都是task_struct类型的结构,它的字段包含了与一个进程相关的所有信息。进程描述符是很基础很重要的东西,整个内核都构建在它的基础之上。 进程切换,这一章里“切换”是跟“调度”完全不同的概念。切换只是当进程调度时要做的数据的处理,特别是与进程描述符相关的操作以及硬件上下文、进程上下文相关的数据、字段。 创建进程,最重要的是do_fork()函数和copy_process()函数。 还有最后一节是撤销进程。重点是do_exit()函数和进程删除时的父子进程关系。 第四章 - 中断和异常 中断(interrupt)通常被定义为一个事件,该事件改变处理器执行的指令顺序。 中断分为同步和异步中断,或者称为异常和中断。 第二节中断和异常。中断包括可屏蔽中断和非屏蔽中断,而异常则包括处理器探测异常和编程异常。还讲述了一些关于IRQ线的知识,然后是异常处理程序发送的19种信号。当然,少不了中断描述符表。 第四节“初始化中断描述符表”,在Linux中分为以下几种描述符:中断门、系统门、系统中断门、陷阱门、任务门。 第六节中断处理。这是本章的重点,也是难点。 物理IRQ可以分配给32~238范围内的任何向量。 每个中断向量都有它自己的irq_desc_t描述符。

Linux内核启动过程分析

1、Linux内核启动协议 阅读文档\linux-2.6.35\Documentation\x86\boot.txt 传统支持Image和zImage内核的启动装载内存布局(2.4以前的内核装载就是这样的布局): | | 0A0000 +------------------------+ | Reserved for BIOS | Do not use. Reserved for BIOS EBDA. 09A000 +------------------------+ | Command line | | Stack/heap | For use by the kernel real-mode code. 098000 +------------------------+ | Kernel setup | The kernel real-mode code. 090200 +------------------------+ | Kernel boot sector | The kernel legacy boot sector. 090000 +------------------------+ | Protected-mode kernel | The bulk of the kernel image. 010000 +------------------------+ | Boot loader | <- Boot sector entry point 0000:7C00 001000 +------------------------+ | Reserved for MBR/BIOS | 000800 +------------------------+ | Typically used by MBR | 000600 +------------------------+ | BIOS use only | 000000 +------------------------+ 当使用bzImage时,保护模式的内核会被重定位到0x1000000(高端内存),内核实模式的代码(boot sector,setup和stack/heap)会被编译成可重定位到0x100000与低端内存底端之间的任何地址处。不幸的是,在2.00和2.01版的引导协议中,0x90000+的内存区域仍然被使用在内核的内部。2.02版的引导协议解决了这个问题。boot loader应该使BIOS 的12h中断调用来检查低端内存中还有多少内存可用。 人们都希望“内存上限”,即boot loader触及的低端内存最高处的指针,尽可能地低,因为一些新的BIOS开始分配一些相当大的内存,所谓的扩展BIOS数据域,几乎快接近低端内存的最高处了。 不幸的是,如果BIOS 12h中断报告说内存的数量太小了,则boot loader除了报告一个错误给用户外,什么也不会做。因此,boot loader应该被设计成占用尽可能少的低端内存。对zImage和以前的bzImage,这要求数据能被写到x090000段,boot loader应该确保不会使用0x9A000指针以上的内存;很多BIOS在这个指针以上会终止。 对一个引导协议>=2.02的现代bzImage内核,其内存布局使用以下格式:| Protected-mode kernel | 100000 +------------------------+ | I/O memory hole | 0A0000 +------------------------+ | Reserved for BIOS | Leave as much as possible unused ~ ~

Linux内核中读写文件

内核中读写文件 1.filp_open()在kernel中可以打开文件,其原形如下: Struct file* filp_open(const char* filename, int open_mode, int mode); 该函数返回strcut file*结构指针,供后继函数操作使用,该返回值用IS_ERR()来检验其有效性。 2. 读写文件(vfs_read/vfs_write) kernel中文件的读写操作可以使用vfs_read()和vfs_write,在使用这两个函数前需要说明一下get_fs()和set_fs()这两个函数。 vfs_read() vfs_write()两函数的原形如下: ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len, loff_t* pos); ssize_t vfs_write(struct file* filp, const char __user* buffer, size_t len, loff_t* pos); 注意这两个函数的第二个参数buffer,前面都有__user修饰符,这就要求这两个buffer指针都应该指向用空的内存,如果对该参数传递kernel空间的指针,这两个函数都会返回失败-EFAULT。但在Kernel中,我们一般不容易生成用户空间的指针,或者不方便独立使用用户空间内存。要使这两个读写函数使用kernel空间的buffer指针也能正确工作,需要使用set_fs()函数或宏(set_fs()可能是宏定义),如果为函数,其原形如下: void set_fs(mm_segment_t fs); 该函数的作用是改变kernel对内存地址检查的处理方式,其实该函数的参数fs只有两个取值:USER_DS,KERNEL_DS,分别代表用户空间和内核空间,默认情况下,kernel取值为USER_DS,即对用户空间地址检查并做变换。那么要在这种对内存地址做检查变换的函数中使用内核空间地址,就需要使用set_fs(KERNEL_DS)进行设置。get_fs()一般也可能是宏定义,它的作用是取得当前的设置,这两个函数的一般用法为:

linux内核中打开文件

首先分析一下sys_read系统调用(内核版本为2.6.19.4)。 源代码如下(摘自fs/read_write.c) [c-sharp]view plaincopy 1.SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) 2.{ 3.struct file *file; 4. ssize_t ret = -EBADF; 5.int fput_needed; 6. file = fget_light(fd, &fput_needed); 7.if (file) { 8. loff_t pos = file_pos_read(file); 9. ret = vfs_read(file, buf, count, &pos); 10. file_pos_write(file, pos); 11. fput_light(file, fput_needed); 12. } 13.return ret; 14.} 这里用到了fget_light(),file_pos_read(),vfs_read(),file_pos_write(),fput_light()。 ?file_pos_read()和file_pos_write()(均位于fs/read_write.c)用来读取当前文件指针(即当前文件操作的位置) ?fget_light()和fput_light()(位于fs/file_table.c和include/linux/file.h)必须是成对出现的!fget_light在当前进程的struct files_struct中根据所谓的用户空间文件描述符fd来获取文件描述符。另外,根据当前fs_struct是否被多各进程共享来判断是否需要对文件描述符进行加锁,并将加锁结果存到一个int中返回, fput_light则根据该结果来判断是否需要对文件描述符解锁 ?vfs_read()(位于fs/read_write.c)调用具体文件系统的read函数来完成读操作,代码如下: [cpp]view plaincopy 1.ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t * pos) 2.{ 3. ssize_t ret;

Linux内核之基于Bootsplash嵌入式Linux启动画面定制

Linux内核之基于Bootsplash嵌入式Linux启动画面定制 Linux内核之基于Bootsplash嵌入式Linux启动画面定制 在基于linux的嵌入式仿真平台开发中,终端的美观和可定制是一个重要的问题。开机时滚动在屏幕上的字符串和单调的penguin图标,使嵌入式设备仍然脱离不了pc的痕迹,linux控制台上单调的“白纸黑字”型表现方式可谓大煞风景。改造linux控制台使之美观可定制地展示开机信息和logo成为基于嵌入式linux应用的一项重要工作。 开源项目bootsplash(https://www.doczj.com/doc/2311802058.html,/)为解决这个问题提供了一个完美的解决方案。Boot- splash通过对内核打补丁来改变linux framebuffer控制台对图形显示的支持。通过用户空间程序来定制启动logo、设定控制台背景和显隐启动时的字符信息,甚至可以支持开机画面的动 画显示。本文介绍利用splashboot打造启动画面的解决方案,

涉及内核补丁、用户空间设置等方面的具体工作。 1 内核补丁和控制工具 1.1 支持bootsplash的内核补丁 针对不同的内核版本,bootsplash站点上给出了相应的内核补丁。我们所使用的内核版本为2.4.23,下载并给内核打上补丁:cd /usr/src/linux make mrproper patch -Np1 -i ../bootsplash-3.0.7-2.4.23.diff 重新编译内核: make menuconfig 选上如下的几个参数: Code maturity level options ---> Prompt for development and/or incomplete code/drivers

[vip专享]Source Insight打开linux内核源代码

用Source Insight打开linux内核源代码 2008-01-09 19:06 Linux的内核源代码可以从很多途径得到。一般来讲,在安装的linux系统下,/usr/src/linux目录下的东西就是内核源代码。另外还可以从互连网上下载,解压缩后文件一般也都位于linux目录下。内核源代码有很多版本,目前最新的稳定版是2.2.14。 许多人对于阅读Linux内核有一种恐惧感,其实大可不必。当然,象Linux内核这样大而复杂的系统代码,阅读起来确实有很多困难,但是也不象想象的那么高不可攀。只要有恒心,困难都是可以克服的。也不用担心水平不够的问题,事实上,有很多事情我们不都是从不会到会,边干边学的吗? 任何事情做起来都需要有方法和工具。正确的方法可以指导工作,良好的工具可以事半功倍。对于Linux 内核源代码的阅读也同样如此。下面我就把自己阅读内核源代码的一点经验介绍一下,最后介绍Window平台下的一种阅读工具。 对于源代码的阅读,要想比较顺利,事先最好对源代码的知识背景有一定的了解。对于linux内核源代码来讲,我认为,基本要求是:1、操作系统的基本知识;2、对C语言比较熟悉,最好要有汇编语言的知识和GNU C对标准C的扩展的知识的了解。另外在阅读之前,还应该知道Linux内核源代码的整体分布情况。我们知道现代的操作系统一般由进程管理、内存管理、文件系统、驱动程序、网络等组成。看一下Linux内核源代码就可看出,各个目录大致对应了这些方面。Linux内核源代码的组成如下(假设相对于linux目录): arch 这个子目录包含了此核心源代码所支持的硬件体系结构相关的核心代码。如对于X86平台就是i386。 include 这个目录包括了核心的大多数include文件。另外对于每种支持的体系结构分别有一个子目录。 init 此目录包含核心启动代码。 mm 此目录包含了所有的内存管理代码。与具体硬件体系结构相关的内存管理代码位于arch/*/mm目录下,如对应于X86的就是arch/i386/mm/fault.c 。 drivers 系统中所有的设备驱动都位于此目录中。它又进一步划分成几类设备驱动,每一种也有对应的子目录,如声卡的驱动对应于drivers/sound。 ipc 此目录包含了核心的进程间通讯代码。 modules 此目录包含已建好可动态加载的模块。

Linux内核启动过程和Bootloader(总述)

Linux内核启动过程和Bootloader(总述) 1.Linux内核启动过程概述 一个嵌入式 Linux 系统从软件角度看可以分为四个部分:引导加载程序(Bootloader),Linux 内核,文件系统,应用程序。其中 Bootloader是系统启动或复位以后执行的第一段代码,它主要用来初始化处理器及外设,然后调用 Linux 内核。Linux 内核在完成系统的初始化之后需要挂载某个文件系统做为根文件系统(Root Filesystem)。根文件系统是Linux 系统的核心组成部分,它可以做为Linux 系统中文件和数据的存储区域,通常它还包括系统配置文件和运行应用软件所需要的库。应用程序可以说是嵌入式系统的“灵魂”,它所实现的功能通常就是设计该嵌入式系统所要达到的目标。如果没有应用程序的支持,任何硬件上设计精良的嵌入式系统都没有实用意义。 2. Bootloader启动过程 Bootloader在运行过程中虽然具有初始化系统和执行用户输入的命令等作用,但它最根本的功能就是为了启动 Linux 内核。 2.1 Bootloader的概念和作用 Bootloader是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序,其作用类似于 PC 机上的 BIOS。在完成对系统的初始化任务之后,它会将非易失性存储器(通常是Flash或DOC等)中的Linux 内核拷贝到 RAM 中去,然后跳转到内核的第一条指令处继续执行,从而启动 Linux 内核。由此可见,Bootloader 和 Linux 内核有着密不可分的联系,要想清楚的了解 Linux内核的启动过程,我们必须先得认识 Bootloader的执行过程,这样才能对嵌入式系统的整个启动过程有清晰的掌握 2.2 Bootloader的执行过程 不同的处理器上电或复位后执行的第一条指令地址并不相同,对于 ARM 处理器来说,该地址为 0x00000000。对于一般的嵌入式系统,通常把 Flash 等非易失性存储器映射到这个地址处,而 Bootloader就位于该存储器的最前端,所以系统上电或复位后执行的第一段程序便是Bootloader。而因为存储 Bootloader的存储器不同,Bootloader的执行过程也并不相同,下面将具体分 嵌入式系统中广泛采用的非易失性存储器通常是 Flash,而 Flash 又分为 Nor Flash 和Nand Flash 两种。它们之间的不同在于:Nor Flash 支持芯片内执行(XIP, eXecute In Place),这样代码可以在Flash上直接执行而不必拷贝到RAM中去执行。而Nand Flash 并不支持XIP,所以要想执行 Nand Flash 上的代码,必须先将其拷贝到 RAM中去,然后跳到 RAM 中去执行 2.3 Bootloader的功能 (1)初始化 RAM

Linux内核中的Makefile文件

Linux内核中的Makefile文件 本节不对内核的Makefile文件进行深入展开,更多语法和说明请阅读 文件。 1.1.1 顶层Makefile 源码目录树顶层Makefile是整个内核源码管理的入口,对整个内核的源码编译起着决定性作用。编译内核时,顶层Makefile会按规则递归历遍内核源码的所有子目录下的Makefile文件,完成各子目录下内核模块的编译。熟悉一下该Makefile,对内核编译等方面会有所帮助。 1.内核版本号 打开顶层Makefile,开头的几行记录了内核源码的版本号,通常如下所示: VERSION = 2 PA TCHLEVEL = 6 SUBLEVEL = 35 EXTRA VERSION =3 说明代码版本为2.6.35.3,编译得到的内核在目标板运行后,输入uname -a命令可以得到印证: # uname -a Linux boy 2.6.35.3-571-gcca29a0-gd431b3d-dirty #22 PREEMPT Tue Oct 27 20:12:33 CST 2015 armv5tejl GNU/Linux 2.编译控制 (1)体系结构 Linux是一个支持众多体系结构的操作系统,在编译过程中需指定体系结构,以与实际平台对应。在顶层Makefile中,通过变量ARCH来指定: ARCH ?= $(SUBARCH) 如果没有在编译命令行中指定ARCH参数,系统将会进行本地编译,通过获取本机信息来自动指定: SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ ) 如果进行ARM嵌入式Linux开发,则必须指定ARCH为arm(注意大小写,须与arch/目录下的arm一致),如: $make ARCH=arm 当然,也可以修改Makefile,将修改为ARCH ?= $(SUBARCH)修改为ARCH = arm,在命令行直接make即可。

Linux内核配置编译与文件系统构建

Linux内核配置编译与文件系统构建 南京大学 黄开成101180046 2012.11.11 一:实验目的 1.了解嵌入式系统的开发环境,内核与文件系统的下载和启动; 2.了解Linux内核源代码的目录结构及各自目录的相关内容,了解Linux内核各配置选项内容和作用,掌握Linux内核的编译过程; 3.了解嵌入式操作系统中文件系统的类型和应用、了解JFFS2文件系统的优点及其在嵌入式系统中的作用、掌握利用Busybox软件制作嵌入式文件系统的方法,并且掌握嵌入式Linux文件系统的挂载过程。二:实验环境说明 1.PC机使用openSUSE 14 Enterprise 系统。 2.开发板使用深圳市武耀博德信息技术有限公司生产的基于Inter 的PXA270处理器的多功能嵌入式开发平台EELIOD。 3.PC机通过RS-232串口与开发板相连,在PC机终端上运行minicom 程序构造一个开发板上的终端,用于对开发板的控制。 4.PC机与开发板通过ethernet网络相连接,并可在开发板上通过加载网络文件系统(NFS)与PC机通信。 5.Bootloader可以通过tftp协议从PC机上下载内核镜像和根文件系统镜像。下载目录为/tftpboot 。 6.用于开发板的Linux内核源码为linux-2.4.21-51Board_EDR,

busybox版本为busybox-1.00-pre5。 7.交叉编译器的路径为/usr/local/arm-linux/bin/arm-linux。 三:实验操作过程和分析记录 1.嵌入式系统的开发环境和开发流程: 1.1启动minicom和开发板 在PC机上打开一个终端,输入: >minicom 按Ctrl+A-o进入minicom的configuration界面。对串行通信接口进行配置,串口设置为:/dev/ttyS0(串口线接在PC机的串口1上)、bps=115200、8位数据、无校验、无流控制。 然后打开开发板电源,看到屏幕有反应之后,按任意键进入配置界面,如果长时间没有按下任何键,bootloader将会自动从flash中读取内核和根文件系统并启动开发板上的Linux系统。 分析:嵌入式系统中,通常并没有像PC机中BIOS 那样的固件程序,因此整个系统的加载启动任务完全由bootloader来完成。bootloader的主要作用是:初始化硬件设备;建立内存空间的映射图;完成内核的加载,为内核设置启动参数。 按0进入命令行模式,出现51board>,可以设置开发板和PC机的IP 地址: 51board> set myipaddr 192.168.208.133(设置开发板的IP地址) 51board> set destipaddr 192.168.208.33(设置PC机的IP地址)注意IP地址的设置:使其处于同一网段,并且避免和其他系统的

相关主题
文本预览
相关文档 最新文档