Giter Site home page Giter Site logo

intel / multiarchuefipkg Goto Github PK

View Code? Open in Web Editor NEW
48.0 10.0 10.0 6.02 MB

Multi-Architecture UEFI Environment Driver

License: GNU Lesser General Public License v2.1

C 97.64% Assembly 1.12% NASL 1.24%
oprom uefi x64 aarch64 driver emulation gop isa multi-architecture riscv64 snp ihv multi-isa x86emulatorpkg rise

multiarchuefipkg's Introduction

MultiArchUefiPkg - Multi-Architecture UEFI Environment Driver

This repo implements a UEFI driver that allows non-native UEFI boot service drivers and applications to be executed in 64-bit UEFI environments.

The primary motivation is bringing together the IHV device and standardized AARCH64 and RISCV64 ecosystems. This driver allows plugging off the shelf storage, network and video cards into non-x86 machines and using them with UEFI for OS boot.

Today, AArch64 and RISC-V are supported as host environments. In AArch64 environments, EmulatorDxe supports X64 (aka x86_64, AMD64) UEFI binaries. On RISCV64, EmulatorDxe can be built with X64 and AARCH64 UEFI binary support.

It's derived from X86EmulatorPkg, yet is otherwise a reimplementation using a UEFI-enabled version of the Unicorn Engine - a flexible CPU emulator framework.

MultiArchUefiPkg has competitive performance, portability and size (2/3rds the binary size on AArch64, even smaller for RISCV64!), support for multiple emulated ISAs, a regression test suite, and improved (but not perfect) correctness in modeling the emulated UEFI Boot Service environment.

See a demo.

Updates

When What
May 2024 Deal with reported issue for a Micron NVMe OpRom, which uses rdrand instruction and scribbles to low RAM on success.
December 2023 More docs, conversion to UEFI DM, MAU_TRY_WITHOUT_MMU as an explicit build option (still enabled by default for RISC-V). LoadOpRom.efi tool. MAU_STANDALONE_LOGGING choices (and EFI_SERIAL_IO_PROTOCOL-backed implementation). SetCon tool.
November 2023 Doc and build system updates.
October 2023 Presented at the UEFI Fall 2023 Developers Conference and Plugfest. See the presentation slides.
September 2023 Move away from TPL manipulation and reduce RISC-V binary size by half.
July 2023 Support for building with MAU_EMU_RAZ_WI_PIO.
June 2023 Presented at the RISC-V Summit Europe, Barcelona. See the extended abstract, poster and presentation slides.
May 2023 Project reported to RISE Board as active priority.
March 2023 Released to GitHub

Theory Of Operation

UEFI code uses a pretty narrowly-defined ABI, which makes it easy to thunk x64/AArch64 client code making EFIAPI calls to native code: no FP/SIMD, no returning large values, etc. E.g. calls like:

    UINT64
    EFIAPI
    Fn(UINT64, UINT64, UINT64, UINT64,
       UINT64, UINT64, UINT64, UINT64,
       UINT64, UINT64, UINT64, UINT64,
       UINT64, UINT64, UINT64, UINT64);

...with up to 16 arguments are supported both client -> native and native -> client, which covers all UEFI needs.

Seamless thunking from native code to emulated code relies on MMU support in the UEFI firmware, specifically the ability to mark a range non-executable.

MultiArchUefiPkg won't work with just any UEFI implementations, but only with implementations that provide the EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL interface, which is the magic that enables loading foreign ISA binaries. Today this means you must use TianoCore EDK2 or a derived implementation.

The emulator presents an x64 and/or AArch64 UEFI Boot Services environment appropriate for running Boot Service drivers (e.g. OpRom drivers for video cards, NICs) and UEFI applications that aren't OS loaders. Certain Boot, Runtime and DXE services are filtered or disabled.

Quick Start

