Magenta
来源:互联网 发布:侠客行 叮叮当当 知乎 编辑:程序博客网 时间:2024/06/05 11:41
Magenta-Userboot
在kernel初始化完毕后,需要跳转至user space并初始化user的init进程(devmgr),此也是user的第一个进程。为了可以顺利的启动user进程,magenta在 编译,初始化和启动 阶段分别做了特殊处理。
userboot就是专为此而实现的模块。包括:
- kernel userboot:运行在kernel空间,为进入user空间做准备
- user userboot:运行在user空间,加载init进程。
编译阶段
user userboot的编译
以目录 /system/core/userboot为基础,生成libuserboot.so,这是user userboot的主体部分。libuserboot.so需要通过sys-call功能访问magenta。所以基于目录/system/ulib/magenta 生成了动态库libmagenta.so。其内容形如其下:
...00000000000064cc <_mx_handle_close>: 64cc: 41 52 push %r10 64ce: 41 53 push %r11 64d0: 49 89 ca mov %rcx,%r10 64d3: b8 02 00 00 00 mov $0x2,%eax 64d8: 0f 05 syscall 00000000000064da <CODE_SYSRET_mx_handle_close_VIA_mx_handle_close>: 64da: 41 5b pop %r11 64dc: 41 5a pop %r10 64de: c3 retq ...
可见实现了系统调用接口。user code可以加载此.so以访问kernel所提供功能。
但是user userboot比较特殊,它运行在kernel创建的进程中,且是第一个user process。在它进入user space时,没有现成的user environment,需要自己创建并配置。由于libuserboot.so在初期就需要访问kernel,为了减少加载.so时所需的重定位等等步骤,magenta对libuserboot.so的编译做了特殊处理,即在编译libuserboot.so阶段就固定libuserboot.so和libmagenta.so的相对地址。这样libuserboot.so可以以PC-relative的方式访问libmagenta.so提供的函数。为了达到此目的,需要解析libuserboot.so和libmagenta.so中的代码和数据的layout结构。
编译libuserboot.so后,根据链接脚本rodso.ld,以及其中定义的 CODE_START/CODE_END,利用脚本生成文件userboot-code.h,其内容形如:
#define USERBOOT_FILENAME "./build-magenta-pc-x86-64/system/core/userboot/libuserboot.so"#define USERBOOT_DATA_START_dynsym 0x0000000000000298#define USERBOOT_DATA_END_dynsym 0x00000000000002b0#define USERBOOT_CODE_START 0x0000000000003000#define USERBOOT_ENTRY 0x0000000000003a40#define USERBOOT_ENTRY_SIZE 0x00000000000009df#define USERBOOT_CODE_END 0x000000000000d000
可以得到libuserboot.so的文件偏移layout。这是供kernel userboot加载libuserboot.so时所用。
编译libmagenta.so后,根据链接脚本rodso.ld,以及其中定义的 CODE_START/CODE_END,利用脚本生成文件vdso-code.h,其内容形如:
#define VDSO_FILENAME "./build-magenta-pc-x86-64/system/ulib/magenta/libmagenta.so"#define VDSO_DATA_START_dynsym 0x0000000000000c38#define VDSO_DATA_END_dynsym 0x00000000000027b0#define VDSO_DATA_CONSTANTS 0x0000000000003d20#define VDSO_DATA_CONSTANTS_SIZE 0x0000000000000018#define VDSO_CODE_START 0x0000000000006000#define VDSO_CODE_soft_ticks_get 0x00000000000062a0#define VDSO_CODE_soft_ticks_get_SIZE 0x0000000000000007....#define VDSO_CODE_END 0x0000000000007000...
可以得到libmagenta.so的文件偏移layout。这是供kernel userboot加载libmagenta.so时所用。
为了让libuserboot.so可以直接访问到libmagenta.so,基于libmagenta.so,利用脚本生成2个文件vdso-syms.h、vdso-syms.ld,供libuserboot.so编译和链接使用。此2个文件形如其下:
vdso-syms.h:...FUNCTION(_mx_handle_close, 0x00000000000064cc, 0x0000000000000013)WEAK_FUNCTION(mx_handle_close, 0x00000000000064cc, 0x0000000000000013)...
vdso-syms.ld:...PROVIDE_HIDDEN(_mx_handle_close = CODE_END + 0x00000000000064cc);...
宏的定义如下:
#define FUNCTION(name, address, size) \ PROVIDE_HIDDEN(name = CODE_END + address);#define WEAK_FUNCTION(name, address, size) FUNCTION(name, address, size)
注:CODE_END指libuserboot.so的代码结束地址,即 USERBOOT_CODE_END。定义了属性PROVIDE_HIDDEN,可以生成简单的PC-relative 代码。
经过上述处理后,如libuserboot.so需要访问系统调用mx_handle_close,则会直接调转至CODE_END + 0x00000000000064cc处。所以需要kernel userboot将libmagenta.so加载至libuserboot.so其后。下图是libmagenta.so和libuserboot.so两者之间的布局示意图。
最后,需要利用宏
RODSO_IMAGE
将libmagenta.so和libuserboot.so作为数据内嵌到magenta.bin文件中,不依赖文件系统就可以访问此2个.so文件。
初始化阶段
此阶段指的是kernel userboot为进入user space所做的各种准备,所需资源包括如下:
enum bootstrap_handle_index { BOOTSTRAP_VDSO, BOOTSTRAP_VDSO_LAST_VARIANT = BOOTSTRAP_VDSO + VDso::variants() - 1, BOOTSTRAP_RAMDISK, BOOTSTRAP_RESOURCE_ROOT, BOOTSTRAP_STACK, BOOTSTRAP_PROC, BOOTSTRAP_THREAD, BOOTSTRAP_JOB, BOOTSTRAP_VMAR_ROOT, BOOTSTRAP_HANDLES};
kernel userboot会创建各种object和其对应的handle,并将handle转移并映射到新进程中,从而新进程启动后可以访问此些资源。
- 创建Job Object: 在root job下创建一个新的job obj,并同步创建对应的handle,此即是BOOTSTRAP_JOB。
- 创建Process Object :在root job下创建name是 “userboot”的process obj,并创建一个handle 指向此obj,此handle即BOOTSTRAP_PROC;同步也创建的进程的vmaro(virtual memory address region object),用于管理进程的的虚拟空间,并同步创建对应的handle,此即是BOOTSTRAP_VMAR_ROOT。
- 创建Thread Object : 在”userboot”的process中创建name是 “userboot”的thread obj,并创建一个handle指向此obj,此handle即BOOTSTRAP_THREAD;
- 创建Ramdisk Object: 根据Ramdisk在ram中的基地址和长度,创建vmo(virtual memory object)。vmo可以理解为RAM中的数据块,可以通过handle对此数据块读写。然后创建一个handle指向此obj,此handle就是BOOTSTRAP_RAMDISK。user process可以根据此obj读取Ramdisk并解析,然后将文件释放到文件系统中。
- 创建VDSO Object: 根据vdso在ram中的基地址和长度,创建vmo。并同步创建对应的handle,此即是BOOTSTRAP_VDSO;
- 创建Stack Object: 创建一个大小为stack size的vmo。并同步创建对应的handle,此即是BOOTSTRAP_STACK。此vmo在此阶段并没有实际分配物理page,待后期stack缺页中断时再分配物理page。
- 创建Resource Object: 创建root resource,并同步创建对应的handle,此即是BOOTSTRAP_VMAR_ROOT。
创建完所需资源后,开始对user userboot的加载:
- 根据libuserboot.so在ram中基地址和长度,创建 “userboot” vmo;
- 结合”userboot” vmo和vdso vmo的总长度,即libmagenta.so和libuserboot.so的总长度,在新进程的虚拟空间中分配对应长度的虚拟空间vmar,然后将这2个vmo映射至此vmar。
- 将stack obj映射进新进程的虚拟空间,从而新线程有课自己的栈空间;
- 创建channel obj,一端定义为kernel_channel obj,另一端定义为user_channel_handle obj。kernel利用kernel_channel将boot trap msg写入此channel; 创建一个handle指向user_channel_handle obj,并将此handle映射进新进程的handle空间,从而在新进程的user space可以通过此handle读取到boot trap msg。
- 根据映射时得到的libmagenta.so和libuserboot.so虚拟地址,启动新线程,并将user_channel_handle 和vdso基地址作为参数传给user code。
以上加载时的log表现如下:
[00000.064] 00000.00000> userboot: ramdisk 0x358000 @ 0xffffff8000252000[00000.069] 00000.00000> userboot: userboot rodata 0 @ [0xe3d00fc6000,0xe3d00fc9000)[00000.069] 00000.00000> userboot: userboot code 0x3000 @ [0xe3d00fc9000,0xe3d00fd3000)[00000.069] 00000.00000> userboot: vdso/full rodata 0 @ [0xe3d00fd3000,0xe3d00fd9000)[00000.070] 00000.00000> userboot: vdso/full code 0x6000 @ [0xe3d00fd9000,0xe3d00fda000)[00000.071] 00000.00000> userboot: entry point @ 0xe3d00fc9a40
新线程经如下调用
UserThread::Start --》 UserThread::StartRoutine --》arch_enter_uspace
切换至user space。不同的arch,arch_enter_uspace的实现不一样。
启动阶段
此阶段是在user space,新线程的entry地址是_start,实现在文件start.c中。有如下流程:
- 从bootstrap_message中读取环境变量和参数,以及handles;
- 在channel read时,kernel会将handles映射于当前process中,且将得到的
handle返回给user;
- 在channel read时,kernel会将handles映射于当前process中,且将得到的
- 创建process “bin/devmgr”
- load文件”bin/devmgr”至process “bin/devmgr”;
- 由于devmgr中有section interp,所以其实是load此interp “lib/ld.so.1”
- 将相关msg写入msgpipe,以便ld.so.1读取并解析;参数包括需要加载的文件名,即”bin/devmgr”;
- 创建并映射stack至process “bin/devmgr”;
- 创建新thread,
- 将启动参数和handles写于msgpipe;
- start process, 在新进程中执行lib/ld.so.1的entry函数。
- 启动loader_service,以响应ld.so.1的加载module的请求。如ld.so.1依赖其他lib,则当ld.so.1初始化时,需要加载依赖库。如”bin/devmgr”有依赖libs,也需此service帮忙load libs。当从ld.so.1跳转至“bin/devmgr”后,会关闭此service。
- 如果loader service退出了,则”userboot”进程退出。
注: ld.so.1 其实本身就是libc.so(musl)
从上可见,分了2个步骤来加载文件”bin/devmgr”:
- libuserboot.so在用户进程中加载ld.so.1,并跳转至其entry函数;
- ld.so.1完成其自身初始化后,加载文件”bin/devmgr”;
libc.so的entry函数是_start,不同arch有不同的定义,但流程都一样。
- _start
- _dl_start :重定位;
- __dls2 :映射”libc.so”和””,这2个模块由libuserboot.so之前已经加载完毕
- __dls3 :读取并解析bootstrap msg,包含handles以及argc/env,配置了当前进程的运行环境;得到application vmo,即文件”bin/devmgr”的vmo。
- dls3 : load “bin/devmgr” vmo至当前process;在此过程中,以请求loader service加载依赖libs;
- jump to application entry(即devmgr entry)
相关的log如下:
[00000.119] 01029.01036> userboot: searching bootfs for program "bin/devmgr"[00000.120] 01029.01036> userboot: bin/devmgr has PT_INTERP "lib/ld.so.1"[00000.120] 01029.01036> userboot: searching bootfs for dynamic linker "lib/ld.so.1"[00000.126] 01029.01036> userboot: process bin/devmgr started.[00000.126] 01029.01036> userboot: waiting for loader-service requests...
以上是 libuserboot.so运行时的log。
[00000.128] 01029.01036> userboot: searching bootfs for shared library "lib/libfs-management.so"[00000.129] 01029.01036> userboot: searching bootfs for shared library "lib/liblaunchpad.so"[00000.130] 01029.01036> userboot: searching bootfs for shared library "lib/libmxio.so"[00000.133] 01043.01046> Loaded at [0x51ab193c6000,0x51ab193e4000): <application>[00000.133] 01043.01046> Loaded at [0x6904190c000,0x69041910000): libfs-management.so[00000.133] 01043.01046> Loaded at [0x229a645d5000,0x229a645de000): liblaunchpad.so[00000.133] 01043.01046> Loaded at [0x3f0516fc9000,0x3f0516fe2000): libmxio.so[00000.133] 01043.01046> Loaded at [0x6212fec84000,0x6212fec8b000): <vDSO> (libmagenta.so)[00000.133] 01043.01046> Loaded at [0x65db29b63000,0x65db29c43000): libc.so
以上是libc.so运行时的log。可见加载了3个依赖libs。
[00000.141] 01043.01046> devmgr: main()
以上是libc.so初始化完后,跳转至devmgr。
...[00000.147] 01029.01036> userboot: loader-service channel peer closed[00000.147] 01029.01036> userboot: finished!
以上是loader service退出后,userboot进程也自动退出。
- Magenta
- Magenta
- Magenta
- Magenta
- Magenta
- Magenta
- Magenta
- 编译Magenta
- Magenta Demos Magenta 实战代码
- Magenta- Qemu + bootloader
- Magenta- 支持虚拟化
- 安装 magenta 失败:rtmidi
- Fuchsia使用的内核Magenta
- Magenta与LK的关系
- 在qemu中运行magenta
- Magenta: devmgr进程的线程分布
- 树莓派3上运行Fuchsia/Magenta OS
- Magenta源代码笔记(3) —— 内存管理
- ip地址 子网掩码 默认网关的联系
- C++11:深入理解右值引用,move语义和完美转发
- 微信小程序Redux绑定
- Myeclipse安装Gradle插件
- C# 面向对象:类、根据不同操作符操作两个变量
- Magenta
- CentOS firewall和selinux相关
- java 多态 父类引用指向子类对象
- Android事件分发机制详解:史上最全面、最易懂
- ubuntu find+sed+grep+args
- python3.5学习笔记:linux6.4 安装python3 pip setuptools
- IIS下建立负载均衡的虚拟目录方法
- 70. Climbing Stairs
- 衰落信道中的平均信噪比和瞬时信噪比