Linux设备子系统初始化
本文介绍的内容是基于Linux3.1源码,并参考了很多网上找来的资料
Linux内核的启动的流程如下:
start_kernel->rest_init->kernel_init->do_basic_setup->driver_init
由driver_init函数完成设备驱动子系统的初始化,这里重点分析driver_init函数,该函数通过调用一系列的初始化函数主要完成了设备驱动子系统的一个整体框架;
/**
* driver_init - initialize driver model.
*
* Call the driver model init functions to initialize their
* subsystems. Called early from init/main.c.
*/
void __init driver_init(void)
{
/* These are the core pieces */
devtmpfs_init();
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init(); /* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
}
这个函数完成驱动子系统的构建,实现了Linux设备驱动的一个整体框架,接下来就可以真正的添加设备了,接下来逐个介绍这些函数的作用。
1、devtmpfs_int函数:
该函数注册一个名为devtmpfs的文件系统dev_fs_type,这部分和设备驱动子系统的建立关系并不大,这里不多做介绍
/*
* Create devtmpfs instance, driver-core devices will add their device
* nodes here.
*/
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 ;
}
2、devices_init函数:创建devices相关的设备模型
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 ; 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;
}
devices_init函数建立/sys/devices、/sys/dev这两个顶级容器节点和/sys/dev/block、/sys/dev/char这两个二级节点
devices_kset是在/driver/base/core.c中定义的全局变量,对应于sysfs的/sys/devices节点
dev_kobj是在/driver/base/core.c中定义的static变量, 对应于sysfs的/sys/dev节点
sysfs_dev_block_kobj是在/driver/base/core.c中定义的全局变量,是dev_kobj的子节点,对应于sysfs的/sys/dev/block,该节点是所有block设备的父节点
sysfs_dev_char_kobj是在/driver/base/core.c中定义的全局变量,是dev_kobj的子节点,对应于sysfs的/sys/dev/char,该节点是所有char设备的父节点
3、buses_init函数:建立Linux设备模型总线部分的顶级节点
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
if (!bus_kset)
return -ENOMEM;
return ;
}
buses_init函数建立了/sys/bus这个顶级容器节点,该节点是Linux内核中所有总线类型的父节点,
bus_kset是drivers/base/bus.c中定义的static变量。
4、classes_init函数:建立Linux设备模型类部分的顶级容器节点
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
return ;
}
建立了/sys/class这个顶级容器节点,该节点是Linux内核中所有class类型的父节点,class_kset是drivers/base/class.c中定义的static变量
5、firmware_init函数:建立Linux设备模型中firmware部分的顶级节点
int __init firmware_init(void)
{
firmware_kobj = kobject_create_and_add("firmware", NULL);
if (!firmware_kobj)
return -ENOMEM;
return ;
}
建立了/sys/firmware这个顶级kobj节点,firmware_kobj是在drivers/base/firmware.c定义的全局变量
6、hypervisor_init函数:建立hypervisor_kobj的顶级容器节点
int __init hypervisor_init(void)
{
hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);
if (!hypervisor_kobj)
return -ENOMEM;
return ;
}
建立了/sys/hypervisor这个顶级节点,hypervisor_kobj是在 drivers/base/hypervisor.c中定义的全局变量
--------------------------------------------------------------------我是分割线-----------------------------------------------------------------------
前面几个函数执行完成后基本已经建立起Linux设备模型的框架了,接下来几个函数都是在前面框架中的扩展
7、platform_bus_init函数:
初始化Linux平台总线,平台总线(platform_bus_type)是在2.6 kernel中引入的一种虚拟总线,主要用来管理CPU的片上资源,具有较好的可移植性能,因此在2.6及以后的kernel中,很多驱动都已经用platform改写了
int __init platform_bus_init(void)
{
int error; early_platform_cleanup(); error = device_register(&platform_bus);
if (error)
return error;
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
platform_bus_init函数中引入两个变量platform_bus,platform_bus_type,均为在drivers/base/platform.c中定义的全局变量,如下:
struct device platform_bus = {
.init_name = "platform",
};
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
该函数先调用device_register函数注册platform_bus这个设备,这会在/sys/devices/节点下创建platform节点/sys/devices/platform,此设备节点是所有platform设备的父节点,即所有platform_device设备都会在/sys/devices/platform下创建子节点
然后调用bus_register函数注册platform_bus_type这个总线类型,这会在/sys/bus目录下创建一个platform节点,这个节点是所有platform设备和驱动的总线类型,即所有platform设备和驱动都会挂载到这个总线上;
8、system_bus_init函数:在/sys/devices/下建立system容器节点
int __init system_bus_init(void)
{
system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
if (!system_kset)
return -ENOMEM;
return ;
}
通过kset_create_and_add函数建立了/sys/devices/system这个容器节点,system_kset是drivers/base/sys.c中定义的static变量。
这个节点中主要是一些和cpu、中断控制器、时钟之类的设备
9、cpu_dev_init函数:建立一个名为”cpu”的类
int __init cpu_dev_init(void)
{
int err; err = sysdev_class_register(&cpu_sysdev_class);
#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
if (!err)
err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
#endif return err;
}
调用sysdev_class_register函数注册cpu_sysdev_class这个类,cpu_sysdev_class是在drivers/base/cpu.c中定义的全局变量,如下:
struct sysdev_class cpu_sysdev_class = {
.name = "cpu",
.attrs = cpu_sysdev_class_attrs,
};
sysdev_class_register函数中将父节点设置为前面system_bus_init时创建的变量system_kset,即/sys/devices/system/节点;因此cpu_dev_init函数会在/sys/devices/system/节点下建立一个名为cpu的子节点/sys/devices/system/cpu/,该节点包含CPU相关的属性
10、memory_dev_init函数:建立memory设备在sysfs中的接口
/*
* Initialize the sysfs support for memory devices...
*/
int __init memory_dev_init(void)
{
unsigned int i;
int ret;
int err;
unsigned long block_sz; memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops;
ret = sysdev_class_register(&memory_sysdev_class);
if (ret)
goto out; block_sz = get_memory_block_size();
sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; /*
* Create entries for memory sections that were found
* during boot and have been initialized
*/
for (i = ; i < NR_MEM_SECTIONS; i++) {
if (!present_section_nr(i))
continue;
err = add_memory_section(, __nr_to_section(i), MEM_ONLINE,
BOOT);
if (!ret)
ret = err;
} err = memory_probe_init();
if (!ret)
ret = err;
err = memory_fail_init();
if (!ret)
ret = err;
err = block_size_init();
if (!ret)
ret = err;
out:
if (ret)
printk(KERN_ERR "%s() failed: %d\n", __func__, ret);
return ret;
}
这边与cpu_dev_init函数类似,先调用sysdev_class_register函数注册memory_sysdev_class这个类,cpu_sysdev_class是在drivers/base/memory.c中定义的全局变量,如下:
#define MEMORY_CLASS_NAME "memory"
static struct sysdev_class memory_sysdev_class = {
.name = MEMORY_CLASS_NAME,
};
因此与cpu_dev_init函数类似,将memory_sysdev_class的父节点设置为前面system_bus_init时创建的变量system_kset,因此会在/sys/devices/system/节点下建立一个名为”memory”的子节点/sys/devices/system/memory/;该节点包含了内存相关的属性,如块大小等
Linux设备子系统初始化的更多相关文章
- linux文件系统 - 初始化(二)
加载initrd(上) 一.目的 本文主要讲述linux3.10文件系统初始化过程的第二阶段:加载initrd. initrd是一个临时文件系统,由bootload负责加载到内存中,里面包含了基本的可 ...
- linux文件系统 - 初始化(一)
术语表: struct task:进程 struct mnt_namespace:命名空间 struct mount:挂载点 struct vfsmount:挂载项 struct file:文件 st ...
- linux文件系统初始化过程(5)---加载initrd(下)
一.目的 linux把文件分为常规文件.目录文件.软链接文件.硬链接文件.特殊文件(设备文件.管道文件.socket文件等)几种类型,分别对应不同的新建函数sys_open().sys_mkdir() ...
- linux文件系统初始化过程(2)---挂载rootfs文件系统
一.目的 本文主要讲述linux3.10文件系统初始化过程的第一阶段:挂载rootfs文件系统. rootfs是基于内存的文件系统,所有操作都在内存中完成:也没有实际的存储设备,所以不需要设备驱动程序 ...
- linux文件系统初始化过程(1)---概述
术语表: struct task:进程 struct mnt_namespace:命名空间 struct mount:挂载点 struct vfsmount:挂载项 struct file:文件 st ...
- linux系统初始化——文件系统初始化步骤
linux文件系统初始化步骤 System V init启动过程 概括地讲,Linux/Unix系统一般有两种不同的初始化启动方式. 1) BSD system init 2) System V in ...
- Linux系统启动初始化
文章目录 一.BIOS 加载启动引导程序 二.MBR 主引导扇区 三.GRUB引导内核 3.1运行 boot.img 3.2加载 core.img 3.3切换到保护模式 3.4kernel.img 引 ...
- Linux启动初始化配置文件
Linux启动初始化配置文件(1)/etc/profile 登录时,会执行. 全局(公有)配置,不管是哪个用户,登录时都会读取该文件. (2)/ect/bashrc Ubuntu没有此文件,与之对应的 ...
- linux环境初始化 用户问题
linux 初始化系统配置(centos6) (2013-04-03 13:19:15) 转载▼ 分类: linux 这篇博文是从别处转来的,原文地址http://zhoualine.iteye. ...
随机推荐
- Python爬取抖音高颜值小视频
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 有趣的python PS:如有需要Python学习资料的小伙伴可以加 ...
- Maven+JSP+SSM+Mysql+C3P0实现的学生管理系统
项目简介 项目来源于:https://gitee.com/wu_yun_long/student_management_system 本系统是基于Maven+JSP+SSM+Mysql+C3P0实现的 ...
- vue原生表格怎样实现动态列及表格数据下载
最近项目经常用到带有合并效果以及动态列的表格,而翻阅iview和element-ui官网没有找到合适的(也有可能自己的水平有限,不会改写),所以只好自己用原生表格写了一个,具体效果如下: 这个表格右侧 ...
- search(7)- elastic4s-search-filter模式
现在我们可以开始探讨ES的核心环节:搜索search了.search又分filter,query两种模式.filter模式即筛选模式:将符合筛选条件的记录作为结果找出来.query模式则分两个步骤:先 ...
- 轻量级mysql安装教程-避免采坑
1:安装包获取 安装了很多次,来来回回踩,踩出了一片光明大道,简单好用. 百度网盘获取:链接:https://pan.baidu.com/s/13frFBTODaMeADZOHj5KdJQ 提取码:a ...
- 科学计算包Numpy
Numpy 用于科学计算的python模块,提供了Python中没有的数组对象,支持N维数组运算.处理大型矩阵.成熟的广播函数库.矢量运算.线性代数.傅里叶变换以及随机数生成等功能,并可与C++.FO ...
- Makefile 中引用多个 include 路径
LIB=-L/usr/informix/lib/c++ INC=-I/usr/informix/incl/c++ -I/opt/informix/incl/public default: main m ...
- 徐州H
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #defi ...
- XmlSerializer .NET 序列化、反序列化
序列化对象 要序列化对象,首先创建要序列化的对象并设置其公共属性和字段.为此,您必须确定要将XML流存储的传输格式,作为流或文件. 例如,如果XML流必须以永久形式保存,则创建一个FileStre ...
- bootstrap-分页-默认分页
说明 默认分页 示例 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta c ...