To quickly build a RISC-V version:

    $ git clone https://github.com/tianocore/edk2.git
    $ cd edk2
    $ git submodule add https://github.com/intel/unicorn-for-efi.git unicorn
    $ git submodule add https://github.com/intel/MultiArchUefiPkg.git
    $ git submodule update --init
    $ export GCC_RISCV64_PREFIX=... (if you are on a non-RISCV64 system)
    $ build -a RISCV64 -t GCC -p MultiArchUefiPkg/Emulator.dsc -b RELEASE

This will produce Build/MultiArchUefiPkg/RELEASE_GCC/RISCV64/EmulatorDxe.efi.

Also see the documents on building and running.

Modeled Environment

The emulator presents UEFI Boot Services environment appropriate for running Boot Service drivers (e.g. OpRom drivers for video cards, NICs) and UEFI applications that aren't OS loaders.

The details are described by a separate document.

Tested Platforms

The emulator is known to work on Qemu -M virt for both AArch64 and RISCV64, Ampere Altra, Raspberry Pi 4 and StarFive VisionFive 2 systems.

License

MultiArchUefiPkg is approved for release under GPLv2 and LGPLv2.1+ for the respective components under those licenses. EmulatorDxe itself is covered by the LGPL v2.1+, but it is statically linked to the Unicorn Engine library, which has a mix of LGPL and GPLv2 code.

Security Policy

Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation.

Reporting A Vulnerability

Please report any security vulnerabilities in this project utilizing the guidelines here.

Contribute

This is a RISE Project under the Firmware WG. See the project wiki page.

Contributions are welcome. Please raise issues and pull requests.

Please see the policy on contributions and our Code of Conduct.

multiarchuefipkg's People

Contributors

agraf avatar andreiw avatar ardbiesheuvel avatar bcran avatar blueswirl avatar drewrisinger avatar pgwipeout avatar rdower avatar xwhu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

multiarchuefipkg's Issues

Investigate forcing loading images below 4GiB if available

As part of developing MultiArchUefiPkg we've seen UEFI apps (thankfully not drivers...yet) that are not 64-bit clean:

  • Treating stack (ESP) as 32-bit
  • Corrupting AllocatePool pointers to be non-64-bit clean

This appears on a system where UEFI prefers memory > 4GiB. MultiArchUefiPkg already tries putting the emulated stack below 4GiB if possible, and with #5 could also try keeping pool/page allocations below 4GiB as well.

For consistency, it could be interesting if the images themselves were loaded below 4GiB if that were available, i.e. if the whole emulated image handling by DXE supported taking a hint and then reloading the image. Maybe, just try loading the image first below 4GiB regardless if the image type is x64. This could be an EDK2 patch...

Implement emulator disconnect

Implement EmulatorStop (), which is called when the UEFI Shell disconnect command is run on the emulator device handle.

Required to support driver unload. Should bail if any emulated images are loaded.

Emulation Failed: Invalid instruction (UC_ERR_INSN_INVALID) due to 'rdrand' usage

When loading the PCIe OptROM for a Micron 7300 MAX U.2 drive on AArch64 (an ADLINK Ampere Altra Dev Kit) I get an emulation failure, as shown in the attached screenshot. I'm using MultiArchUefiPkg commit 7972cdf from Feb 6th, 2024.

GLt0n6LakAAxlkq

I extracted the optrom image using PciRom and attached it. The information PciRom shows about it is:

ROM 0x0000E200 bytes
--------------------
+0x0: UEFI image (0xE200 bytes)
          Machine Type: 0x8664
             Subsystem: 0xB
    InitializationSize: 0xE200 (bytes)
  EfiImageHeaderOffset: 0x1B8
            Compressed: no

00-UEFI.rom.gz

MUA crash in unrelated driver after a previous x64 driver failed to load

The twitter crash had Synchronous Exception at 0xf14fc7e8, which with image base 0xf14f5000 corresponds to offset 0x77E8. This looks like data (no int3 after ret). The region is protected from execution, but MUA is not claiming it.

