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,又叫超级进程(代码片段

Linux防火墙基础与编写防火墙规则

Linux内核的启动流程之基础概念

linuxshell基础知识

linux shell 基础

你为什么看不懂Linux内核驱动源码?