Kernel entry driver - helloword module

1. Understanding Linux Kernel Programming
      1. Linux is a "monolithic kernel" operating system, which means that the entire system kernel runs in a single protection domain, but the linux kernel is modular, which allows the kernel to dynamically insert or Remove the code from it. Modules allow us to easily remove and reload kernel code;
       2. The particularity of kernel programming:
       A. Kernel programming is very different from traditional application programming is the issue of concurrency. Most applications are a notable exception, typically run sequentially, from start to finish, without worrying that something else will happen to change their Environment. Kernel code does not run in such a simple world, and even the simplest kernel modules must be written with such a concept, and many things can happen at once.
       B. We cannot call some functions provided by glibc when writing the kernel driver module, such as printf(), malloc(), etc. At this time, we need to call the corresponding functions defined in the Linux kernel, such as printk(), kmalloc(), etc.;
        C. The application exists in virtual memory and has a very large stack area and stack, whereas the kernel, in contrast, has only a very small stack; it may be as small as one, 4096-byte page. Your function must be associated with the entire Kernel space call chains share this stack. Therefore, if you need to store a large structure, you should allocate it dynamically at call time.
         D. When we are writing an application, if the pointer is wrong, it will only cause the process to exit without affecting other processes; and if an illegal address access occurs when writing a Linux kernel module, the entire system will die; so when writing the kernel code need to be extra careful;
          E. When you look at the kernel API, you will come across function names starting with a double underscore (__). A function name marked like this is usually a low-level interface component and should be used with care.

2. hello kernel module
    1. Write the hello module
  
[a4729821@JYstd driver]$ vim kernel_hello.c

 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>

static __init int hello_init(void)
{
     printk(KERN_ALERT "HELLO, lingyun IoT Studio!\n");
    return 0;
 }

 static __exit void hello_exit(void)
 {
     printk(KERN_ALERT  "Goodbye, I have found a good job!\n");

 }

module_init(hello_init);
 module_exit(hello_exit);


Code Analysis:
   1. _init attribute: A large part of the linux kernel is the driver function, and these functions only need to be executed once. Linux adds the _init attribute to functions that only need to be executed once.
                          The purpose is to put the initialization function of the driver module into the input section named .init.text. When the kernel is started, the memory in this segment will be released for other uses.
  2. _exit attribute: If the driver is compiled into the kernel, the __exit macro will ignore the cleanup function, because the module compiled into the kernel does not need to do cleanup work.
  3.module_init macro: almost every linux driver has a module_init, which is defined in linux/Init.h. The loading of the driver depends on it. module_init(hello_init) means to load the hello_init() function into the ".initcall" area of ​​the kernel image. When the kernel is loaded, all functions in ".initcall" will be searched by priority and executed in sequence.
4.module_exit macro: Also defined in /linux/init.h, this function will be called when the driver is uninstalled using the rmmod command.
5.printk() function: use the printk() function to print information in the driver.
3. Test the module on the pc
[a4729821@JYstd driver]$ mkdir x86
[a4729821@JYstd x86]$ vim Makefile

+ Makefile                                                                  
  1 KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
  2 PWD := $(shell pwd)
  3 obj-m := kernel_hello.o
  4
  5 modules:
  6      $(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules
  7      @make clear
  8
  9 clear:
10 @rm -f * .o * .cmd * .mod.c
11      @rm -rf  *~ core .depend  .tmp_versions Module.symvers modules.     
    order -f
12 @rm -f.*Ko.cmd.*. O.cmd.*. Od
13      @rm -f *.unsigned
14
15 clean:
16 @rm -f hello.ko
17
18
                          
dmesg view the printing information of the Linux kernel, dmesg -c will clear the printing information of the previous Linux kernel
[a4729821@JYstd x86]$ sudo dmesg
Initializing cgroup subsys cpuset
Initializing cgroup subsys cpu
Linux version 2.6.32-696.el6.x86_64 ( [email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC) ) #1 SMP Tue Mar 21 19:29:05 UTC 2017
Command line: ro root=UUID=ef8d9755-a3ab-442b-84a7-a99d713b6336 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
KERNEL supported cpus:
  Intel GenuineIntel
  AMD AuthenticAMD
  Centaur CentaurHauls
Disabled fast string operations
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009ec00 (usable)
BIOS-e820: 000000000009ec00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000dc000 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 000000007fee0000 (usable)
BIOS-e820: 000000007fee0000 - 000000007feff000 (ACPI data)
BIOS-e820: 000000007feff000 - 000000007ff00000 (ACPI NVS)
BIOS-e820: 000000007ff00000 - 0000000080000000 (usable)
BIOS-e820: 00000000f0000000 - 00000000f8000000 (reserved)
BIOS-e820: 00000000fec00000 - 00000000fec10000 (reserved)
BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved)
BIOS-e820: 00000000fffe0000 - 0000000100000000 (reserved)