The strange thing is how anything in the image could have been invoked if it failed to start. Here's a theory: a different image was loaded after the the NVMe driver failed to load, but MUA didn't clean up the protection mappings.

    7792:       75 4c                   jne    0x77e0
    7794:       4c 89 44 24 30          mov    %r8,0x30(%rsp)
    7799:       4c 8d 0d b8 0e 00 00    lea    0xeb8(%rip),%r9        # 0x8658
    77a0:       48 89 54 24 28          mov    %rdx,0x28(%rsp)
    77a5:       4c 8d 05 fc 2c 00 00    lea    0x2cfc(%rip),%r8        # 0xa4a8
    77ac:       48 89 4c 24 20          mov    %rcx,0x20(%rsp)
    77b1:       ba 00 02 00 00          mov    $0x200,%edx
    77b6:       48 8d 4c 24 40          lea    0x40(%rsp),%rcx
    77bb:       e8 a8 ef ff ff          call   0x6768
    77c0:       48 8b 05 39 37 00 00    mov    0x3739(%rip),%rax        # 0xaf00
    77c7:       48 85 c0                test   %rax,%rax
    77ca:       74 14                   je     0x77e0
    77cc:       48 8b 40 40             mov    0x40(%rax),%rax
    77d0:       48 85 c0                test   %rax,%rax
    77d3:       74 0b                   je     0x77e0
    77d5:       48 8d 54 24 40          lea    0x40(%rsp),%rdx
    77da:       48 8b c8                mov    %rax,%rcx
    77dd:       ff 50 08                call   *0x8(%rax)
    77e0:       48 81 c4 48 02 00 00    add    $0x248,%rsp
    77e7:       c3                      ret
    77e8:       c6 05 b9 36 00 00 01    movb   $0x1,0x36b9(%rip)        # 0xaea8
    77ef:       c3                      ret

Originally posted by @andreiw in #48 (comment)

Investigate code size for RISCV64 build vs AARCH64

RISCV64 build is 2x the size of AARCH64 build, when build with comparable options.

The difference almost comes from the -Os compared to the aarch64 parts. The RISC-V parts will have an even smaller code size with the below options enabled.

  • -Os
  • -mrelax

Also, look into LTO.

Option to automatically load compatible OpRoms after Emulator start

Using the LoadOpRom logic in #36, add a new build option that will enhance EmulatorDxe to load all compatible OpRom images in DriverBinding Start(). This is not useful when the emulator is built as part of firmware (PciBus won't even be started when the driver loads), but it does make using a standalone-built emulator on existing systems easier via sideloading.

Dedicted I/O perf testers

There ought to be I/O perf tests (separate apps) to exercise the kinds of drivers that could be run using MultiArchUefiPkg. This includes block I/O tests, network perf tests, and GOP tests.

MSI GeForce RTX 3060 causes crash on AArch64 ADLINK Ampere Altra Dev Kit

MultiArchUefiPkg commit: d235d9f
unicorn commit: 6acd0781c792a9fbb3c904ed88aac0a55c65592d

System: ADLINK Ampere Altra Developer Kit
Graphics card: MSI GeForce RTX 3060 VENTUS 2X 12G OC

When using MultiArchUefiPkg I get a crash apparently when loading the optrom for the GPU, after the PCI scanning code finds the card.

I've attached the full boot log and the files generated from the PciRom.efi tool.

FS0:\UefiTools\> PciRom.efi -s Pny3060Rtx 0D   01   00    00
ROM 0x00026800 bytes
--------------------
+0x0: BIOS image (0xFE00 bytes)
Saving Msi3060Rtx\00-BIOS.rom
+0xFE00: UEFI image (0x16A00 bytes)
          Machine Type: 0x8664
             Subsystem: 0xB
    InitializationSize: 0x16A00 (bytes)
  EfiImageHeaderOffset: 0x50
            Compressed: yes
Saving Msi3060Rtx\01-UEFI.rom

Msi3060Rtx-rom.tar.gz
boot.txt

