(整理中)01 - 模块机制

---- 整理自 王利涛老师 课程

文章目录

1. 可加载模块

1.1 Linux内核的模块机制

  • LKM:Loadable Kernel Module
    • 内核模块化、高度可定制化和可裁剪
    • 适配不同的架构、硬件平台
    • 支持运行时动态加载或卸载一个模块
    • 不需要重新编译、重启内核

1.2 实验:hello模块

  • 目标:一个内核模块的编译和运行,动态加载和卸载
  1. 新建 hello.c 文件,内容如下:
#include <linux/init.h>
#include <linux/module.h>static int __init hello_init(void)
{printk("Hello world\n");return 0;
}static void __exit hello_exit(void)
{printk("Goodbye world\n");
}module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("uuxiang");
.PHONY : all cleanobj-m := hello.oEXTRA_CFLAGS += -DDEBUG
# KDIR := ${PWD}/../../linux-5.10.4all:make -C $(KDIR) M=$(PWD) modules
# clean:
# 	make -C $(KDIR) M=$(PWD) modules cleanclean:@rm -rf *.o *~ .depend .*.cmd  *.mod *.mod.c .tmp_versions *.ko *.symvers modules.order
  1. 到代码根目录进入build目录下:
    sudo cmake …
    sudo make kernel drivers rootfs
  2. 到代码根目录下进入out目录下:
    sudo ./start.sh
    得到实验结果:
    [root@vexpress drivers]# pwd
    /my_data/drivers
    [root@vexpress drivers]# ls
    hello.ko
    [root@vexpress drivers]# insmod hello.ko
    hello: loading out-of-tree module taints kernel.
    hello: module license ‘unspecified’ taints kernel.
    Disabling lock debugging due to kernel taint
    Hello world
    [root@vexpress drivers]# lsmod
    hello 16384 0 - Live 0x7f000000 (PO)
    [root@vexpress drivers]# rmmod hello.ko
    Goodbye world
    [root@vexpress drivers]#

1.3 内核模块的构成

●hello_init
– 模块加载入口函数,主要完成模块初始化工作
– 使用 __init声明,使用module_init指定
– 模块被加载到内核时,入口函数自动被内核执行
– 返回值:errno
– 应用层可根据返回值,使用 perror 进行解析
●hello_exit
– 模块卸载函数,模块卸载时该函数自动被内核执行
– 使用 __exit声明,使用module_exit指定
– 主要完成结束模块运行的相关工作、清理各种资源
– 返回类型:void
●insmod
●lsmod
●rmmod
2. 内核许可声明
用来描述内核的许可权限:内核以GPL发布
模块不声明LICENSE,内核会有(kernel tainted)警告
内核状态此时是受污染的(dirty)
内核受污染后,一些调试、打印功能可能会失效
2.1 协议分类

2.2 内核污染(kernel tainted)
2.2.1 cat /proc/sys/kernel/tainted
[root@vexpress ]# cat /proc/sys/kernel/tainted
0
[root@vexpress ]# cd my_data/drivers/
[root@vexpress drivers]#
[root@vexpress drivers]#
[root@vexpress drivers]# ls
hello.ko
[root@vexpress drivers]# insmod hello.ko
hello: loading out-of-tree module taints kernel.
hello: module license ‘unspecified’ taints kernel.
Disabling lock debugging due to kernel taint
Hello world
[root@vexpress drivers]# cat /proc/sys/kernel/tainted
4097
[root@vexpress drivers]#

2.2.2 内核被污染的原因

