
必须包含 <linux/init.h>
module_init(your_init_func)
module_exit(your_exit_func)
老版本:int init_module(void)
void cleanup_module(voi)
2.4中两种都可以用,对如后面的入口函数不必要显示包含任何头文件。
2、 GPL
MODULE_LICENSE("Dual BSD/GPL")
老版本:MODULE_LICENSE("GPL")
3、 模块参数
必须显式包含<linux/moduleparam.h>
module_param(name, type, perm)
module_param_named(name, value, type, perm)
参数定义
module_param_string(name, string, len, perm)
module_param_array(name, type, num, perm)
老版本:MODULE_PARM(variable,type)
MODULE_PARM_DESC(variable,type)
4、 模块别名
MODULE_ALIAS("alias-name")
这是新增的,在老版本中需在/etc/modules.conf配置,现在在代码中就可以实现。
5、 模块计数
int try_module_get(&module)
module_put()
老版本:MOD_INC_USE_COUNT 和 MOD_DEC_USE_COUNT
6、 符号导出
只有显示的导出符号才能被其他 模块使用,默认不导出所有的符号,不必使用EXPORT_NO
_SYMBOLS
老板本:默认导出所有的符号,除非使用EXPORT_NO_SYMBOLS
7、 内核版本检查
需要在多个文件中包含<linux/module.h>时,不必定义__NO_VERSION__
老版本:在多个文件中包含<linux/module.h>时,除在主文件外的其他文件中必须定义_
_NO_VERSION__,防止版本重复定义。
8、 设备号
kdev_t被废除不可用,新的dev_t拓展到了32位,12位主设备号,20位次设备号。
unsigned int iminor(struct inode *inode)
unsigned int imajor(struct inode *inode)
老版本:8位主设备号,8位次设备号
int MAJOR(kdev_t dev)
int MINOR(kdev_t dev)
9、 内存分配头文件变更
所有的内存分配函数包含在头文件<linux/slab.h>,而原来的<linux/malloc.h>不存在
老版本:内存分配函数包含在头文件<linux/malloc.h>
10、 结构体的初试化
gcc开始采用ANSI C的struct结构体的初始化形式:
static struct some_structure = {
.field1 = value,
.field2 = value,
..
}
老版本:非标准的初试化形式
static struct some_structure = {
field1: value,
field2: value,
..
}
11、 用户模式帮助器
int call_usermodehelper(char *path, char **argv, char **envp,
int wait)
新增wait参数
12、 request_module()
request_module("foo-device-%d", number)
老版本:
char module_name[32]
printf(module_name, "foo-device-%d", number)
request_module(module_name)
13、 dev_t引发的字符设备的变化
1、取主次设备号为
unsigned iminor(struct inode *inode)
unsigned imajor(struct inode *inode)
2、老的register_chrdev()用法没变,保持向后兼容,但不能访问设备号大于256的设备
。
3、新的接口为
a)注册字符设备范围
int register_chrdev_region(dev_t from, unsigned count, char *name)
b)动态申请主设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char
*name)
看了这两个函数郁闷吧^_^!怎么和file_operations结构联系起来啊?别急!
c)包含 <linux/cdev.h>,利用struct cdev和file_operations连接
struct cdev *cdev_alloc(void)
void cdev_init(struct cdev *cdev, struct file_operations *fops)
int cdev_add(struct cdev *cdev, dev_t dev, unsigned count)
(分别为,申请cdev结构,和fops连接,将设备加入到系统中!好复杂啊!)
d)void cdev_del(struct cdev *cdev)
只有在cdev_add执行成功才可运行。
e)辅助函数
kobject_put(&cdev->kobj)
struct kobject *cdev_get(struct cdev *cdev)
void cdev_put(struct cdev *cdev)
这一部分变化和新增的/sys/dev有一定的关联。
14、 新增对/proc的访问 *** 作
<linux/seq_file.h>
以前的/proc中只能得到string, seq_file *** 作能得到如long等多种数据。
相关函数:
static struct seq_operations 必须实现这个类似file_operations得数据中得各个成
员函数。
seq_printf();
int seq_putc(struct seq_file *m, char c)
int seq_puts(struct seq_file *m, const char *s)
int seq_escape(struct seq_file *m, const char *s, const char *esc)
int seq_path(struct seq_file *m, struct vfsmount *mnt,
struct dentry *dentry, char *esc)
seq_open(file, &ct_seq_ops)
等等
15、 底层内存分配
1、<linux/malloc.h>头文件改为<linux/slab.h>
2、分配标志GFP_BUFFER被取消,取而代之的是GFP_NOIO 和 GFP_NOFS
3、新增__GFP_REPEAT,__GFP_NOFAIL,__GFP_NORETRY分配标志
4、页面分配函数alloc_pages(),get_free_page()被包含在<linux/gfp.h>中
5、对NUMA系统新增了几个函数:
a) struct page *alloc_pages_node(int node_id,
unsigned int gfp_mask,
unsigned int order)
b) void free_hot_page(struct page *page)
c) void free_cold_page(struct page *page)
6、 新增Memory pools
<linux/mempool.h>
mempool_t *mempool_create(int min_nr,
mempool_alloc_t *alloc_fn,
mempool_free_t *free_fn,
void *pool_data)
void *mempool_alloc(mempool_t *pool, int gfp_mask)
void mempool_free(void *element, mempool_t *pool)
int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask)
16、 per-CPU变量
get_cpu_var()
put_cpu_var()
void *alloc_percpu(type)
void free_percpu(const void *)
per_cpu_ptr(void *ptr, int cpu)
get_cpu_ptr(ptr)
put_cpu_ptr(ptr)
老版本使用
DEFINE_PER_CPU(type, name)
EXPORT_PER_CPU_SYMBOL(name)
EXPORT_PER_CPU_SYMBOL_GPL(name)
DECLARE_PER_CPU(type, name)
DEFINE_PER_CPU(int, mypcint)
2.6内核采用了可剥夺得调度方式这些宏都不安全。
17、 内核时间变化
1、现在的各个平台的HZ为
Alpha: 1024/1200ARM : 100/128/200/1000CRIS: 100i386: 1000IA-64:
1024M68K: 100M68K-nommu: 50-1000MIPS: 100/128/1000MIPS64: 100
PA-RISC: 100/1000PowerPC32: 100PowerPC64: 1000S/390: 100SPARC32:
100SPARC64: 100SuperH: 100/1000UML: 100v850: 24-100x86-64: 1000.
2、由于HZ的变化,原来的jiffies计数器很快就溢出了,引入了新的计数器jiffies_64
3、#include <linux/jiffies.h>
u64 my_time = get_jiffies_64()
4、新的时间结构增加了纳秒成员变量
struct timespec current_kernel_time(void)
5、他的timer函数没变,新增
void add_timer_on(struct timer_list *timer, int cpu)
6、新增纳秒级延时函数
ndelay();
7、POSIX clocks 参考kernel/posix-timers.c
18、 工作队列(workqueue)
1、任务队列(task queue )接口函数都被取消,新增了workqueue接口函数
struct workqueue_struct *create_workqueue(const char *name)
DECLARE_WORK(name, void (*function)(void *), void *data)
INIT_WORK(struct work_struct *work,
void (*function)(void *), void *data)
PREPARE_WORK(struct work_struct *work,
void (*function)(void *), void *data)
2、申明struct work_struct结构
int queue_work(struct workqueue_struct *queue,
struct work_struct *work)
int queue_delayed_work(struct workqueue_struct *queue,
struct work_struct *work,
unsigned long delay)
int cancel_delayed_work(struct work_struct *work)
void flush_workqueue(struct workqueue_struct *queue)
void destroy_workqueue(struct workqueue_struct *queue)
int schedule_work(struct work_struct *work)
int schedule_delayed_work(struct work_struct *work, unsigned long
delay)
19、 新增创建VFS的"libfs"
libfs给创建一个新的文件系统提供了大量的API.
主要是对struct file_system_type的实现。
参考源代码:
drivers/hotplug/pci_hotplug_core.c
drivers/usb/core/inode.c
drivers/oprofile/oprofilefs.c
fs/ramfs/inode.c
fs/nfsd/nfsctl.c (simple_fill_super() example)
linux的uboot启动映像、zImage和uImage的区别
uboot启动zImage(go)和uImage(bootm)分析
1.bootm加载linux镜像是加载uIamge,uIamge是由mkimage制作而来,和zIamge的差异是uIamge是zIamge压缩过的,bootm需要先对uIamge解压,解压地址为内核入口地址。当解压完成时uIamge和zIamge几乎是相同的,具体差异可以论述。uboot目前只能支持uImage启动,不支持zImage启动
2.bootm解压过程
---------------------------------------------------------------------------
## Booting image at 08808000 ...
Image Name: Linux-2.6.14.7
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 989172 Bytes = 966 kB
Load Address: 08008000
Entry Point: 08008000
Verifying Checksum ... OK
OK uboot bootm命令对uIamge的解压 *** 作
---------------------------------------------------------------------------
Starting kernel ...
传递内核参数将控制权交给arch\arm\boot\compressed]head.S
----------------------------------------------------------------------------
如mx1ADS班子内存的起始地址为0x0800_0000,通过tftp 下载到0x0800_8000 +offset ,offset大于0x80_0000,即tftp 0x0880_8000 然后bootm 0x0880_8000 即将0x0880_8000处的uIamge解压,解压地址即为mkimage 设置的kernel入口地址0x0800_8000。
zImage和uImage的区别一、vmlinuzvmlinuz 是可引导的、压缩的内核。“vm”代表“Virtual Memory”。Linux 支持虚拟内存,不像老的 *** 作系统比如DOS有640KB内存的限制。Linux能够使用硬盘空间作为虚拟内存,因此得名“vm”。
vmlinuz 的建立有两种方式。一是编译内核时通过“make zImage”创建,然后通过:“cp /usr/src/linux-2.4/arch/i386/linux/boot/zImage/boot/vmlinuz”产生。zImage适用于 小内核的情况,它的存在是为了向后的兼容性。
二 是内核编译时通过命令make bzImage创建,然后通过:“cp/usr/src/linux-2.4/arch/i386/linux/boot/bzImage /boot/vmlinuz”产生。bzImage是压缩的内核映像,需要注意,bzImage不是用bzip2压缩的,bzImage中的bz容易引起 误解,bz表示“big zImage”。 bzImage中的b是“big”意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有 gzip解压缩代码。所以你不能用gunzip 或 gzip –dc解包vmlinuz。
二、 initrd-x.x.x.img
initrd是“initial ramdisk”的简写。initrd一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态。
initrd 映象文件是使用mkinitrd创建的。mkinitrd实用程序能够创建initrd映象文件。这个命令是RedHat专有的。其它Linux发行版或 许有相应的命令。这是个很方便的实用程序。具体情况请看帮助:man mkinitrd下面的命令创建initrd映象文件。
最后生成的内核镜象有两种zImage以及uImage。其中zImage下载到 目标板中后,可以直接用uboot的 命令go来 进行直接跳转。这时候内核直接解压启动。但是无法挂载文件系统,因为go命令没有将内核需要的相关的启动参数传递给内核。传递启动参数我们必须使用命令bootm来进行跳 转。Bootm命 令跳转只处理uImage的 镜象。
uboot源代码的tools/目录下 有mkimage工 具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。
mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头, 记录参数所指定的信息,这样uboot才 能识别这个映象是针对哪个CPU体 系结构的,哪个OS的, 哪种类型,加载内存中的哪个位置,入口点在内存的那个位置以及映象名是什么
用法如下:
./mkimage -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
-A ==>set architecture to 'arch'
-O ==>set operating system to 'os'
-T ==>set image type to 'type'
-C ==>set compression type 'comp'
-a ==>set load address to 'addr' (hex)
-e ==>set entry point to 'ep' (hex)
-n ==>set image name to 'name'
-d ==>use image data from 'datafile'
-x ==>set XIP (execute in place)
参数说明:
-A 指定CPU的体系结构:
取值表示的体 系结构
alpha Alpha
arm A RM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64 Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64 Bit
m68k MC68000
-O 指定 *** 作系统类 型,可以取以下值:
openbsd、netbsd、freebsd、4_4bsd、linux、svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos
-T 指定映象类型, 可以取以下值:
standalone、kernel、ramdisk、multi、firmware、script、filesystem
-C 指定映象压缩方 式,可以取以下值:
none 不 压缩
gzip 用gzip的压缩方式
bzip2 用bzip2的压缩方 式
-a 指 定映象在内存中的加载地址,映象下载到内存中时,要按照用mkimage制作映象时,这个参数所指定的地址值来下载
-e 指定映象运行的 入口点地址,这个地址就是-a参 数指定的值加上0x40(因 为前面有个mkimage添 加的0x40个 字节的头)
-n 指定映象名
-d 指定制作映象的源文件
我在编译时用到的命令如下:
# make zImage //生成zImage镜象
#/usr/local/arm/k9uboot/tools/mkimage -n 'Linux 2.4.27' -A arm -O linux -T
kernel -C none -a 0x20007fc0 -e 0x20008000 -d zImage uImage
内核镜象已经准备好了,这个时候我们就要来准备文件系统了。由于时间缘故,本人暂时采用的是其他 人已经好的文件系统k9.img.gz。 这个时候我们要做的是,自己写一个简单hello.c的程序,编译通过后加入到该文件系统中,然后下载到目标板中运行。
先编写hello.c;
编译:
#/usr/local/arm/2.95.3/bin/arm-linux-gcc –o start-hello hello.c
编译后生成可执行文件start-hello
下面我们就必须把该执行文件加入到文件系统中去,步骤如下:
#gunzip k9.img.gz //解 压缩
#mount –o loop k9.img /mnt/new_disk //挂载
#cp start-hello /mnt/new_disk //将 文件拷贝到文件系统中
#cd /mnt/new_disk
#umount /mnt/new_disk //卸 载
#gzip –c –v9 k9.img >k9.img.gz //压缩生成最终的文件系统
下面我们就要下载内核以及准备好文件系统了,这边先说明我 的内存分配情况如下:
Flash:
0x10000000 ――― 0x10020000 boot
0x10020000 ――― 0x10040000 uboot
0x10040000 ――― 0x10060000 uboot env
0x10060000 ――― 0x10200000 kernel
0x10200000 ――― 0x11000000 ramdisk
Sdram:
0x20007fc0 ――― 0x20a00000 kernel
0x20a00000 ――― ramdisk
Loadb 通过串口下载数据到ram中
cp.b 拷贝ram中的数据到flash中。
将kernel以及文件系统ramdisk下载完 毕之后,我们还需要设置uboot的 环境变量,这样uboot才 能够在上电启动的时候启动内核等 *** 作。环境变量设置如下:
Set cpfltoram cp.b 10200000 20a00000 18ffff //拷贝文件系统到ram中
Set boot bootm 20007fc0 //启动kernel
Set bootcmd run cpfltoker\run cpfltoram\run boot //uboot复位的执行指令
Set cpfltoker cp.b 10060000 20007fc0 f4fff //拷贝内核到ram中
Set bootargs root=/dev/ram rw initrd=0x20a00000,4M init=/linuxrc console=ttyS0,11520
0,mem=32m //uboot传 递给内核的启动参数
设置完毕后,saveenv把 环境变量存储起来。
学习心得:zImage 和uImage 都是生成的可执行内核镜像文件
2者在u-boot中启动的方式分别是 go addr 与 bootm addr 来实现启动过程的
即对于zImage是通过 go 来进行引导 而uImage是通过bootm来进行引导的
zImage 和 uImage 2者的关系 是 uImage 是zImage通过mkimage (u--boot下面tools下的工具)来生成的
结果是后者比前者在头部多了64个byte,这多余的64 个byte是用来通知给u-boot用的;将相关信息告知u-boot
这样做的结果在u-boot引导内核时存在2个地址:loadaddress 和entry address 2者的差值刚好是0x40(64byte)的大小
这样在使用bootm loadaddress 时u-boot会根据相应的loadaddress进行调整,有2中情况;
1)、当loadaddress与mkimage时传送的一致时:
那么在加载 ldr pc,entry address时,会选择mkinage 时的entry地址;即pc=loadaddress + 4然后由pc来控制流程跳转倒ram中去执行;
2)、当loadaddress与mkimage时传送的不一致时:
那么,u-bbot会进行地址比较 后,将当前的loadaddress减去64byte后,将真正的内核映像(去掉64byte头部的内核)拷贝倒预先制定的loadaddress,然后 直接从这个loadaddress来引导内核运行;
总结,那么上面2中情况实际区别呢?其实就是最终代码执行时,如果地址与mkinage时指定的 不符,那么u-boot将进行去头后,拷贝内核代码,直接执行;而如果不处理,则会将 loadaddress+0x40来执行内核;
通过tftp服务来下载 zImage或者uImage;
loadb 在tftp不成功的情况下使用 串口来下载内核 希望不要用这个方法
cp【.b\.w\.l】 完成 内存之间 内存向flash之间进行拷贝
最后可以设置 bootcmd 环境变量可以实现 u-boot自动引导内核启动
至于文件系统的2中方式:ramdisk 以及nfs 推荐开发者使用nfs 方便修改;
当使用ramdisk时,
#gunzip k9.img.gz //解压缩
#mount –o loop k9.img /mnt/new_disk //挂 载
#umount /mnt/new_disk //卸载
#gzip –c –v9 k9.img >k9.img.gz //压 缩生成最终的文件系统
这四条命令不要忘记,对于你来说多么强大
不要你去再建立根文件系统。
Linux 是一个开放自由的 *** 作系统内核,具有一些鲜明特点如下:(1) Linux 是一个一体化内核;
注:“一体化内核”是也称“宏内核”,是相对于“微内核”而言的。几乎所有
的嵌入式和实时系统都采用微内核,如 VxWorks、uC/OS-II、PSOS 等。
(2) 可移植性强。尽管 Linus 最初只为在 X86 PC 上实现一个“类 UNIX”,后来随
着加入者的努力,Linux 目前已经成为支持硬件平台最广泛的 *** 作系统;
注:目前已经在 X86、IA64、ARM、MIPS、AVR32、M68K、S390、Blackfin、M32R
等众多架构处理器上运行。
(3) 是一个可裁剪 *** 作系统内核。Linux 极具伸缩性,内核可以任意裁剪,可以大至
几十或者上百兆,可以小至几百 K,运行的设备从超级计算机、大型服务器到
小型嵌入式系统、掌上移动设备或者嵌入式模块,都可以运行;
(4) 模块化。Linux 内核采用模块化设计,很多功能模块都可以编译为模块,可以在
内核运行中动态加载/卸载而无需重启系统;
(5) 网络支持完善。Linux 内核集成了完整的 POSIX 网络协议栈,网络功能完善;
(6) 稳定性强。运行 Linux 的内核的服务器可以做到几年不用复位重启;
(7) 安全性好。Linux 源码开放,由众多黑客参与 Linux 的开发,一旦发现漏洞都能及时修复;
(8) 支持的设备广泛。Linux 源码中,设备驱动源码占了很大比例,几乎能支持任何
常见设备,无论是很老旧的设备还是最新推出的硬件设备,几乎都能找到 Linux下的驱动。致远电子那边有很多的,你可以去看一下
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)