Per-image tracing

Today all sorts of debug info is printed for debug builds, but it's completely non-selective, rendering it useless for situations where you need extra logging.

Make logging levels/options per image (inheriting global state on image launch). Add a test protocol call to manipulate local image logging state. Add an application to change the global state.

Detect leaked event handlers on image crashes.

If an emulated image crashes and gets unloaded, it may have left event handlers behind which will of course bomb out. This is a good reason for always enabling MAU_WRAPPED_ENTRY_POINTS and for performing clean up on these.

Key off of a Pcd in DriverBinding Start()

This, when the Pcd is backed by an NV variable, will enable the emulator to be disabled when it is built as part of firmware. Also add an EmulatorToggle tool to set this state.

Confusion over adding support for MultiArchUefiPkg into a project

I'm confused about how to go about adding support for MultiArchUefiPkg into a project. https://github.com/intel/MultiArchUefiPkg/blob/main/Docs/Building.md has instructions, and details options like SUPPORTS_X64_BINS.

But, SUPPORTS_X64_BINS only appears to be an applicable option for Emulator.dsc, not platforms like ArmVirtPkg because elsewhere the option for building X64 binary support is referred to as MAU_SUPPORTS_X64_BINS.

I attempted to work around this by adding the following in to my platform's .dsc file:

  ON_PRIVATE_STACK               = NO
  WRAPPED_ENTRY_POINTS           = NO
  CHECK_ORPHAN_CONTEXTS          = NO
  EMU_TIMEOUT_NONE               = NO
  SUPPORTS_X64_BINS              = YES
  UPPORTS_AARCH64_BINS           = NO
  EMU_X64_RAZ_WI_PIO             = YES
  UC_LTO_JOBS                    = auto

and:

[BuildOptions]
# MultiArchUefiPkg (x86 emulation) build options
  *_*_*_CC_FLAGS                       = -DDISABLE_NEW_DEPRECATED_INTERFACES
!if "$(ON_PRIVATE_STACK)" == "YES"
  *_*_*_CC_FLAGS                       = -DMAU_ON_PRIVATE_STACK
!endif
!if "$(WRAPPED_ENTRY_POINTS)" == "YES"
  *_*_*_CC_FLAGS                       = -DMAU_WRAPPED_ENTRY_POINTS
!endif    
!if "$(CHECK_ORPHAN_CONTEXTS)" == "YES"
  *_*_*_CC_FLAGS                       = -DMAU_CHECK_ORPHAN_CONTEXTS
!endif
!if "$(EMU_TIMEOUT_NONE)" == "YES"
  *_*_*_CC_FLAGS                       = -DMAU_EMU_TIMEOUT_NONE    
!endif
!if "$(SUPPORTS_X64_BINS)" == "YES"
  *_*_*_CC_FLAGS                       = -DMAU_SUPPORTS_X64_BINS
!endif
!if "$(EMU_X64_RAZ_WI_PIO)" == "YES"
  *_*_*_CC_FLAGS                       = -DMAU_EMU_X64_RAZ_WI_PIO
!endif

But then during boot I get an error "Unimplemented x86_uc_init!" followed by a synchronous exception.

Also, Emulator.dsc includes unicorn/efi/UnicornPkg.dsc.inc - is that something other platforms should be including too?

Optimize use of uc_context_save/restore

Technically these should only be needed if the previous context was interrupted. If the last context was in a native call, we should be able to get away with saving/restoring minimal state as per calling convention (RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15)

Seems like a fairly minor optimization, as realistically there won't be giant chains of emu->native->emu invocations, while event handling would still involve a full context save (akin to an interrupt handler, really).

Add tool to set ConOut

