230 likes | 248 Views
Understand uClinux, build instances, explore modules, devices, and drivers, learn to create kernel modules, and dive into device drivers as modules in this comprehensive guide.
E N D
Contents • uClinux • uClinux Introduction • 构建一个uClinux实例 • Modules and device drivers
uClinux Introduction • uClinux • http://www.uclinux.org • A derivative of Linux 2.0 kernel intended for microcontrollers without Memory Management Units (MMUs). • First ported to the Motorola MC68328: DragonBall Integrated Microprocessor
构建一个uClinux实例 • http://www.cyberguard.com/snapgear/tb20020807.html • Emulator: xcopilot • Cross compile tools: m68k-elf-tools • uClinux source codes: uClinux-dist-20030305.tar.gz
xcopilot • A PalmPilot emulator that runs under Unix/X11. • Offers emulation of the timer, serial ports, touch pad and LCD display along with Motorola 68000 emulation (m68k).
m68k-elf-tools • m68k-elf-gcc, m68k-elf-as, m68k-elf-ld, m68k-elf-gdb, … • elf2flt • flat二进制文件的创建工具 • genromfs • rom文件系统的创建工具
Getting/Building the uClinux Source • Get the source codes • Build the source codes • make xconfig • make dep • make
Running uClinux in Xcopilot • mkdir ~/.xcopilot • ln -s `pwd`/images/pilot.rom ~/.xcopilot
Further… • User applications
Modules • Linux引入的机制 • 一些代码能够按照需要被加载到内核中和从内核中卸载 • 扩展了kernel的功能而不需要重新启动系统 • 设备驱动不需要长期驻留在内存中,保持核心非常小
模块和普通函数的区别 • 没有主函数 • init_module(), cleanup_module() • 运行在内核空间 • 只能使用内核提供的函数 • eg. printk vs. printf
A simplest kernel module #include <linux/module.h> /* Needed by all modules */ #include <linux/kernel.h> /* Needed for KERN_ALERT */ int init_module(void) { printk("Hello world.\n"); // A non 0 return means init_module failed; module can't be loaded. return 0; } void cleanup_module(void) { printk(KERN_ALERT "Goodbye world.\n"); }
Makefile for the module TARGET = hello WARN = -W -Wall INCLUDE = -I/lib/modules/`uname -r`/build/include CFLAGS = -O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE} CC = gcc ${TARGET}.o: ${TARGET}.c $(CC) $(CFLAGS) –c hello.c clean: rm -rf ${TARGET}.o
编译模块 • 创建Makefile,运行make • insmod hello.o • 查看模块: • /proc/modules • lsmod, modprobe, modinfo • /var/log/messages • rmmod hello
多文件内核模块 • 编译所有文件 • 连接所有的目标文件到一个模块文件,在x86下: • ld –m elf_i386 –r –o <modulename.o> <1 src file.o> <2 src file.o>
Device drivers • Device drivers as modules • Device regarded as file • struct file_operations (include/linux/fs.h) • 创建设备 • mknod /dev/status c <major_num> 0
定义设备驱动程序提供的函数 struct file_operations status_fops = { NULL, /* seek */ read_ status, write_ status, NULL, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ open_ status, NULL, /* flush */ close_ status, NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_ media_ change */ NULL, /* revalidate */ NULL, /* lock */ };
register_chrdev,unregister_chrdev • register_chrdev(), register_blkdev(): 在内核中注册设备的驱动程序接口 • register_ chrdev(0, "status", &status_ fops); • init_module()中调用 • unregister_chrdev(): 注销驱动程序 • unregister_chrdev(majorNumber, “status”); • cleanup_module()中调用
static int major_ number = 0; int init_ module( void) { major_ number = register_ chrdev( 0, "status", &status_ fops); if (major_ number < 0) { printk( KERN_ WARNING "Dynamic allocation of major failed"); return major_ number; /* return error code */ } printk( KERN_ INFO "Assigned major number %i.\ n", major_ number); return 0; } int cleanup_ module( void) { printk( KERN_ INFO "Unregistering major number %i.\ n", major_ number); unregister_ chrdev( major_ number, "status"); /* give back our number */ return 0; }
static int open_ status( struct inode *inode, struct file *file) { MOD_ INC_ USE_ COUNT; /* ensures that currently used modules aren’t unloaded*/ return 0; } static int close_ status( struct inode *inode, struct file *file) { MOD_ DEC_ USE_ COUNT; /* rmmod won’t run unless USE_ COUNT is 0 */ return 0; }
static char *message = "All your base are belong to us."; static ssize_ t read_ status( struct file *file, char *buffer, size_ t count, loff_ t *ppos) { int char_ count = 0; int count_ to_ copy = 0; while (message[ char_ count] != '\0') { char_ count ++; } count_ to_ copy = (char_ count > count) ? count : char_ count; copy_ to_ user( buffer, message, count_ to_ copy); /* write to the user- space buffer */ return char_ count; }
static ssize_ t write_ status( struct file *file, const char *buffer, size_ t count, loff_ t *ppos) { return -EINVAL; /* we’ve decided not to support writes for now */ }