- KASLR kernel address space layout randomization 内核地址空间布局随机化
本质是将链接的地址做了随机偏移,这样System.map中的地址也不一样了,需要用 cat /proc/kallsyms才能查看到实际的地址。主要还是为了安全,这样地址布局随机化,来增加安全,被攻击的难度会增加。
- 防止利用内核漏洞。由于struct等数据结构会产生内核漏洞,通过随机化的方式将这些地址随机,这样攻击者就难以定位。
- 提高安全性。每次引导得到的内核和内存地址都不用,即使得到上一次的内存布局,下一次就不再有效。
- 减少信息泄露的影响
通过 CONFIG_RANDOMIZE_BASE
开启
启动流程
设备树加载与解析
设备树最开始在Image末尾,由uboot加载到.init.data中,存在的地址相当于物理地址。
start_kernel->
setup_arch-> (对架构进行解析、包括设备树)
setup_machine_fdt
(本函数得到在.init.data中地址(物理地址)转换后的虚拟地址)
unflatten_device_tree->
__unflatten_device_tree->
unflatten_gt_nodes
(执行两次,第一次得到转换成struct device_node所需要的空间后,分配内存。第二次真正开始解析设备树节点。)
unflatten_dt_nodes
从根节点开始:
- fdt_next_node 找下一个节点
- populate_node 为当前节点申请空间,并对node进行初始化,并且根据内容进行填充
- 会对深度进行设置从而得到父子关系
各个子系统初始化
子系统初始化和设备的初始化,都在最后一步rest_init中的do_initcalls中
rest_init->
user_mode_thread(kernel_init, NULL, CLONE_FS)-> (开启0号进程)
kernel_init->
kernel_init_freeable->
do_basic_setup->
do_initcalls
顺便说一下,kernel_init中,会执行1号进程,首先判断是不是ramdisk(/init),其次会检查传入的命令中指定的1号进程,最后会依次判断 "/sbin/init" "/etc/init" "/bin/init" "/bin/sh"
do_initcalls中会从level0依次执行各种初始化函数。
其中 宏定义__define_initcall(fn, id)
会将函数指针fn放在section段 .initcall##id.init,通过段名设置优先级(各个段依次执行)。
这样就可以回答下面几个问题
- 设备什么时候开始注册
注册函数of_platform_default_populate_init
被放到了 .init.text中,被定义到 .initcall3s中(arch_initcall_sync(of_platform_default_populate_init)
)
所以在执行 do_initcalls
就会执行到of_platform_default_populate_init进行设备的注册
of_platform_default_populate_init->
of_platform_default_populate->
of_platform_populate->
(从根节点开始遍历所有节点)
of_platform_bus_create->
of_device_alloc
dev->dev.bus = &platform_bus_type
of_device_add->
device_add
-
各个子系统的注册
会通过__define_initcall(fn,id)
注册到段中,依次注册 -
Bus的初始化流程
同样注册也是在 rest_init
中执行
rest_init->
kernel_init->
kernel_init_freeable->
do_basic_setup->
driver_init->
devices_init->
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
(在/sys/下创建device)
dev_kobj = kobject_create_and_add("dev", NULL)
(在sys/下创建dev)
buses_init->
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL)
(在sys/下创建bus kset)
classes_init->
class_kset = kset_create_and_add("class", NULL, NULL);
(在sys/下创建class kset)
platform_bus_init->
device_register
bus_register
(注册总线)
do_initcalls
device和driver匹配流程
总的来说,总线将设备树中的设备描述(device)与驱动文件(driver)统一管理,并且总线提供了match函数,用来将device与driver匹配上,然后调用driver的probe进行初始化
- 设备和驱动在注册到bus管理的链表中的时候都会去遍历匹配对应的驱动或者设备。
- 几种匹配
- pdev中dirver_override和drv的name匹配
- of_driver_match_device(设备树匹配)
- acpi_driver_match_device(acpi匹配)
- id_table匹配
- pdev和drv中name匹配
文件系统挂载
start_kernel
>vfs_caches_init(fs/dcache.c)
初始化根目录/
>mnt_init((fs/namespace.c))
>sysfs_init(fs/sysfs/mount.c)注册sysfs文件系统(创建根目录,注册到全局链表file_system中)
>fs_kobj = kobject_create_and_add("fs", NULL);在sys/下创建fs kobject
>shmem_init(mm/shmem.c)注册tmpfs文件系统
>init_rootfs(init/do_mounts.c)
>init_mount_tree(fs/namespace.c)
>proc_root_init(fs/proc/root.c)注册proc文件系统
>rest_init
>kernel_init
>kernel_init_freeable(init/main.c)
>do_basic_setup
>do_initcalls
>core_initcall(debugfs_init)注册debugfs文件系统
解压根文件系统
>rootfs_initcall(populate_rootfs)(init/initramfs.c)
>populate_rootfs(init/initramfs.c)
>do_populate_rootfs(init/initramfs.c)解压cpio包
>prepare_namespace(/init不存在等情况,initramfs不涉及)
>run_init_process(ramdisk_execute_command)执行ramdisk_execute_command指定参数,即init=的值,默认为/init。调用进程会替换当前进程,执行成功不再返回
标签:do,populate,启动,kernel,bus,流程,init,linux,device
From: https://www.cnblogs.com/alanli07/p/18399618