What is linuxboot?

LinuxBoot is a firmware for modern servers that replaces specific firmware functionality like the UEFI DXE phase with a Linux kernel and runtime.

Why?

  • Improves boot reliability by replacing lightly-tested firmware drivers with hardened Linux drivers.
  • Improves boot time by removing unnecessary code. Typically makes boot 20 times faster.
  • Allows customization of the initrd runtime to support site-specific needs (both device drivers as well as custom executables).
  • Proven approach for almost 20 years in military, consumer electronics, and supercomputing systems – wherever reliability and performance are paramount.

Hackweek goals

  • Study how linuxboot works.
  • Firmware building and running based on QEMU.
  • Try booting openSUSE via linuxboot. (optional)

Resources

Looking for hackers with the skills:

Nothing? Add some keywords!

This project is part of:

Hack Week 21

Activity

  • over 2 years ago: vkarasulli joined this project.
  • over 2 years ago: clin joined this project.
  • over 2 years ago: dmdiss liked this project.
  • over 2 years ago: fakhrylinux joined this project.
  • over 2 years ago: aextecki liked this project.
  • over 2 years ago: aextecki started this project.
  • over 2 years ago: clin originated this project.

  • Comments

    • clin
    • clin
      over 2 years ago by clin | Reply

      Getting started with LinuxBoot Firmware on AArch64 Server

      • clin
    • clin
      over 2 years ago by clin | Reply

      Problem (Solved, please see the next message): The newer kernel versions for x86_64 [v5.8 ~ v5.18] seem too big [bzImage: 8.6MB ~ 11MB] to fit into the regular max size of an OVMF FD, which is 8MB. I tried to extend the size defined in edk2/OvmfPkg/OvmfPkgX64.dsc to 16MB in order to finish the build process. [DONE]

      However, QEMU limits the size of x86_64 system FW to 8MB. [QEMU ver: 6.2.0]

      > chester@linux-8mug:~/workspace/src/github/build/linuxboot/linuxboot> make run

      > qemu-system-x86_64 \

      > -machine q35,smm=on \

      > -global ICH9-LPC.disable_s3=1 \

      > -global driver=cfi.pflash01,property=secure,value=on \

      > --serial stdio \

      > -drive if=pflash,format=raw,unit=0,file=build/qemu/linuxboot.rom

      > qemu-system-x86_64: combined size of system firmware exceeds 8388608 bytes

      > make: [boards/qemu/Makefile.board:67: run] Error 1 (ignored)

      • clin
        over 2 years ago by clin | Reply

        edk2 patch:

        Note: The edk2 branch that LinuxBoot aligns with is UDK2018, which is relatively old. The following patch is only based on the code tree which is automatically fetched by LinuxBoot's Makefile.

        diff --git a/OvmfPkg/OvmfPkg.fdf.inc b/OvmfPkg/OvmfPkg.fdf.inc index 8d6e3c6f..77a73c31 100644 --- a/OvmfPkg/OvmfPkg.fdf.inc +++ b/OvmfPkg/OvmfPkg.fdf.inc @@ -124,4 +124,4 @@ SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize = $(BLOCK_SIZ SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwSpareBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlas SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = $(VARS_SPARE_SIZE)^M ^M -DEFINE MEMFD_BASE_ADDRESS = 0x800000^M +DEFINE MEMFD_BASE_ADDRESS = 0x1000000^M diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index ad2a3e39..eac09b85 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -56,8 +56,8 @@ !ifdef $(FD_SIZE_4MB)^M DEFINE FD_SIZE_IN_KB = 4096^M !else^M - #DEFINE FD_SIZE_IN_KB = 16384^M - DEFINE FD_SIZE_IN_KB = 8192^M + DEFINE FD_SIZE_IN_KB = 16384^M + #DEFINE FD_SIZE_IN_KB = 8192^M !endif^M !endif^M !endif^M diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index b8b7777e..def1e57a 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -68,10 +68,10 @@ FV = SECFV ^M [FD.MEMFD]^M BaseAddress = $(MEMFD_BASE_ADDRESS)^M -Size = 0xB00000^M +Size = 0xFF0000^M ErasePolarity = 1^M BlockSize = 0x10000^M -NumBlocks = 0xB0^M +NumBlocks = 0xFF^M ^M 0x000000|0x006000^M gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize^M @@ -89,7 +89,7 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.P gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize^M FV = PEIFV^M ^M -0x100000|0xA00000^M +0x100000|0xEF0000^M gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize^M FV = DXEFV^M

      • clin
        over 2 years ago by clin | Reply

        linuxboot patch

        ``` diff --git a/boards/qemu/Makefile.board b/boards/qemu/Makefile.board
        index 57784f7..77436d7 100644
        --- a/boards/qemu/Makefile.board
        +++ b/boards/qemu/Makefile.board
        @@ -10,12 +10,12 @@
        # 0x084000.fv FV (DXE and PEI)
        # 0.fv PEI
        # 1.fv DXE
        -# 0x7cc000.fv SEC
        +# 0xfcc000.fv SEC
        #
        #

        -dxe-size := 0xA00000
        -merged-size := 0x748000
        +dxe-size := 0xEF0000
        +merged-size := 0xF48000

        fv-path := $(BUILD)/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792
        dxe-path := $(fv-path)/1
        @@ -34,7 +34,7 @@ $(fv-path)/0.fv: $(BUILD)/$(BOARD).txt
        FVS := \
        $(BUILD)/rom/0x00000000.fv \
        $(BUILD)/merged.vol \
        - $(BUILD)/rom/0x007cc000.fv \
        + $(BUILD)/rom/0x00fcc000.fv \

        $(BUILD)/merged.vol: \
        $(fv-path)/0.fv \
        @@ -43,7 +43,7 @@ $(BUILD)/merged.vol: \
        ./bin/create-ffs \
        --compress \
        --type FIRMWAREVOLUMEIMAGE \
        - $^ \
        + $(filter-out $(BUILD)/$(BOARD).txt,$^) \
        | ./bin/create-fv \
        --size $(merged-size) \
        -o $@
        @@ -65,7 +65,7 @@ boards/$(BOARD)/$(BOARD).rom: edk2/.git
        # We can also launch a qemu with the LinuxBoot kernel
        run: $(BUILD)/linuxboot.rom
        -qemu-system-x8664 \
        - -machine q35,smm=on \
        + -machine q35,smm=on,max-fw-size=16777216 \
        -global ICH9-LPC.disable
        s3=1 \
        -global driver=cfi.pflash01,property=secure,value=on \
        --serial $(or $(SERIAL),stdio) \ diff --git a/boards/qemu/image-files.txt b/boards/qemu/image-files.txt
        index 5ae8d58..4ec4850 100644
        --- a/boards/qemu/image-files.txt
        +++ b/boards/qemu/image-files.txt
        @@ -6,10 +6,10 @@ d93ce3d8-a7eb-4730-8c8e-cc466a9ecc3c ReportStatusCodeRouterRuntimeDxe b601f8c4-43b7-4784-95b1-f4226cb40cee RuntimeDxe
        f80697e9-7fd6-4665-8646-88e33ef71dfc SecurityStubDxe
        13ac6dd0-73d0-11d4-b06b-00aa00bd6de7 EbcDxe
        -245CB4DA-8E15-4A1B-87E3-9878FFA07520 Legacy8259
        +79ca4208-bba1-4a9a-8456-e1e66a81484e Legacy8259
        a19b1fe7-c1bc-49f8-875f-54a5d542443f CpuIo2Dxe
        1a1e4886-9517-440e-9fde-3be44cee2136 CpuDxe
        -C190FE35-44AA-41A1-8AEA-4947BC60E09D Timer
        +f2765dec-6b41-11d5-8e71-00902707b35e Timer
        f6697ac4-a776-4ee1-b643-1feff2b615bb IncompatiblePciDeviceSupportDxe
        11a6edf6-a9be-426d-a6cc-b22fe51d9224 PciHotPlugInitDxe
        128fb770-5e79-4176-9e51-9bb268a17dd1 PciHostBridgeDxe
        @@ -29,7 +29,7 @@ f9d88642-0737-49bc-81b5-6889cd57d9ea SmbiosDxe
        49970331-e3fa-4637-9abc-3b7868676970 AcpiPlatform
        7e374e25-8e01-4fee-87f2-390c23c606cd ACPI data
        bdce85bb-fbaa-4f4e-9264-501a2c249581 S3SaveStateDxe
        -7C04A583-9E3E-4F1C-AD65-E05268D0B4D1 Shell
        +# 7C04A583-9E3E-4F1C-AD65-E05268D0B4D1 Shell
        d9dcc5df-4007-435e-9098-8970935504b2 PlatformDxe
        2ec9da37-ee35-4de9-86c5-6d9a81dc38a7 AmdSevDxe
        8657015b-ea43-440d-949a-af3be365c0fc IoMmuDxe
        diff --git a/build/.gitignore b/build/.gitignore
        deleted file mode 100644
        index 72e8ffc..0000000
        --- a/build/.gitignore
        +++ /dev/null
        @@ -1 +0,0 @@
        -* ```

      • clin
        over 2 years ago by clin | Reply

        Files and configs for my experiment:

        • KERNEL: vmlinuz-5.8.14-1-default [10MB] copied from my laptop kernel [OpenSUSE Tumbleweed 20211101] since it's smaller than the bzImage compiled by x86_64_defconfig [11MB].
        • INITRD: initramfs.linux_amd64.cpio.xz[3.3MB]. A smaller initramfs built by u-root.
        • BOARD: qemu [x86_64]
        • CONFIG_EFI_BDS: A downstream patch that is outdated to new kernels [~v5.x] since the related codes have been changed and moved from boot/compressed/boot.c to efistub since kernel v5.8.

      • clin
        over 2 years ago by clin | Reply

        u-root compiling instructions: go version >=1.17 > # git clone https://github.com/u-root/u-root

        > # cd u-root/

        > # go build

        > # go install github.com/u-root/u-root

        > # export GOPATH=$HOME/go

        > # export PATH=$PATH:$GOPATH/bin

        > # u-root -uroot-source github.com/u-root/u-root core

        > # xz --check=crc32 -9 --lzma2=dict=1MiB \

        > --stdout /tmp/initramfs.linux_amd64.cpio \

        > | dd conv=sync bs=512 \

        > of=/tmp/initramfs.linux_amd64.cpio.xz

    • clin
      over 2 years ago by clin | Reply

      The FW size limitation can be solved by adding the property "max-fw-size=16777216". For example:

      > qemu-system-x86_64 \

      > -machine q35,smm=on,max-fw-size=16777216 \

      > -global ICH9-LPC.disable_s3=1 \

      > -global driver=cfi.pflash01,property=secure,value=on \

      > --serial stdio \

      > -drive if=pflash,format=raw,unit=0,file=build/qemu/linuxboot.rom

      Now I can launch a QEMU instance but there's no console output. Under investigation.

    • clin
      over 2 years ago by clin | Reply

      If you found that LzmaCompress could not be found when the build system was compiling the edk2, it seems to be a toolchain issue but you can still compile it by your local x86-64 tool-chain, just simply cd to edk2/BaseTools and then run make.

    • clin
      over 2 years ago by clin | Reply

      I put all my current work here.

      Progress:

      • The simulation starts from edk2 and the boot sequence SEC->PEI->DXE looks good.
      • The BDS stage owned by LinuxBoot can be reached but the process always dies at the following assertion:

      > --------

      > Transfering control to BDS 7B31450

      > Entry Point 7B2F280 (7B2F280)

      > --------

      > LinuxBoot: BDS time has arrived

      > LinuxBoot: connect pci root bridges

      > efivisithandles 2F707EBB

      > handle_count=00000001

      > PCI Bus First Scanning

      > PciBus: Discovered PCI @ [00|00|00]

      >

      > PciBus: Discovered PCI @ [00|01|00]

      > BAR[0]: Type = PMem32; Alignment = 0xFFFFFF; Length = 0x1000000; Offset = 0x10

      > BAR[2]: Type = Mem32; Alignment = 0xFFF; Length = 0x1000; Offset = 0x18

      >

      > PciBus: Discovered PCI @ [00|02|00]

      > ASSERT [PciHostBridgeDxe] /home/chester/workspace/src/github/test/linuxboot/edk2/MdePkg/Library/BasePciCf8Lib/PciCf8Lib.c(1114): ((Address) & (~0xffff0ff | (3))) == 0

    • clin
      over 2 years ago by clin | Reply

      TODO:

      • Solve the assertion issued by PciHostBridgeDxe.
      • run the rest of boot sequence test.
        • BDS -> 1st kernel owned by linuxboot -> mount u-root initramfs -> kexec to next-kernel or launch grub2.
      • Come up with a minimum config in order to downsize the kernel.
        • Different platforms might have different configs.

    Similar Projects

    This project is one of its kind!