linux 内核设备模型的初始化(01)
文章目录
一、驱动框架模型初始化流程
(1-1)driver_init()
驱动框架模型的初始化操作由driver_init()
函数完成(/drivers/base/init.c)
void __init driver_init(void)
{
/* 核心初始化部分 */
//(/drivers/base/devtmpfs.c)
devtmpfs_init();
//(/drivers/base/core.c)
devices_init();
//(/drivers/base/buses.c)
buses_init();
//(drivers/base/class.c)
classes_init();
//(drivers/base/firmware.c)
firmware_init();
//(drivers/base/hypervisor.c)
hypervisor_init();
/* 以下函数也是驱动模型初始化的核心,但是要放在以上函数的后面调用 */
//(drivers/base/platform.c)
platform_bus_init();
//(drivers/base/auxiliary.c)
auxiliary_bus_init();
//(drivers/base/cpu.c)
cpu_dev_init();
//(drivers/base/memory.c)
memory_dev_init();
//(drivers/base/container.c)
container_dev_init();
//(drivers/of/base.c)
of_core_init();
}
(1-2)do_basic_setup()
driver_init()
在(init/main.c)中do_basic_setup()
函数中被调用:
static void __init do_basic_setup(void)
{
cpuset_init_smp();
usermodehelper_init();
shmem_init();
driver_init();
init_irq_proc();
do_ctors();
usermodehelper_enable();
do_initcalls();
random_int_secret_init();
}
二、devtmpfs初始化
devtmpfs
由devtmpfs_init()
函数完成,如下代码所示:
int __init devtmpfs_init(void)
{
int err = register_filesystem(&dev_fs_type);
if (err) {
printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
"type %i\n", err);
return err;
}
thread = kthread_run(devtmpfsd, &err, "kdevtmpfs");
if (!IS_ERR(thread)) {
wait_for_completion(&setup_done);
} else {
err = PTR_ERR(thread);
thread = NULL;
}
if (err) {
printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
unregister_filesystem(&dev_fs_type);
return err;
}
printk(KERN_INFO "devtmpfs: initialized\n");
return 0;
}
上述第3行代码,调用register_filesystem()
注册devtmpfs文件系统,devtmpfs文件系统类型定义如下:
static struct file_system_type dev_fs_type = {
.name = "devtmpfs",
.mount = dev_mount,
.kill_sb = kill_litter_super,
};
在整个linux内核启动过程中,在注册驱动程序核心设备之前,将创建基于tmpfs的文件系统devtmpfs
。每个请求设备节点的驱动核心设备都将在这个文件系统中添加一个节点。默认情况下,所有设备都以设备名命名,属于根用户,默认模式为0600
(小生疑问:这个是什么含义呢?),子系统可以在需要时覆盖默认设置。
三、kset、kobject概述
(3-1)kobject概述
kobject
内核对象定义:
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct kernfs_node *sd;
struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
(3-2)kset概述
kset
有如下定义(/include/linux/kobject.h):
struct kset {
//这个kset的所有kobject的列表
struct list_head list;
//用于遍历kobject的锁
spinlock_t list_lock;
//放在kset中的kobject
struct kobject kobj;
//kset的uevent操作集
const struct kset_uevent_ops *uevent_ops;
};
kset用于描述:一个特定子系统的一组特定类型的kobjects
,即使用kset
来描述一个子系统的多个kobjects。它们可以是单独的、不同的类型,但总的来说,这些kobjects
都希望被组合在一起,并以相同的方式操作它们。kset
用于定义属性回调和发生在kobject上的其他的常见事件。
四、devices初始化
linux 内核使用devices_init()
函数来初始化devices、dev内核设备模型的支持对象,定义如下:
int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;
return 0;
char_kobj_err:
kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
kobject_put(dev_kobj);
dev_kobj_err:
kset_unregister(devices_kset);
return -ENOMEM;
}
上述代码中kobject_create_and_add
使用动态方法创建struct kset
,并将其添加到sysfs
中,当该函数执行完成后,linux内核下将会有devices
(/sys/devices/)对象集合、还创建了dev
对象,其中dev对象包含block
和char
两个子对象。
五、buses初始化
linux内核中使用buses_init()
函数来初始化buses总线。定义如下(/drivers/base/bus.c):
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
if (!bus_kset)
return -ENOMEM;
system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
if (!system_kset)
return -ENOMEM;
return 0;
}
上述代码第3行,使用kset_create_and_add()
创建bus
对象集合。
第7行代码,使用kset_create_and_add()
创建了system
集合,同时指定system
的父对象是在devices_init()
中创建的devices
对象集。
函数buses_init()
的本质就是在系统中创建bus
和system
两个与buses
相关的对象集合。
如下图所示,在根文件系统中有以下的目录信息:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-83B2RWlu-1644243333731)(/home/iriczhao/.config/Typora/typora-user-images/image-20220127212836151.png)]
六、classes初始化
linux内核中使用classes_init()
函数来初始化classes类。定义如下(/drivers/base/class.c):
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
return 0;
}
与buses_init()
相同,使用kset_create_and_add()
创建class
对象集。
七、firmware初始化
linux内核中使用firmware_init()
函数来进行firmware初始化。定义如下(/driver/base/firmware.c):
int __init firmware_init(void)
{
firmware_kobj = kobject_create_and_add("firmware", NULL);
if (!firmware_kobj)
return -ENOMEM;
return 0;
}
同样的,firmware_init使用kobject_create_and_add()
将firmware
被添加到/sys/
中。
八、hypervisor初始化
linux内核中使用hypervisor_init()
函数进行hypervisor的初始化,如下定义(/driver/base/hypervisor.c):
int __init hypervisor_init(void)
{
hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);
if (!hypervisor_kobj)
return -ENOMEM;
return 0;
}
同样的,hypervisor_init()
将创建hypervisor
对象,并将其添加到/sys/
中。