LINUX 内核编写基础
Posted zengkefu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LINUX 内核编写基础相关的知识,希望对你有一定的参考价值。
http://blog.chinaunix.net/uid-20564848-id-73208.html
内核文档:
[[email protected] Documentation]# pwd /usr/src/kernels/linux-2.6.32/Documentation [[email protected] Documentation]# ls 00-INDEX i2o parport.txt ABI ia64 PCI accounting ics932s401 pcmcia acpi ide pi-futex.txt aoe infiniband pnp.txt applying-patches.txt initrd.txt power arm input powerpc atomic_ops.txt Intel-IOMMU.txt pps auxdisplay intel_txt.txt prctl bad_memory.txt ioctl preempt-locking.txt basic_profiling.txt io-mapping.txt printk-formats.txt binfmt_misc.txt IO-mapping.txt prio_tree.txt blackfin io_ordering.txt rbtree.txt block iostats.txt RCU blockdev IPMI.txt rfkill.txt braille-console.txt IRQ-affinity.txt robust-futex-ABI.txt bt8xxgpio.txt irqflags-tracing.txt robust-futexes.txt btmrvl.txt IRQ.txt rtc.txt BUG-HUNTING isapnp.txt rt-mutex-design.txt c2port.txt isdn rt-mutex.txt cachetlb.txt ja_JP s390 cdrom java.txt SAK.txt cgroups kbuild scheduler Changes kdump scsi CodingStyle kernel-doc-nano-HOWTO.txt SecurityBugs connector kernel-docs.txt SELinux.txt console kernel-parameters.txt serial cpu-freq keys-request-key.txt serial-console.txt cpu-hotplug.txt keys.txt sgi-ioc4.txt cpuidle kmemcheck.txt sgi-visws.txt cpu-load.txt kmemleak.txt sh cputopology.txt kobject.txt slow-work.txt credentials.txt ko_KR SM501.txt cris kprobes.txt Smack.txt crypto kref.txt sound dcdbas.txt kvm sparc debugging-modules.txt laptops sparse.txt debugging-via-ohci1394.txt ldm.txt spi dell_rbu.txt leds-class.txt spinlocks.txt development-process leds-lp3944.txt stable_api_nonsense.txt device-mapper lguest stable_kernel_rules.txt devices.txt local_ops.txt SubmitChecklist DMA-API.txt lockdep-design.txt SubmittingDrivers DMA-attributes.txt lockstat.txt SubmittingPatches dmaengine.txt logo.gif svga.txt DMA-ISA-LPC.txt logo.txt sysctl DMA-mapping.txt m68k sysfs-rules.txt DocBook magic-number.txt sysrq.txt dontdiff make telephony driver-model Makefile thermal dvb ManagementStyle timers dynamic-debug-howto.txt mca.txt tomoyo.txt early-userspace md.txt trace edac.txt memory-barriers.txt uml eisa.txt memory-hotplug.txt unaligned-memory-access.txt email-clients.txt memory.txt unicode.txt fault-injection mips unshare.txt fb misc-devices usb feature-removal-schedule.txt mn10300 vgaarbiter.txt filesystems mono.txt VGA-softcursor.txt firmware_class mtd video4linux flexible-arrays.txt mutex-design.txt video-output.txt frv namespaces vm futex-requeue-pi.txt netlabel volatile-considered-harmful.txt gcov.txt networking voyager.txt gpio.txt nmi_watchdog.txt w1 highuid.txt nommu-mmap.txt watchdog HOWTO numastat.txt wimax hwmon oops-tracing.txt x86 hw_random.txt parisc zh_CN i2c parport-lowlevel.txt zorro.txt
内核书籍:
LDK:LINUX内核设计与实现
ULK:深入理解LINUX内核
LDD:LINUX 设备驱动程序
LVMM:深入理解LINUX 虚拟内存管理
深入理解LINUX网络内幕
内核社区: http://vger.kernel.org/vger-lists.html#linux-kernel http://dir.gmane.org/gmane.linux.usb.general https://www.kernel.org/
http://linux.chinaunix.net/
printk小结 1 printk 消息级别定义 #define KERN_EMERG "<0>" /*紧急事件,一般是系统崩溃之前的提示消息*/ #define KERN_ALERT "<1>" /*必须立即采取行动*/ #define KERN_CRIT "<2>" /*临界状态,通常涉及严重的硬件或者软件操作失败*/ #define KERN_ERR "<3>" /*用于报告错误状态,设备驱动会经常使用KERN_ERR来报告硬件错误*/ #define KERN_WARNING "<4>" /*对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重问题 */ #define KERN_NOTICE "<5>" /*有必要进行提示的正常情形,许多与安全相关的状况用这个级别进行汇报*/ #define KERN_INFO "<6>" /*内核提示性信息,很多驱动程序在启动的时候以这个级别打印找到的硬件信息*/ #define KERN_DEBUG "<7>" /*用于调试信息*/ 2 使用方法 printk(KERN_ALERT "XXXXXX",XXXX); 3 /proc/sys/kernel/printk 该文件可以调节printk的输出等级,文件中有四个数字值。 (1) 控制台日志级别:优先级高于该值的消息将被打印至控制台。 (2) 默认的消息日志级别:用该优先级来打印未定义优先级的消息。 (3) 最低的控制台日志级别:控制台日志界别可被设置的最小值。 (4) 默认的控制台日志级别:控制台日志级别的默认值。
4 通过如下命令可以使得Linux内核的任何printk都被输出到控制台 #echo 8 > /proc/sys/kernel/printk
5. cat /proc/kmsg
这个文件用于检索用printk生成的内核消息。任何时刻只能有一个具有超级用户权限的进程可以读取这个文件。也可以用系统调用syslog检索这些消息。
通常使用工具dmesg或守护进程klogd检索这些消息。
hello.c 内核模块编绎 #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> static int init_hello_4(void) { printk(KERN_ALERT "Hello, world 4 "); return 0; } static void cleanup_hello_4(void) { printk(KERN_ALERT "Goodbye, world 4 "); } module_init(init_hello_4); module_exit(cleanup_hello_4); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Playmud"); MODULE_DESCRIPTION("Test only!");
配置Makefile和执行ko编译
[[email protected] ~]# echo "obj-m:=hello.o" > Makefile
[[email protected] ~]# make -C /lib/modules/`uname -r`/build M=`pwd` modules
make: Entering directory `/usr/src/kernels/2.6.32-431.23.3.el6.x86_64‘
Building modules, stage 2.
MODPOST 1 modules
make: Leaving directory `/usr/src/kernels/2.6.32-431.23.3.el6.x86_64‘
/lib/modules/`uname -r`/build
就是本地机子的module编译配置目录 不是为正在运行的内核编译模块: make -C M=`pwd`
为正在运行的内核编译模块: make -C /lib/modules/`uname -r`/build M=`pwd` modules
printk没有在console上打印出提示,通过
[[email protected] ~]# dmesg |tail -1
Hello, world
可以查到,具体配置可以查看
vim /etc/syslog.conf
sysrq 常使用的魔术键: echo 1>/proc/sys/kernel/sysrq 打开sysrq功能 echo ‘t‘ >/proc/sysrq-trigger 打印进程栈,调试时很有用 echo ‘c‘ >/proc/sysrq-trigger 常常用来测试dump模式
printk打印不能显示到终端的问题 【原型】 int printk(const char * fmt,…); 【示例】 与大多数展示printf的功能一样,我们也用一个helloworld的程序来演示printk的输出: 编写一个内核模块: #include #include #if CONFIG_MODVERSIONS==1 #define MODVERSIONS #include #endif MODULE_LICENSE("GPL"); int init_module() { printk("hello.word-this is the kernel speaking\n"); return 0; } void cleanup_module() { printk("Short is the life of a kernel module\n"); } 保存为文件hello.c 编写一个Makefile: CC=gcc MODCFLAGS:=-O6 -Wall -DMODULE -D__KERNEL__ -DLINUX hello.o:hello.c /usr/include/linux/version.h $(CC) $(MODCFLAGS) -c hello.c echo insmod hello.o to turn it on 保存为文件Makefile 执行make 我们可以看到生成了一个hello.o的内核模块,我们想通过这个模块在插入内核的时候输出 "hello.word-this is the kernel speaking" 这样一条信息。 然后我们开始: [[email protected] root]# insmod hello.o [[email protected] root]# 并没有输出任何消息。why? 这也是printf和printk的一个不同的地方 用printk,内核会根据日志级别,可能把消息打印到当前控制台上,这个控制台通常是一个字符模式的终端、一个串口打印机或是一个并口打印机。这些消息正常输出的前提是──日志输出级别小于console_loglevel(在内核中数字越小优先级越高)。 没有指定日志级别的printk语句默认采用的级别是 DEFAULT_ MESSAGE_LOGLEVEL(这个默认级别一般为<4>,即与KERN_WARNING在一个级别上),其定义在linux26/kernel/printk.c中可以找到 日志级别一共有8个级别,printk的日志级别定义如下(在include/linux/kernel.h中): #define KERN_EMERG 0 #define KERN_ALERT 1 #define KERN_CRIT 2 #define KERN_ERR 3 #define KERN_WARNING 4 #define KERN_NOTICE 5 #define KERN_INFO 6 #define KERN_DEBUG 7 现在我们来修改hello.c程序,使printk的输出级别为最高: printk("<0>""hello.word-this is the kernel speaking\n"); 然后重新编译hello.o,并插入内核: [[email protected] root]# insmod hello.o [[email protected] root]# Message from [email protected] at Sat Aug 15 05:32:22 2009 ... localhost kernel: hello.word-this is the kernel speaking hello,world信息出现了。 其实printk始终是能输出信息的,只不过不一定是到了终端上。我们可以去 /var/log/messages这个文件里面去查看。 如果klogd没有运行,消息不会传递到用户空间,只能查看/proc/kmsg 通过读写/proc/sys/kernel/printk文件可读取和修改控制台的日志级别。查看这个文件的方法如下: #cat /proc/sys/kernel/printk 6 4 1 7 上面显示的4个数据分别对应控制台日志级别、默认的消息日志级别、最低的控制台日志级别和默认的控制台日志级别。 可用下面的命令设置当前日志级别: # echo 8 > /proc/sys/kernel/printk 这样所有级别<8,(0-7)的消息都可以显示在控制台上.
以上是关于LINUX 内核编写基础的主要内容,如果未能解决你的问题,请参考以下文章
LINUX PID 1和SYSTEMD PID 0 是内核的一部分,主要用于内进换页,内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程,PID 为 1,又叫超级进程(代码片段