************

[a4729821@JYstd x86]$ sudo insmod kernel_hello.ko      //安装Linux内核模块,并查看内核的打印信息:
[a4729821@JYstd x86]$ dmesg
HELLO, lingyun IoT Studio!

[a4729821@JYstd x86]$ sudo lsmod | grep kernel_hello.     //lsmod命令查看当前linux内核安装了的内核模块
kernel_hello             891  0

[a4729821@JYstd x86]$ sudo rmmod kernel_hello               //rmmod将会删除linux内核安装了的内核模块
[a4729821@JYstd x86]$ dmesg
HELLO, lingyun IoT Studio!
Goodbye, I have found a good job!



四。在ARM 上测试内核模块
[a4729821@JYstd driver]$ vim makefile


  1 LINUX_SRC = ${shell pwd}/../linux/linux-3.0/
  2 CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
  3 INST_PATH=/tftp
  4 PWD := $(shell pwd)
+ makefile                                                                                
  5 EXTRA_CFLAGS+=-DMODULE
  6 obj-m += kernel_hello.o
  7
  8 modules:
  9      @make -C $(LINUX_SRC) M=$(PWD) modules
10      @make clear
11
12 uninstall:
13       rm -f ${INST_PATH}/*.ko
14
15 install: uninstall
16      cp -af *.ko ${INST_PATH}
17
18 clear:
19     @rm -f *.o *.cmd *.mod.c
20      @rm -rf  *~ core .depend  .tmp_versions Module.symvers modules.order -f
  1       @rm -f .*ko.cmd .*.o.cmd .*.o.d
22
23 clean: clear
24      @rm -f  *.ko


[4729821@JYstd driver]$ make
关于Makefile 文件说明
1,LINUX_SRC  应该指定开发板所运行的Linux内核源码的路径,并且这个linux内核源码必须make menuconfig并且make过的,因为Linux内核的一个模块可能依赖另外一个模块,如果另外一个没有 编译则会出现问题。所以Linux内核必须编译过,这样才能确认这种依赖关系; 
2, 交叉编译器必须使用 CROSS_COMPILE  变量指定;
 3, 如果编译Linux内核需要其它的一些编译选项,那可以使用 EXTRA_CFLAGS 参数来指定;
 4, obj-m += kernel_hello.o   该行告诉Makefile要将  kernel_hello.c 源码编译生成内核模块文件 kernel_hello.ko ;
5, @make -C $(LINUX_SRC) M=$(PWD) modules  @ make是不打印这个命令本身  -C:把工作 目录切换到-C后面指定的参数目录,M是Linux内核源码Makefile里面的一个变量,作用是回到当前 目录继续读取Makefile。当使用make命令编译内核驱动模块时,将会进入到 KERNEL_SRC 指定的 Linux内核源码中去编译,并在当前目录下生成很多临时文件以及驱动模块文件kernel_hello.ko;
 6, clear  目标将编译linux内核过着产生的一些临时文件全部删掉;

开发板测试:
~ >: tftp -gr kernel_hello.ko 192.168.1.8
tftp: sendto: Network is unreachable
开发板与PC网络通信没有建立
原因有:
PC网络IP没有设置对,与开发板不处于一个网端中
~ >: ifconfig
eth0      Link encap:Ethernet  HWaddr 06:2F:5F:90:A4:68  
          inet addr:192.168.2.10  Bcast:192.168.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:16 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1624 (1.5 KiB)  TX bytes:0 (0.0 B)
          Interrupt:51 Base address:0x2300
重新修改PC的IP 与命令
~ >: tftp -gr kernel_hello.ko 192.168.2.55
kernel_hello.ko      100% |*******************************| 23718   0:00:00 ETA
~ >: lsmod
~ >: insmod kernel_hello.ko
HELLO, lingyun IoT Studio!
~ >: lsmod
kernel_hello 561 0 - Live 0xbf000000
~ >: rmmod kernel_hello
Goodbye, I have found a good job!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324719731&siteId=291194637