COCONUT-SVSM 代码初次阅读
本文最后更新于 117 天前,其中的信息可能已经有所发展或是发生改变。

SVSM: Secure VM Service Module,即安全虚拟机服务模块。

SVSM 的白皮书:https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/58019.pdf

COCONUT-SVSM 项目地址:GitHub – coconut-svsm/svsm: COCONUT-SVSM

git clone https://github.com/coconut-svsm/svsm
cd svsm
git submodule update --init
cargo install bindgen-cli

这个项目是使用 Rust 语言编写的,前期需要安装 Rust 相关工具。

阅读大型项目还是非常推荐安装语言服务器的,这样可以概览一个代码文件实现的函数情况,从而有针对性的阅读。

项目概览

项目根目录下就放了很多目录,大部分是项目所需的库和工具。需要关注的几个代码文件夹是:

  • cpuarch:有 ARM 架构相关的内容,其中包含 VMSA (VM Shared Area)。

  • kernel:项目核心代码文件夹了。

  • stage1:第一启动阶段。

  • syscall:系统调用相关的代码。

其他文件夹就按需阅读。

项目主体

项目的主题代码都在 kernel 目录下。打开文件夹后,可以看看 kernel 的目录结构:

  • 各个功能模块,包括:

    • acpi:中断控制相关。

    • cpu:抽象虚拟 cpu 模块。

    • fs:ram_fs 文件系统。

    • locking:锁功能模块。

    • mm:内存管理模块。

    • platform:具体的 Guest CPU 的实现。

    • protocols:按照 SVSM 白皮书实现的相关接口功能。

    • sev:即 SEV 的相关功能。

    • syscall:系统调用。

    • task:任务管理模块。

    • vtpm:TPM 的相关实现。

    • 一些其他功能模块。

  • 单独的代码文件。

这么一看,SVSM 堪称一个完成的操作系统。在单独的代码文件中,可以看到 svsm.rs 代码文件。不妨先从这个代码文件入手。

通过浏览这个代码实现的函数,就发现两个可能比较重要的函数。一个 svsm_start,一个 svsm_main。先来看看后者。

svsm_main 完成了 SVSM 客户机的初步配置。包括 SVSM 平台的环境初始化,SVSM 参数配置,相关内存空间的初始化和拷贝。通过 config.load_cpu_info 函数获取 CPU 相关信息和中断相关信息。然后,调用 start_kernel_task 来启动一个 kernel 任务。

再看看 svsm_start,似乎感觉这个代码才是 SVSM 的主函数。不仅完成了整个 SVSM 的GDT 和 IDT 的初始化,还完成每个 BSP_CPU 的初始化(此处的 BSP 指的是 Bootstrap Processor),包括页表,架构,以及初始任务。这个初始任务,就是 svsm_main。最后,通过调度的方式,进入到 svsm_main 中执行。

svsm_start 有两个函数参数,应该还有其他函数来调用该函数。直接看代码,不太能直接找到这个函数。但是再看看文件目录,找到了 svsm.lds 链接文件。链接文件的内容如下:

OUTPUT_ARCH(i386:x86-64)

SECTIONS
{
    . = 0xffffff8000000000;
    .text : {
        *(.startup.*)
        *(.text)
        *(.text.*)
        . = ALIGN(16);
        entry_code_start = .;
        *(.entry.text)
        entry_code_end = .;
        . = ALIGN(16);
        exception_table_start = .;
        KEEP(*(__exception_table))
        exception_table_end = .;
    }
    . = ALIGN(4096);
    .rodata : { *(.rodata) *(.rodata.*) }
    . = ALIGN(4096);
    .data : { *(.data) *(.data.*) }
    . = ALIGN(4096);
    .bss : {
        *(.bss) *(.bss.*)
        . = ALIGN(4096);
    }
    . = ALIGN(4096);
}

ENTRY(startup_64)

大概率,整个 SVSM 的启动代码是用汇编写的。用 grep 命令搜索一下 startup,结果发现,startup 的汇编代码是镶嵌在 Rust 代码中的,也就在svsm.rs 文件中。startup 的汇编代码如下:

    .text
    .section ".startup.text","ax"
    .code64

    .globl  startup_64
startup_64:
    /* Setup stack */
    leaq bsp_stack_end(%rip), %rsp

    /* Jump to rust code */
    movq    %r8, %rdi
    movq    %r9, %rsi
    jmp svsm_start

    .bss

    .align {PAGE_SIZE}
bsp_stack:
    .fill 8*{PAGE_SIZE}, 1, 0
bsp_stack_end:

startup_64 也仅仅初始化了栈的大小以及将 r8r9 值拷贝到传递参数的两个寄存器中,并调用 svsm_start。这样看来,系统的根也不在这里。再读读 startup_64 的注释,得到了是 stage2 加载器设置的该入口。

第一阶段启动过程

第一阶段启动过程 (stage1) 的代码在 SVSM 项目根目录下  stage1 文件夹中。主要是 resetstage1 两个汇编代码。后者完成了激活缓存和准备 stage2 启动的工作。

stage2 的准备工作

第二阶段的启动准备工作包括以下内容:

  • 初始化栈指针第二阶段启动二进制文件相关信息,起始和终止地址内核二进制文件的相关信息,起始和终止地址

  • 将 BSP 一些元数据压入栈。

  • 跳转第二阶段启动地址,进入二阶段启动。

第二阶段启动过程

第二阶段启动过程的代码在 kernel/stage2.rs 文件中。从 stage2.lds 链接文件中可以看出,其入口函数仍然为 startup 函数。startup 函数在 boot_stage2.rs 文件中实现。该函数完成一些页面初始化后,调用了 stage2_main 函数。stage2_main 函数在 kernel/stage2.rs 中实现。

stage2_main 函数完成了以下内容:

  • 初始化平台的类型。

  • 获取 SVSM 的配置信息。

  • 分配内核的内存空间。

  • 加载第一块内核的ELF和IGVM,得到 kernel_entry 的地址。

  • 设置内核的启动选项。

  • 设置内核启动选项参数,跳转到 kernel_entry,实际上就是 startup_64

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