LDD3 学习笔记
LDD3 WEEK0
这周忙于人工智能课程的作业,书本看的不多,下周多看一些多实践一些。
1.简介
主要介绍了驱动程序的角色,内核划分,以及 Linux 版本号、社区的一些基本信息。
2.建立和运行模块
hello world
obj-m += hello_world.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
#include<linux/module.h>
#include<linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("RogerThat");
MODULE_DESCRIPTION("A simple hello world module");
MODULE_VERSION("0.01");
static int __init hello_mod_init(void)
{
printk(KERN_ALERT "Hello world from kernel!! \n");
return 0;
}
static void __exit hello_mod_exit(void)
{
printk(KERN_ALERT "Exiting hello world module from kernel !!!\n");
}
module_init(hello_mod_init);
module_exit(hello_mod_exit);
output
rt@rogerthat ~/kernel> make
make -C /lib/modules/5.19.0-46-generic/build M=/home/rt/kernel modules
make[1]: Entering directory '/usr/src/linux-headers-5.19.0-46-generic'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc-12 (Ubuntu 12.2.0-3ubuntu1) 12.2.0
You are using: gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
CC [M] /home/rt/kernel/hello_world.o
MODPOST /home/rt/kernel/Module.symvers
CC [M] /home/rt/kernel/hello_world.mod.o
LD [M] /home/rt/kernel/hello_world.ko
BTF [M] /home/rt/kernel/hello_world.ko
Skipping BTF generation for /home/rt/kernel/hello_world.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.19.0-46-generic'
rt@rogerthat ~/kernel [1]> sudo insmod hello_world.ko
rt@rogerthat ~/kernel> sudo lsmod | grep "hello"
hello_world 16384 0
rt@rogerthat ~/kernel [1]> sudo dmesg
[ 489.143299] hello_world: loading out-of-tree module taints kernel.
[ 489.143332] hello_world: module verification failed: signature and/or required key missing - tainting kernel
[ 489.144447] Hello world from kernel!!
rt@rogerthat ~/kernel [1]> sudo rmmod hello_world
也可以用 modprob
,处理依赖。
内核符号表,这个比较新奇,之前对这个的了解比较少。
感觉可以多用一下 goto
了(,新版的 linux
(6.x) 内核有不少 rust
的代码,但是怎么这么多函数都是 unsafe
的,这算一种画蛇添足吗=。=。
我的 WSL 内核版本是 5.15.90.4,在 WSL 上做这些事情是不是会有趣一些
3.字符驱动
讲字符驱动,顺便翻了一下 Linux 2.1 fs.h
中关于文件的一些数据结构
struct file {
struct file *f_next, **f_pprev;
struct dentry *f_dentry;
struct file_operations *f_op;
mode_t f_mode;
loff_t f_pos;
unsigned short f_count, f_flags;
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
struct fown_struct f_owner;
unsigned long f_version;
/* needed for tty driver, and maybe others */
void *private_data;
};
可以看到第三个结构体 file_operations
也就是书中讲的。
而在 Linux 6.x
中变成了
989 struct file {
990 union {
991 /* fput() uses task work when closing and freeing file (default). */
992 struct callback_head f_task_work;
993 /* fput() must use workqueue (most kernel threads). */
994 struct llist_node f_llist;
995 unsigned int f_iocb_flags;
996 };
997
998 /*
999 * Protects f_ep, f_flags.
1000 * Must not be taken from IRQ context.
1001 */
1002 spinlock_t f_lock;
1003 fmode_t f_mode;
1004 atomic_long_t f_count;
1005 struct mutex f_pos_lock;
1006 loff_t f_pos;
1007 unsigned int f_flags;
1008 struct fown_struct f_owner;
1009 const struct cred *f_cred;
1010 struct file_ra_state f_ra;
1011 struct path f_path;
1012 struct inode *f_inode; /* cached value */
1013 const struct file_operations *f_op;
1014
1015 u64 f_version;
1016 #ifdef CONFIG_SECURITY
1017 void *f_security;
1018 #endif
1019 /* needed for tty driver, and maybe others */
1020 void *private_data;
1021
1022 #ifdef CONFIG_EPOLL
1023 /* Used by fs/eventpoll.c to link all the hooks to this file */
1024 struct hlist_head *f_ep;
1025 #endif /* #ifdef CONFIG_EPOLL */
1026 struct address_space *f_mapping;
1027 errseq_t f_wb_err;
1028 errseq_t f_sb_err; /* for syncfs */
1029 } __randomize_layout
1030 __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
结构有一些变化,2.x
直接用双向链表连起了 struct file
,而 6.x
的 f_llist
是一个单向链表?多了 epoll,security
等选项。具体的一些细节回头再看看。
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *);
int (*fasync) (int, struct file *, int);
int (*check_media_change) (kdev_t dev);
int (*revalidate) (kdev_t dev);
int (*lock) (struct file *, int, struct file_lock *);
};
似乎是几个 CRT 中比较常用的函数,实际上这些操作大部分实现系统调用。struct file 中包含了 f_op 方法,一种面向对象思想。
没找到 aio_read,aio_write
异步读写,可能是没支持?回头再看看。
poll
是三个系统调用的后端 poll,epoll
和 select
。
ioctl
设备发出特定命令,readv, writev
发散/汇聚读和写操作?回头再看看
struct inode
,i_rdev,i_cdev
unsigned long copy_to_user(void __user *to,const void *from,unsigned long count);
skull
还没试过这部分代码,接着看看
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 R0gerThat!
评论