3.模块签名机制
1.在make_kernel.sh中添加:make menuconfig
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel$ git diff make_kernel.sh
diff --git a/kernel/make_kernel.sh b/kernel/make_kernel.sh
index 7434ede7e…bc8ff3ef6 100755
— a/kernel/make_kernel.sh
+++ b/kernel/make_kernel.sh
@@ -17,6 +17,7 @@ make_kernel() {
cd ./linux-5.10.4
# make clean
make vexpress_defconfig

  • make menuconfig
    make zImage -j8
    make modules -j8
    make dtbs -j8
    ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel$

2.打开如下选项:
CONFIG_MODULE_SIG
CONFIG_MODULE_SIG_FORCE
CONFIG_MODULE_SIG_ALL

3.未签名的hello.ko
[root@vexpress drivers]# insmod hello.ko
hello: Loading of unsigned module is rejected
insmod: can’t insert ‘hello.ko’: Key was rejected by service
[root@vexpress drivers]#

4.查看签名需要的文件:
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/certs$ ls signing_key.*
signing_key.pem signing_key.x509
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/certs$

certs/signing_key.x509 公钥
certs/signing_key.pem 私钥
scripts/sign-file 签名工具
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/scripts$ ls sign-*
sign-file sign-file.c
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/scripts$

5.手工给模块签名
(1)签名前:
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$ hexdump -C hello.ko | tail
00014990 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |…|
000149a0 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 |…|
000149b0 74 f9 00 00 50 03 00 00 26 00 00 00 30 00 00 00 |t…P…&…0…|
000149c0 04 00 00 00 10 00 00 00 09 00 00 00 03 00 00 00 |…|
000149d0 00 00 00 00 00 00 00 00 c4 fc 00 00 e3 00 00 00 |…|
000149e0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |…|
000149f0 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |…|
00014a00 40 42 01 00 97 01 00 00 00 00 00 00 00 00 00 00 |@B…|
00014a10 01 00 00 00 00 00 00 00 |…|
00014a18
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$

(2)签名:
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$ sudo …/…/linux-5.10.4/scripts/sign-file sha1 …/…/linux-5.10.4/certs/signing_key.pem …/…/linux-5.10.4/certs/signin
g_key.x509 hello.ko
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$

(3)签名后:
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$ hexdump -C hello.ko | tail
00014c60 ac 93 36 2e 7c 67 a1 e5 3d 8f 5f bb 82 3b 2e 3a |…6.|g…=._…;.😐
00014c70 80 01 38 34 3f 07 46 60 06 43 68 3b 8f 7c 61 c8 |…84?.F`.Ch;.|a.|
00014c80 97 38 9b 34 a0 dd bd ba 53 bc 03 12 cf a1 a5 77 |.8.4…S…w|
00014c90 81 ee d4 78 17 d2 44 23 cb 68 2f fe 37 79 77 04 |…x…D#.h/.7yw.|
00014ca0 71 b7 6d b9 63 40 20 70 ba e6 52 a8 d0 72 e0 0b |q.m.c@ p…R…r…|
00014cb0 ed 74 9f 07 3e be ef 35 0b 00 00 02 00 00 00 00 |.t…>…5…|
00014cc0 00 00 00 02 a1 7e 4d 6f 64 75 6c 65 20 73 69 67 |…~Module sig|
00014cd0 6e 61 74 75 72 65 20 61 70 70 65 6e 64 65 64 7e |nature appended~|
00014ce0 0a |.|
00014ce1
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$

6.签名的hello.ko
拷贝签名的hello.ko到out目录下,执行sudo make rootfs,将其编译到文件系统中,然后启动qemu。
[root@vexpress drivers]# insmod hello.ko
hello: loading out-of-tree module taints kernel.
hello: module license ‘unspecified’ taints kernel.
Disabling lock debugging due to kernel taint
Hello world
[root@vexpress drivers]#

7.补充:
清除模块签名:
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$ hexdump -C hello.ko | tail
00014c60 ac 93 36 2e 7c 67 a1 e5 3d 8f 5f bb 82 3b 2e 3a |…6.|g…=._…;.😐
00014c70 80 01 38 34 3f 07 46 60 06 43 68 3b 8f 7c 61 c8 |…84?.F.Ch;.|a.| 00014c80 97 38 9b 34 a0 dd bd ba 53 bc 03 12 cf a1 a5 77 |.8.4....S......w| 00014c90 81 ee d4 78 17 d2 44 23 cb 68 2f fe 37 79 77 04 |...x..D#.h/.7yw.| 00014ca0 71 b7 6d b9 63 40 20 70 ba e6 52 a8 d0 72 e0 0b |q.m.c@ p..R..r..| 00014cb0 ed 74 9f 07 3e be ef 35 0b 00 00 02 00 00 00 00 |.t..>..5........| 00014cc0 00 00 00 02 a1 7e 4d 6f 64 75 6c 65 20 73 69 67 |.....~Module sig| 00014cd0 6e 61 74 75 72 65 20 61 70 70 65 6e 64 65 64 7e |nature appended~| 00014ce0 0a |.| 00014ce1 ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$ strip --strip-debug hello.ko strip: Unable to recognise the format of the input file hello.ko’
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$ …/…/…/toolchain/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-strip --strip-debug hello.ko
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$ hexdump -C hello.ko | tail
00000ce0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |…|
00000cf0 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 |…|
00000d00 00 04 00 00 b0 02 00 00 1a 00 00 00 26 00 00 00 |…&…|
00000d10 04 00 00 00 10 00 00 00 09 00 00 00 03 00 00 00 |…|
00000d20 00 00 00 00 00 00 00 00 b0 06 00 00 cf 00 00 00 |…|
00000d30 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |…|
00000d40 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |…|
00000d50 e0 07 00 00 28 01 00 00 00 00 00 00 00 00 00 00 |…(…|
00000d60 01 00 00 00 00 00 00 00 |…|
00000d68
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/drivers/00hello$

4.将模块编译进内核
1.代码根目录进入如下目录,新建hello.c文件(内容同上),并修改KConfig和Makefile
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/drivers/char$ git diff Kconfig
diff --git a/kernel/linux-5.10.4/drivers/char/Kconfig b/kernel/linux-5.10.4/drivers/char/Kconfig
index d229a2d0c…dc35d91e6 100644
— a/kernel/linux-5.10.4/drivers/char/Kconfig
+++ b/kernel/linux-5.10.4/drivers/char/Kconfig
@@ -22,6 +22,12 @@ config TTY_PRINTK

      If unsure, say N.

+config HELLO

  •   bool "A hello module test"
    
  •   default n
    
  •   help
    
  •           a simple kernel module test
    

config TTY_PRINTK_LEVEL
depends on TTY_PRINTK
int “ttyprintk log level (1-7)”
ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/drivers/char$

ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/drivers/char$ git diff Makefile
diff --git a/kernel/linux-5.10.4/drivers/char/Makefile b/kernel/linux-5.10.4/drivers/char/Makefile
index ffce287ef…a91edf6b3 100644
— a/kernel/linux-5.10.4/drivers/char/Makefile
+++ b/kernel/linux-5.10.4/drivers/char/Makefile
@@ -47,3 +47,5 @@ obj- ( C O N F I G P S 3 F L A S H ) + = p s 3 f l a s h . o o b j − (CONFIG_PS3_FLASH) += ps3flash.o obj- (CONFIGPS3FLASH)+=ps3flash.oobj(CONFIG_XILLYBUS) += xillybus/
obj- ( C O N F I G P O W E R N V O P P A N E L ) + = p o w e r n v − o p − p a n e l . o o b j − (CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o obj- (CONFIGPOWERNVOPPANEL)+=powernvoppanel.oobj(CONFIG_ADI) += adi.o
+
+obj- C O N F I G H E L L O + = h e l l o . o u b u n t u @ V M − 8 − 3 − u b u n t u : / w u x i a n g / c o d e f o l d e r / k e r n e l / l i n u x − 5.10.4 / d r i v e r s / c h a r {CONFIG_HELLO} += hello.o ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel/linux-5.10.4/drivers/char CONFIGHELLO+=hello.oubuntu@VM83ubuntu: /wuxiang/codefolder/kernel/linux5.10.4/drivers/char

ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel$ git diff make_kernel.sh
diff --git a/kernel/make_kernel.sh b/kernel/make_kernel.sh
index 7434ede7e…bc8ff3ef6 100755
— a/kernel/make_kernel.sh
+++ b/kernel/make_kernel.sh
@@ -17,6 +17,7 @@ make_kernel() {
cd ./linux-5.10.4
# make clean
make vexpress_defconfig

  • make menuconfig
    make zImage -j8
    make modules -j8
    make dtbs -j8
    ubuntu@VM-8-3-ubuntu:~/wuxiang/code_folder/kernel$

2.dmesg显示开机信息:
[root@vexpress ]# dmesg | grep “Hello world”
Hello world
[root@vexpress ]#

完整的开机信息如下:(Hello world在110行)
[root@vexpress ]# dmesg
Booting Linux on physical CPU 0x0
Linux version 5.10.4 (root@VM-8-3-ubuntu) (arm-linux-gnueabi-gcc (Linaro GCC 7.5-2019.12) 7.5.0, GNU ld (Linaro_Binutils-2019.12) 2.28.2.20170706) #7 SMP Tue Aug 8 22:04:14 CST 2023
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
OF: fdt: Machine model: V2P-CA9
Malformed early option ‘earlycon’
printk: debug: ignoring loglevel setting.
Memory policy: Data cache writeback
Reserved memory: created DMA memory pool at 0x4c000000, size 8 MiB
OF: reserved mem: initialized node vram@4c000000, compatible id shared-dma-pool
cma: Reserved 16 MiB at 0x9f000000
Zone ranges:
Normal [mem 0x0000000060000000-0x000000009fffffff]
Movable zone start for each node
Early memory node ranges
node 0: [mem 0x0000000060000000-0x000000009fffffff]
Initmem setup node 0 [mem 0x0000000060000000-0x000000009fffffff]
On node 0 totalpages: 262144
Normal zone: 2048 pages used for memmap
Normal zone: 0 pages reserved
Normal zone: 262144 pages, LIFO batch:63
CPU: All CPU(s) started in SVC mode.
percpu: Embedded 19 pages/cpu s46156 r8192 d23476 u77824
pcpu-alloc: s46156 r8192 d23476 u77824 alloc=19*4096
pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
Built 1 zonelists, mobility grouping on. Total pages: 260096
Kernel command line: root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait earlycon console=tty0 console=ttyAMA0 init=/linuxrc ignore_loglevel
printk: log_buf_len individual max cpu contribution: 4096 bytes
printk: log_buf_len total cpu_extra contributions: 12288 bytes
printk: log_buf_len min size: 16384 bytes
printk: log_buf_len: 32768 bytes
printk: early log buf free: 14628(89%)
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes, linear)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes, linear)
mem auto-init: stack:off, heap alloc:off, heap free:off
Memory: 1011660K/1048576K available (7168K kernel code, 583K rwdata, 1720K rodata, 1024K init, 184K bss, 20532K reserved, 16384K cma-reserved)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
rcu: Hierarchical RCU implementation.
rcu: RCU event tracing is enabled.
rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
GIC CPU mask not found - kernel will fail to boot.
GIC CPU mask not found - kernel will fail to boot.
L2C: platform modifies aux control register: 0x02020000 -> 0x02420000
L2C: DT/platform modifies aux control register: 0x02020000 -> 0x02420000
L2C-310 enabling early BRESP for Cortex-A9
L2C-310 full line of zeros enabled for Cortex-A9
L2C-310 dynamic clock gating disabled, standby mode disabled
L2C-310 cache controller enabled, 8 ways, 128 kB
L2C-310: CACHE_ID 0x410000c8, AUX_CTRL 0x46420001
random: get_random_bytes called from start_kernel+0x388/0x52c with crng_init=0
sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275 ns
Failed to initialize ‘/bus@4000000/motherboard/iofpga@7,00000000/timer@12000’: -22
smp_twd: clock not found -2
Console: colour dummy device 80x30
printk: console [tty0] enabled
Calibrating local timer… 90.81MHz.
Calibrating delay loop… 609.07 BogoMIPS (lpj=3045376)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 2048 (order: 1, 8192 bytes, linear)
Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes, linear)
CPU: Testing write buffer coherency: ok
CPU0: Spectre v2: using BPIALL workaround
CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
Setting up static identity map for 0x60100000 - 0x60100060
rcu: Hierarchical SRCU implementation.
smp: Bringing up secondary CPUs …
smp: Brought up 1 node, 1 CPU
SMP: Total of 1 processors activated (609.07 BogoMIPS).
CPU: All CPU(s) started in SVC mode.
devtmpfs: initialized
VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 0
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 1024 (order: 4, 65536 bytes, linear)
NET: Registered protocol family 16
DMA: preallocated 256 KiB pool for atomic coherent allocations
cpuidle: using governor ladder
hw-breakpoint: debug architecture 0x4 unsupported.
Serial: AMBA PL011 UART driver
SCSI subsystem initialized
libata version 3.00 loaded.
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
Advanced Linux Sound Architecture Driver Initialized.
clocksource: Switched to clocksource arm,sp804
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear)
TCP established hash table entries: 8192 (order: 3, 32768 bytes, linear)
TCP bind hash table entries: 8192 (order: 4, 65536 bytes, linear)
TCP: Hash tables configured (established 8192 bind 8192)
UDP hash table entries: 512 (order: 2, 16384 bytes, linear)
UDP-Lite hash table entries: 512 (order: 2, 16384 bytes, linear)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
hw perfevents: enabled with armv7_cortex_a9 PMU driver, 5 counters available
workingset: timestamp_bits=30 max_order=18 bucket_order=0
squashfs: version 4.0 (2009/01/31) Phillip Lougher
jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
9p: Installing v9fs 9p2000 file system support
io scheduler mq-deadline registered
io scheduler kyber registered
Hello world
i2c i2c-0: Added multiplexed i2c bus 2
physmap-flash 40000000.flash: physmap platform flash device: [mem 0x40000000-0x43ffffff]
40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
erase region 0: offset=0x0,size=0x40000,blocks=256
physmap-flash 40000000.flash: physmap platform flash device: [mem 0x44000000-0x47ffffff]
40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
erase region 0: offset=0x0,size=0x40000,blocks=256
Concatenating MTD devices:
(0): “40000000.flash”
(1): “40000000.flash”
into device “40000000.flash”
physmap-flash 48000000.psram: physmap platform flash device: [mem 0x48000000-0x49ffffff]
libphy: Fixed MDIO Bus: probed
libphy: smsc911x-mdio: probed
smsc911x 4e000000.ethernet eth0: MAC Address: 52:54:00:12:34:56
isp1760 4f000000.usb: bus width: 32, oc: digital
isp1760 4f000000.usb: NXP ISP1760 USB Host Controller
isp1760 4f000000.usb: new USB bus registered, assigned bus number 1
isp1760 4f000000.usb: Scratch test failed.
isp1760 4f000000.usb: can’t setup: -19
isp1760 4f000000.usb: USB bus 1 deregistered
usbcore: registered new interface driver usb-storage
ledtrig-cpu: registered to indicate activity on CPUs
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
NET: Registered protocol family 17
9pnet: Installing 9P2000 support
oprofile: using arm/armv7-ca9
Registering SWP/SWPB emulation handler
aaci-pl041 10004000.aaci: ARM AC’97 Interface PL041 rev0 at 0x10004000, irq 28
aaci-pl041 10004000.aaci: FIFO 512 entries
mmci-pl18x 10005000.mmci: Got CD GPIO
mmci-pl18x 10005000.mmci: Got WP GPIO
mmci-pl18x 10005000.mmci: mmc0: PL181 manf 41 rev0 at 0x10005000 irq 29,30 (pio)
10009000.uart: ttyAMA0 at MMIO 0x10009000 (irq = 33, base_baud = 0) is a PL011 rev1
mmc0: new SD card at address 4567
mmcblk0: mmc0:4567 QEMU! 1.00 GiB
printk: console [ttyAMA0] enabled
1000a000.uart: ttyAMA1 at MMIO 0x1000a000 (irq = 34, base_baud = 0) is a PL011 rev1
1000b000.uart: ttyAMA2 at MMIO 0x1000b000 (irq = 35, base_baud = 0) is a PL011 rev1
1000c000.uart: ttyAMA3 at MMIO 0x1000c000 (irq = 36, base_baud = 0) is a PL011 rev1
random: fast init done
input: AT Raw Set 2 keyboard as /devices/platform/bus@4000000/bus@4000000:motherboard/bus@4000000:motherboard:iofpga@7,00000000/10006000.kmi/serio0/input/input0
mmcblk0: p1 p2
rtc-pl031 10017000.rtc: registered as rtc0
rtc-pl031 10017000.rtc: setting system clock to 2023-08-08T14:06:36 UTC (1691503596)
drm-clcd-pl111 1001f000.clcd: assigned reserved memory node vram@4c000000
drm-clcd-pl111 1001f000.clcd: using device-specific reserved memory
drm-clcd-pl111 1001f000.clcd: core tile graphics present
drm-clcd-pl111 1001f000.clcd: this device will be deactivated
drm-clcd-pl111 1001f000.clcd: Versatile Express init failed - -19
drm-clcd-pl111 10020000.clcd: DVI muxed to daughterboard 1 (core tile) CLCD
drm-clcd-pl111 10020000.clcd: initializing Versatile Express PL111
drm-clcd-pl111 10020000.clcd: found bridge on endpoint 0
drm-clcd-pl111 10020000.clcd: Using non-panel bridge
[drm] Initialized pl111 1.0.0 20170317 for 10020000.clcd on minor 0
Console: switching to colour frame buffer device 128x48
drm-clcd-pl111 10020000.clcd: [drm] fb0: pl111drmfb frame buffer device
ALSA device list:
#0: ARM AC’97 Interface PL041 rev0 at 0x10004000, irq 28
input: ImExPS/2 Generic Explorer Mouse as /devices/platform/bus@4000000/bus@4000000:motherboard/bus@4000000:motherboard:iofpga@7,00000000/10007000.kmi/serio1/input/input2
EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
VFS: Mounted root (ext4 filesystem) on device 179:2.
Freeing unused kernel memory: 1024K
Run /linuxrc as init process
with arguments:
/linuxrc
with environment:
HOME=/
TERM=linux
random: crng init done
[root@vexpress ]#

5.out-of-tree编译
.PHONY : all clean

obj-m := hello.o

EXTRA_CFLAGS += -DDEBUG

KDIR := ${PWD}/…/…/linux-5.10.4

all:
make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules

clean:

make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules clean

clean:
@rm -rf *.o ~ .depend ..cmd *.mod *.mod.c .tmp_versions *.ko *.symvers modules.order

6.模块的Makefile分析
Kbuild:
obj-y := hello.o
obj-m := hello.o
obj-{CONFIG_HELLO} := hello.o
hello-objs := hello.c sub.c

将Kbuild和Makefile分开:
obj-m := hello_Kbuild.o

.PHONY : all clean

EXTRA_CFLAGS += -DDEBUG

KDIR := ${PWD}/…/…/linux-5.10.4

all:
make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules

clean:

make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules clean

clean:
@rm -rf *.o ~ .depend ..cmd *.mod *.mod.c .tmp_versions *.ko *.symvers modules.order

7.模块参数
7.1 如何给模块传参数?
#define module_param(name, type, perm) module_param_named(name, name, type, perm)

●name:要传递的参数,对应模块中的全局变量
●type:要传递的参数类型,要和全局变量类型一致
●perm:读写权限
○/sys/module/hello/parameters/xx 参数节点
○0666:读写权限
○0444:只读权限,无法对这个文件节点执行写的操作
○4-读,2-写,1-执行
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

static int num = 10;
module_param(num, int, 0660);

static int __init hello_init(void)
{
printk(“Hello world\n”);
printk(“num = %d\n”, num);

return 0;

}

static void __exit hello_exit(void)
{
printk(“Goodbye world\n”);
printk(“num = %d\n”, num);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“uwu16”);

[root@vexpress drivers]# insmod hello_params.ko
Hello world
num = 10
[root@vexpress drivers]# cd /sys/module/hello_params/parameters/
[root@vexpress parameters]#
[root@vexpress parameters]# ls
num
[root@vexpress parameters]# cat num
10
[root@vexpress parameters]# echo 100 > num
[root@vexpress parameters]# cat num
100
[root@vexpress parameters]# lsmod
hello_params 16384 0 - Live 0x7f000000 (O)
[root@vexpress parameters]# rmmod hello_params
Goodbye world
num = 100
[root@vexpress parameters]# cd /my_data/drivers/
[root@vexpress drivers]# insmod hello_params.ko num=111
Hello world
num = 111
[root@vexpress drivers]# rmmod hello_params.ko
Goodbye world
num = 111
[root@vexpress drivers]#

7.2 通过uboot给模块传参
●需要使用编译进内核中的hello模块
1.编译uboot时,make menuconfig,在bootargs中添加hello.num=100
2.启动qemu
[root@vexpress ]# dmesg | grep num
Kernel command line: root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait earlycon console=tty0 console=ttyAMA0 init=/linuxrc ignore_loglevel hello.num=100
num = 100
isp1760 4f000000.usb: new USB bus registered, assigned bus number 1
[root@vexpress ]# dmesg | grep Hello
Hello world
[root@vexpress ]#

3.完整开机log如下:

io scheduler mq-deadline registered
io scheduler kyber registered
Hello world
num = 100
i2c i2c-0: Added multiplexed i2c bus 2

8.EXPORT_SYMBOL
8.1 用户空间的模块化编程
函数的实现:math.c/int add(int a, int b)
函数的声明:math.h/int add(int a, int b);

8.2 内核空间的模块化编程
模块的封装:static、EXPORT_SYMBOL
函数的声明:头文件
●按不同的协议导出符号
EXPORT_SYMBOL
EXPORT_SYMBOL_GPL

***** welcome to vexpress board *****

Please press Enter to activate this console.
[root@vexpress ]#
[root@vexpress ]#
[root@vexpress ]#
[root@vexpress ]# cd my_data/drivers/
[root@vexpress drivers]#
[root@vexpress drivers]# ls
hello.ko hello_in_kernel.ko hello_params.ko
hello_Kbuild.ko hello_module.ko math_module.ko
[root@vexpress drivers]#
[root@vexpress drivers]#
[root@vexpress drivers]#
[root@vexpress drivers]# insmod math_module.ko
math_module: loading out-of-tree module taints kernel.
Hello math_module
[root@vexpress drivers]# insmod hello_module.ko
num = 10
sum = 7
[root@vexpress drivers]#

9.模块的版本控制
解决内核模块和内核之间的接口一致性问题
根据函数参数、返回值类型等生成CRC校验码
当内核和模块双方的校验码相等,则为相同接口
内核启动版本控制功能:CONFIG_MODVERSIONS

●实验:版本控制实验
1.不开CONFIG_MODVERSIONS编译内核,基于此内核编译drivers
2.打开CONFIG_MODVERSIONS,不编译drivers
3.使用打开CONFIG_MODVERSIONS的内核和不开CONFIG_MODVERSIONS编译内核后编译的drivers,进行版本控制的实验。

●相关的几个文件
hello_version_ctrl.mod.c
hello_version_ctrl.ko:__versions section
内核中:Modules.symvers
模块中:Modules.symvers

hello_version_ctrl.ko模块中调用的内核中的接口函数以及CRC校验码,当模块被加载到内核中运行的时候,内核就会根据调用的比如printk的校验码和内核中保存的printk的校验码进行比对,比对成功,模块才可以加载到内核中运行。

反汇编:

我们自己编译的模块,使用EXPORT_SYMBOL导出的时候,也会生成校验码,别的模块在调用时也会进行校验。

10.模块的头文件
#include <linux/xx.h>
#include <asm/xx.h>
#include <plat/xx.h>
#include <mach/xx.h>
#include “usb.h”

●头文件分类
内核专用头文件:include/linux
和CPU架构相关:arch/ ( A R C H ) / i n c l u d e 板级硬件相关: a r c h / (ARCH)/include 板级硬件相关: arch/ (ARCH)/include板级硬件相关:arch/(ARCH)/plat-xx/include
arch/$(ARCH)/mach-xx/include
●通过GCC -I指定头文件路径
#include <module1/module1.h>
#include <module2/module2.h>
#include <module3/module3.h>

├── a.out
├── inc
│ ├── module1
│ │ └── module1.h
│ ├── module2
│ │ └── module2.h
│ └── module3
│ └── module3.h
├── main.c
├── module1
│ └── module1.c
├── module2
│ └── module2.c
└── module3
└── module3.c

●内核中的头文件路径

11.多文件构成的模块
●编程实验:
1.一个复杂模块往往由多个C文件构成
2.模块内部接口的封装和引用
3.模块如何封装
4.模块间如何引用
5.头文件
6.Makefile 的写法

12.模块间的依赖

●生成模块间的依赖关系
depmod –a

depmod会解析/lib/modules/ ( k e r n e l v e r s i o n ) 下的所有内核模块,通过各个模块 E X P O R T S Y M B O L 和引用的符号,生成一个模块依赖关系表: / l i b / m o d u l e s / (kernel_version)下的所有内核模块,通过各个模块EXPORT_SYMBOL和引用的符号,生成一个模块依赖关系表:/lib/modules/ (kernelversion)下的所有内核模块,通过各个模块EXPORTSYMBOL和引用的符号,生成一个模块依赖关系表:/lib/modules/(kernel_version)/modules.dep
modprobe hello # 加载
modprobe –r hello # 卸载

13.编写一个字符驱动
read / write
sys_read / sys_write
普通文件 设备文件
文件系统 设备模型
inode 设备号
块设备驱动 字符设备驱动
●编程实验:实现一个最简单的字符驱动
驱动源码:实现基本的read、write接口
Makefile编写
创建设备节点
编写应用程序读写设备,看驱动工作是否正常
// hello_char.ko
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>

static char hello_buf[512] = “0”;

static int hello_open(struct inode *inode, struct file *fp)
{
return 0;
}

static int hello_release(struct inode *inode, struct file *fp)
{
return 0;
}

static ssize_t hello_read(struct file *fp, char __user *buf,
size_t size, loff_t *pos)
{
unsigned long p = *pos;
unsigned int count = size;

if (p >= 512) {return -1;
}if (count > 512) {count = 512 - p;
}if (copy_to_user(buf, hello_buf + p, count) != 0) {printk("read error!\n");return -1;
}return count;

}

static ssize_t hello_write(struct file *fp, const char __user *buf,
size_t size, loff_t *pos)
{
unsigned long p = *pos;
unsigned int count = size;

if (p >= 512) {return -1;
}if(count > 512) {count = 512 - p;
}if(copy_from_user(hello_buf, buf + p, count) != 0) {printk("write error!\n");return -1;
}return count;

}

static const struct file_operations hello_fops = {
.owner = THIS_MODULE,
.read = hello_read,
.write = hello_write,
.open = hello_open,
.release = hello_release,
};

static int __init hello_init(void)
{
int ret;

ret = register_chrdev(222, "hello_char", &hello_fops);
if (ret < 0) {printk("Register char module: hello_char failed..\n");return 0;
} else {printk("Register char module: hello_char success!\n");
}return 0;

}

static void __exit hello_exit(void)
{
printk(“Goodbye char module: hello_char!\n”);
unregister_chrdev(222, “hello_char”);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“uuuuu”);

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
int fd;
int i, ret;
char write_buf[10] = “aaaabbbb”;
char read_buf[10] = “0”;

fd = open("/dev/hello_char", O_RDWR);
if(fd == -1) {printf("cannot open file..\n");exit(1);
}if ((ret = write(fd, write_buf, 10)) < 0) {printf("write failed\n");return -1;
}lseek(fd, 0, SEEK_SET);
if ((ret = read(fd, read_buf, 10)) < 10) {printf("read error!\n");exit(1);
}printf("%s\n", read_buf);close(fd);return 0;

}

14.模块的运行过程
●模块的分类
可加载模块:源码外编译,动态加载、动态卸载
内置模块:直接编译进内核,随内核启动初始化
●使用dump_stack()打印函数调用栈

15.模块机制实现分析
●分析之前的准备
C语言与链接脚本、Makefile、Kbuild的交互
C语言如何引用链接脚本中定义的符号
C语言如何使用Makefile中定义的符号
C语言如何使用kbuild配置变量
???
???
???
???
16.使用模块机制分析内核

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/201059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3网站用户引导功能【Intro.js】

一、介绍 Intro.js 是一个用于创建网站用户引导、功能介绍和教程的 JavaScript 库。它允许开发者通过步骤和提示突出显示网站上的特定元素&#xff0c;以帮助用户更好地了解和使用网站的功能。以下是 Intro.js 的一些关键特点和用法介绍&#xff1a; 更多Intro.js 功能网址&a…

mac批量修改图片格式

1. 当前窗口在word文档&#xff0c;选择工具-》宏-》点击宏 2. 弹出弹框&#xff0c;起个宏名1&#xff0c;点击2添加一个宏。 输入以下代码&#xff1a; Sub 图片格式统一()图片格式统一 宏Dim iDim Height, WeightHeight 200 改成自己的高度Weight 350 改成自己的宽度On E…

STM32-GPIO

一、GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口 可配置8种输入输出模式 引脚电平&#xff1a;0V~3.3V&#xff0c;部分引脚可容忍5V 输出模式下&#xff1a;可控制端口输出高低电平&#xff0c;用以驱动LED、控制蜂鸣器、模拟通信协议输…

MIT_线性代数笔记:第 12 讲 图、网络、关联矩阵

目录 图和网络 Graphs & Networks关联矩阵&#xff08;Incidence matrices&#xff09;矩阵的零空间矩阵列空间矩阵的左零空间矩阵的行空间 本讲讨论线性代数在物理系统中的应用。 图和网络 Graphs & Networks “图”就是“结点”和“边”的一个集合。 边线上的箭头代…

力扣11.盛最多水的容器

题目描述 思路 用双指针法。 每次向内移动较短的那个板&#xff0c;能带来更大的效益。 代码 class Solution {public int maxArea(int[] height) {int res 0;int i 0,j height.length - 1;while(i < j){res height[i] < height[j] ? Math.max((j - i) * height…

2023.12.4 关于 Spring Boot 统一异常处理

目录 引言 统一异常处理 异常全部监测 引言 将异常处理逻辑集中到一个地方&#xff0c;可以避免在每个控制器或业务逻辑中都编写相似的异常处理代码&#xff0c;这降低了代码的冗余&#xff0c;提高了代码的可维护性统一的异常处理使得调试和维护变得更加容易&#xff0c;通…

photoshop实现抠图的步骤

实现抠图的主要步骤如下&#xff1a; 打开图片&#xff1a;用Photoshop打开需要抠图的图片。 选择抠图工具&#xff1a;在Photoshop工具栏中找到“套索工具”、“魔术棒工具”、“快速选择工具”等工具&#xff0c;选择其中一个作为抠图工具。 选择抠图区域&#xff1a;用抠图…

pytorch学习9-优化器学习

系列文章目录 pytorch学习1-数据加载以及Tensorboard可视化工具pytorch学习2-Transforms主要方法使用pytorch学习3-torchvisin和Dataloader的使用pytorch学习4-简易卷积实现pytorch学习5-最大池化层的使用pytorch学习6-非线性变换&#xff08;ReLU和sigmoid&#xff09;pytorc…

Linux swatch命令教程:如何监控系统活动(附案例详解和注意事项)

Linux swatch命令介绍 Swatch&#xff0c;全称为Simple Watcher&#xff0c;是一个简单的监视器&#xff0c;设计用于监控系统活动。为了使Swatch有用&#xff0c;它需要一个配置文件&#xff0c;该文件包含要查找的模式和在找到每个模式时要执行的操作。 Linux swatch命令适…

[头歌系统数据库实验] 实验3 MySQL的DDL语言

目录 第1关&#xff1a;将P表中的所有红色零件的重量增加6 第2关&#xff1a;把P表中全部红色零件的颜色改成蓝色 第3关&#xff1a;将SPJ表中由S5供给J4的零件P6改为由S3供应 第4关&#xff1a;将SPJ表中所有天津供应商的QTY属性值减少11&#xff08;用子查询方式&#x…

C标准输入输出函数

介绍 C语言中常用的输入输出函数包括&#xff1a; scanf&#xff1a;从标准输入设备&#xff08;通常是键盘&#xff09;读取数据。printf&#xff1a;将数据输出到标准输出设备&#xff08;通常是显示器&#xff09;。getchar&#xff1a;从标准输入设备读取一个字符。putcha…

云轴科技ZStack助力彬长矿业建设智能矿山

陕西彬长矿业集团有限公司&#xff08;简称彬长矿业&#xff09;选择云轴科技ZStack智能矿山云解决方案建设云基础设施&#xff1a;ZStackCube超融合一体机部署在西咸云基地机房构建私有云资源池&#xff0c;ZStackCMP多云管理平台对西咸云基地机房以及各矿井生产服务中心资源进…

【每日OJ —— 94. 二叉树的中序遍历】

每日OJ —— 94. 二叉树的中序遍历 1.题目&#xff1a;94. 二叉树的中序遍历2.解法2.1.算法讲解2.2.代码实现2.3.提交通过展示 1.题目&#xff1a;94. 二叉树的中序遍历 2.解法 2.1.算法讲解 1.首先如果在每次每个节点遍历的时候都去为数组开辟空间&#xff0c;这样的效率太低…

quickapp_快应用_快应用与h5交互

快应用与h5交互 h5跳转到快应用[1] 判断当前环境是否支持组件跳转快应用[2] h5跳转到快应用(1)deeplink方式进行跳转(推荐)(2)h5点击组件(接收参数存在问题)(3)url配置跳转(官方不推荐) 问题-浏览器问题 web组件h5页面嵌入快应用快应用发送消息到h5页面h5页面接收快应用发送的消…

网络安全(三)-- 网络嗅探及协议分析技术

目标 了解网络嗅探的基本含义了解tcpdump工具的基本用法掌握tcpdump工具抓包保存到文件的方法熟悉wireshark工具的基本用法掌握借助wireshark抓包工具分析简单网络协议的方法 6.1. 概述 网络嗅探是一种常用的数据收集、分析的方法: 黑客常通过网络嗅探获取主机或网络的控制权…

golang使用sip实现语音通话

在使用 github.com/cloudwebrtc/sip 这个 Go 语言库时&#xff0c;要实现通话&#xff0c;您需要处理 SIP 协议的一系列操作&#xff0c;包括建立和终止呼叫、处理媒体传输等。以下是一个简化的示例代码&#xff0c;演示如何使用该库来处理 SIP 通话的基本流程&#xff1a; pac…

Python智能语音识别语翻译平台|项目后端搭建

Python程序设计基础&#xff0c;第三方库Django、requests、hashlib、pyttsx3等的使用&#xff0c;百度API语音识别业务接口、文本朗读业务接口、翻译业务接口的传入。 01、任务实现步骤 任务描述&#xff1a;本任务利用Django框架搭建智能语音识别与翻译平台的后端&#xff0…

ULAM公链第九十六期工作总结

迈入12月&#xff0c;接下来就是雪花&#xff0c;圣诞&#xff0c;新年和更好的我们&#xff01;愿生活不拥挤&#xff0c;笑容不必刻意&#xff0c;愿一切美好如期而至&#xff01; 2023年11月01日—2023年12月01日关于ULAM这期工作汇报&#xff0c;我们通过技术板块&#xff…

加州大学伯克利分校研究人员推出Starling-7B:一款通过人工智能反馈强化学习(RLAIF)训练的开源大型语言模型(LLM)

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

CentOS中安装数据库

1.下载 网址&#xff1a;https://dev.mysql.com/downloads/mysql/ 按如图选择&#xff0c;然后点击Download 这里它让我们登录&#xff0c;我们直接选择不登录&#xff0c;直接下载 2.关闭防火墙 systemctl disable firewalld3.正式安装 切换到/usr/local下 cd /usr/l…