While not directly related to emulation, it will make testing MultiArchUefiPkg easier on existing systems when not building the emulator as part of firmware (e.g. loading a GOP driver doesn't automatically place the system console on the new graphics device).

Rework documentation

Split Building.md/Running.md into several files:

  1. GettingStarted.md should focus on how to use a standalone-built emulator on existing systems (without modifying firmware).
  2. FirmwareIntegration.md should focus on how to build the emulator as part of firmware
  3. BuildingFaq.md should cover the rest (build options etc)

Add EFI wrappers for SetMemoryAttributes, AllocatePages, AllocatePool

Catch/filter SetMemoryAttributes to ignore any attempts to change attributes for the emulated image itself, as on architectures that use no-exec protection, this would lead to a crash.

Also, technically would also need to wrap AllocatePages and track attempts to allocate code regions (so that these can be protected).

Not a driver use case, but a correctness one.

Add compatibility testing tool

Esp. when trying emulator on existing systems with unknown firmware, it's useful to know how compatible the system is. E.g. does it have functioning MMU? Can you correctly set exception handlers? Does LongJmp work correctly?

Test cross-ISA emulated calls

Validate that one emulated binary (e.g. x64 app) can call an interface provided by another emulated binary with a different ISA (e.g. AArch64 driver).

This is primarily test application / test driver work + a fixes to Emulator.c/Cpu.c. Namely, it needs to treat code with ImageRecords having a different arch as being native.

Create EFI wrappers for GOP/SNP protocols

Even with working MMU-based trapping for seamless native->emulated calls, native wrappers around GOP/SNP/Block protocols may make sense as there will be less overhead involved.

The trap based mechanism involves:

  • exception entry
  • ImageFindByAddress
  • RISCV only: instruction decoding to recover call target
  • exception exit to EmulatorThunk
  • EmulatorVmEntry

The wrapper based mechanism is just

  • EmulatorVmEntry

Need to evaluate impact on I/O perf.

Investigate per-driver work/arounds

Maybe venid/devid based, maybe signature or name based. Basically provide an escape hatch for integrators to deal with crazy issues like #48. This would also need a way to negotiate behavior warts with unicorn-for-efi.

Rework error logging, esp. for BinaryIncluded.

Either replace DebugLib or implement a EFI_SERIAL_IO_PROTOCOL-based variant. The problem with ConOut-based logging is that it doesn't work until ConOut is connected, which is almost always true for a) driver load b) emulated driver loads (e.g. a crash on loading GOP).

Get into Tiano upstream

Investigate what is required to get into upstream. IIRC this needs to be compatibly licensed (which today would need agreement from the two X86EmulatorPkg engineers - Ard and Alexander). It's also unclear if it's okay to depend on a GPL/LGPL submodule. If not, then a BSD-licensed impl. of Unicorn API is needed (perhaps based on the DynaRec from https://github.com/ptitSeb/box64).

DEBUG UEFI build assertions due to IoLibNoIo

An emulated driver doing port I/O on a debug UEFI build that doesn't forward CpuIo2 I/O accesses to PCIe will always hit an assert inside IoLibNoIo.c. Add a build mode to terminate port accesses early.

Originally reported by Rebecca Cran using an Ampere Altra Developer Platform (AADP) and Tiano firmware

#22

LTO issue with AArch64 build if UnicornArm64Lib is included

Repro: modify Emulator.dsc to make UnicornArm64Lib inclusion common for all arches. Try build. Build will spend 10s of minutes in LTO, then fail with undefined ref to __ashrti3 (which is in unicorn/efi/ashrti3.c).

The fix for the later may be similar to ./ArmPkg/Library/GccLto (untested), who knows. Not tested yet.

Compiler info:

andreiw@awarkent-mobl1:~/src/edk2-staging$ aarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=aarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/9/lto-wrapper
Target: aarch64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.4.0-1ubuntu1~20.04.1' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --without-target-system-zlib --enable-libpth-m2 --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu --program-prefix=aarch64-linux-gnu- --includedir=/usr/aarch64-linux-gnu/include
Thread model: posix
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
andreiw@awarkent-mobl1:~/src/edk2-staging$ aarch64-linux-gnu-ld -v

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.