Save 37% off PRO during our Black Friday Sale! »

Practical Rust (Hypervisor) Firmware

Practical Rust (Hypervisor) Firmware

Rust Hypervisor Firmware is a small firmware written in Rust from scratch, which is dedicated to boot Linux cloud workloads on hypervisors. Since its main focus is to boot Linux, the supported guest OS is limited to the customized Ubuntu VM images and Clear Linux. In this talk, I will talk about how to boot recent versions of Windows from the firmware. In addition, I will describe how to port it to a physical machine like MinnowBoard MAX.

8dc3958dc2480bd681e4b5c197817047?s=128

Akira Moroo

July 10, 2021
Tweet

Transcript

  1. Practical Rust (Hypervisor) Firmware July 10, 2021 Kernel/VM Online Part

    3 @retrage
  2. Rust Hypervisor Firmware

  3. What’s Rust Hypervisor Firmware? • Small f irmware written from

    scratch in Rust • One of Cloud Hypervisor[1] subproject • Focuses on booting Linux cloud workloads • Ubuntu and Clear Linux • Supported VMMs: • Cloud Hypervisor and QEMU
  4. Architecture Overview • Minimal device drivers and f ilesystem support

    • VirtIO block device • FAT f ilesystem • Linux boot modes: • Native Linux loader • EFI compatible layer VirtIO Block Device FAT Filesystem EFI Compatible Layer Native Linux Loader Rust Hypervisor Firmware
  5. EFI Compatible Layer • Small subset of EFI features •

    Implemented 8 out of 39 EFI Boot Services • Enough to boot customized Ubuntu VM image • Works with typical Linux boot loaders (shim[2]+GRUB) • It was not compatible with the EFI spec. to boot: • Stock Ubuntu cloud images[3] • Other OSs?
  6. 🤔 Can it boot Windows?

  7. Challenge Accepted 😏

  8. How to Boot Windows

  9. Windows Boot Stages • Windows boot process has three steps[4]:

    1. Boot Manager (bootmgfw.e f i) • Determines boot order from EFI variables/BCD 2. OS Loader (winload.e f i) • Setups Windows speci f ic pre-boot process 3. NT OS Kernel (ntoskrnl.exe) • Need to support above chain loading
  10. Changes Needed to Boot Windows EFI Variable Support EFI Device

    Path Decoder Support Chain Loading Support Fix Memory Segments Directory Support for EFI File Protocol EFI Runtime Services Support Fix EFI Memory Map Clock/Delay Support Fix PE Loader
  11. Changes Needed to Boot Windows EFI Variable Support EFI Device

    Path Decoder Support Chain Loading Support Fix Memory Segments Directory Support for EFI File Protocol EFI Runtime Services Support Fix EFI Memory Map Clock/Delay Support Fix PE Loader
  12. Implement EFI Runtime Services

  13. Boot Services and Runtime Services • Boot Services: available during

    BDS phase and TSL phase • Runtime Services: must be always available DXE Run Time (RT) Transient System Load (TSL) Boot Device Selection (BDS) EFI Runtime Services Availability EFI Boot Services Availability
  14. EFI Boot Process System Control Hand-o ff Flow • Loader

    loads and starts OS • EFI Boot Services is still available at this point DXE Run Time (RT) Transient System Load (TSL) OS Loader OS Kernel Boot Device Selection (BDS) Boot Dispatcher Boot Manager
  15. EFI Boot Process System Control Hand-o ff Flow • The

    OS requests system control hand-off to the EFI • This is done by calling gBS->ExitBootServices () DXE Run Time (RT) OS Kernel Transient System Load (TSL) OS Loader OS Kernel Boot Device Selection (BDS) Boot Dispatcher Boot Manager ExitBootServices()
  16. Paging Problem Regarding EFI Runtime Services • The OS is

    responsible to manage the system memory • It also remaps the EFI Runtime Services to the new virtual address • The EFI Runtime Services code must be relocated EFI Runtime Code mov $0x175bd0, %rax call *%rax 0x175bd0: ... ... 0x175000: EFI Runtime Code mov $0x175bd0, %rax call *%rax 0xfffc607f046ebd0: ... ... 0xfffc607f046e000: Unrecoverable Page Fault Set new page table
  17. EFI Runtime Code Relocation • The OS must call gRT-

    >SetVirtualAddressMap() • It provides the new virtual address map to the EFI Runtime Services • The EFI Runtime Services do self relocation using given map • How to implement? SetVirtualAddressMap() 0x175000 -> 0xfffc607f046e000 ... EFI Runtime Code mov $0x175bd0, %rax call *%rax 0x175bd0: ... ... 0x175000: Self Relocator Fixup
  18. EFI Runtime Services Design • Generate EFI Runtime Services as

    an independent dynamic ELF binary • The binary is embedded in the static binary using objcopy • Relocator does 1st relocation • Self-relocator does 2nd relocation Boot Services Code Relocator Self Relocator Runtime Services (Dynamic ELF) Rust Hypervisor Firmware (Static ELF)
  19. Target Windows Guest Environment • Exactly same environment supported by

    Cloud Hypervisor[5] • Recent versions of Windows: • Windows 10 20H2 and 21H1 • Windows Server 2019 • Installed 3rd-party VirtIO device drivers[6] • Enabled Emergency Management Services (EMS) [7] to use serial console • Cloud Hypervisor does not support graphics
  20. Booting Windows on Cloud Hypervisor Pass the f irmware image

    from —kernel option
  21. Booting Windows on Cloud Hypervisor EMS SAC appeared to tty

    via UART serial
  22. Booting Windows on Cloud Hypervisor Everything is up, cmd.exe is

    available
  23. Porting to Physical Machine

  24. Porting to coreboot • coreboot[8]: Open source f irmware •

    coreboot ROM: • Basic system initialization + static ELF binary payload • Added coreboot table parser to provide memory map info (~170 LoC) System Initialization Code Intel FSP Rust (Hypervisor) Firmware
  25. Target Machine • MinnowBoard MAX[9] • Intel Atom (Bay Trail)

    • Easily access to SPI f lash • Pin header exposed • UART serial available x86 SBC from 2014
  26. Booting Rust (Hypervisor) Firmware from coreboot It panicked because no

    VirtIO block device found
  27. Summary • Rust Hypervisor Firmware is a f irmware written

    in Rust • Added more compatibility to the f irmware to boot Windows • It requires sane implementation of EFI Runtime Services • Ported the f irmware to coreboot with small efforts • It now boots up on a physical machine • It still cannot boot OS due to lack of physical disk device drivers • https://github.com/cloud-hypervisor/rust-hypervisor- f irmware
  28. References • [0] https://github.com/cloud-hypervisor/rust-hypervisor- f irmware • [1] https://github.com/cloud-hypervisor/cloud-hypervisor •

    [2] https://github.com/rhboot/shim • [3] https://cloud-images.ubuntu.com • [4] https://ue f i.org/sites/default/ f iles/resources/UEFI-Plugfest-WindowsBootEnvironment.pdf • [5] https://github.com/cloud-hypervisor/cloud-hypervisor/blob/master/docs/windows.md • [6] https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.185-2/ • [7] https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/bcdedit--ems • [8] https://coreboot.org • [9] https://www.elinux.org/Minnowboard:MinnowMax
  29. Appendix

  30. Pros & Cons of Writing Firmware in Rust Rust is

    not a silver bullet • Pros: • no_std-friendly ecosystem • core crate is modular design • Clean compile-time environment • macro/const_fn • C preprocessor is hell • Strong type system • Cons: • Nightly Rust is required • Some of ABIs are unstable • Efforts needed to keep dependencies up-to-date • Cargo is so not f lexible • e.g. oreboot uses GNU Make in addition to Cargo
  31. Debugging Issues • Issue #1: WinDbg is not available in

    early boot phase • winload.e f i (2nd phase) starts WinDbg session before loading the kernel • It cannot be used for debugging bootmgfw.e f i (1st phase) • Issue #2: Dealing with KASLR • KASLR is also applied to EFI runtime services • It is hard to f ind EFI service caller from backtrace
  32. Debugging Issue #1 • Issue #1: WinDbg is not available

    in early boot phase • winload.e f i starts WinDbg session before loading the kernel • It cannot be used for debugging bootmgfw.e f i • -> Ghidra: • Microsoft Symbol Server: • Also provides bootmgfw.e f i and winload.e f i symbols • Ghidra Firmware Utilities: • Adds EFI-speci f ic types and annotates well-known GUIDs
  33. Debugging Issue #2 • Issue #2: Dealing with KASLR •

    winload.e f i loads NT OS kernel at randomized offset • It is also applied to EFI runtime services • It makes debugging EFI runtime services hard • -> Custom GDB Python script • Hooks kernel hand off and calculates KASLR offset • Set breakpoints using the offset value