# CcLoader ## 概述 ccoskrnl使用UEFI引导内核。由于使用EDK2进行UEFI开发,所以入口函数应该是UefiMain而不是efi_main。所以第一行代码应该从UefiMain开始编写。UEFI是一套规格书,定义了固件平台与操作系统之间的接口,底层固件产商负责实现这些接口,而操作系统产商则可以调用这些接口,只要产商们都遵循UEFI标准,操作系统跟硬件便可以无缝衔接。 加载器为操作系统内核提供了一个随机数(如果它所在的UEFI平台支持随机数协议的话),这个随机数在后面可能会用到,考虑到能产生随机数的方式很多,所以即使平台不支持也无关紧要。 ## 流程 MachineInfo结构体收集当前机器的各种信息并将这些信息传递给操作系统内核供后续使用。 加载器首先会调整屏幕分辨率,一般情况下屏幕分辨率会被设置为当前显示器所支持的最大的分辨率。接着会调用GetEfiMemMap()函数来获得当前机器的内存布局,内核后续会根据这个结构来初始化内存管理器。UEFI提供了很方便的功能方便开发者快速找到ACPI表,ACPI表记录了当前设备的一些硬件信息,操作系统需要使用这些信息去启用和初始化这些硬件。 之后加载器根据当前的内存信息来设置内核空间的大小,一般内核大小为内存的四分之一,最高为2G。加载器向UEFI请求这块内存,并将内核镜像加载到新申请好的内存空间中。 当完成上面这些工作之后加载器就可以调用`ExitBootServices()`来转到加载二阶段了。 当UEFI应用程序调用`ExitBootServices()`后,Intel 64 CPU(x86-64架构)将处于以下状态: - **单处理器模式**:CPU运行在单处理器环境中,即使是多核心处理器也只有一个核心被激活。 - **长模式**:CPU处于64位的长模式,这意味着它可以访问64位的指令集和寻址能力。 - **分页启用**:分页机制被启用,所有页面都被标识映射,这意味着虚拟地址直接映射到相同的物理地址。 - **平坦模式的段选择器**:段选择器(如CS、DS等)被设置为平坦模式,这意味着段的基址为0,段的限长为最大值,从而允许访问整个64位的线性地址空间。 在`ExitBootServices()`调用之后,UEFI不再提供引导服务,操作系统加载器需要接管所有硬件资源的管理。 CcLoader主要使用了额外的二进制程序`ccldr`来进一步引导内核。ccldr是由NASM格式的汇编语言开发的一个简单的小程序。 在UefiMain的末尾会跳转到ccldr程序的起始位置,并将MachineInfo结构体指针一并传递过来。ccldr简单设置了GDT(x86_64架构中定义的一个非常重要的数据结构),并将加载器所使用的内存空间映射到虚拟地址空间相同的位置。接着ccldr将申请好的并存放来内核镜像的内存空间映射到虚拟地址的高地址处,最后跳转到内核的`krnl_start`函数。 ## Q&A **为什么要先构建一个临时的页表再把控制权移交给内核?** 临时页表需要将物理内存中预留的内核空间内存映射到虚拟地址空间的高地址部分(以0xfffff00000000000为基地址)。内核空间的大小一般设置为 **总空闲物理内存的大小的四分之一**。分页机制从`UefiMain()`函数开始之前就已经启用,假如不使用临时页表机制而直接将控制权移交给内核,那么在执行内核镜像的代码期间将很难(这并不是不可能,但是实现逻辑将会变得更加复杂)再将自身的镜像部分映射到虚拟地址空间的高地址部分。所以临时页表至少要将内核镜像提前映射到虚拟地址空间的高地址部分,并预留一部分空间供内核使用。UEFI程序为`ccldr`程序预留了16MiB内存空间供`ccldr`来存储临时页表。 ## References ### UEFI 1. **内存是怎么映射到物理地址空间的?内存是连续分布的吗?** https://zhuanlan.zhihu.com/p/66288943?utm_id=0 2. **UEFI启动流程概览** https://zhuanlan.zhihu.com/p/483888207 3. **UEFI Specification** https://uefi.org/specs/UEFI/2.10/01_Introduction.html 4. **ACPI Software Programming Model** https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html 5. **ACPI Overview** https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/Frontmatter/Overview/Overview.html