Skip to content

Commit

Permalink
Build and Run support for a Dfci Enabled Device Under Test (#489)
Browse files Browse the repository at this point in the history
## Description

Fixes #470.

PRE-REQ. This PR requires the following PR's before this one will work
correctly:
#473
#471
microsoft/mu_feature_dfci#84

This PR will have to bump DfciPkg to include PR 84 above before it is
completed.

This change adds the prereqs for DFCI - that is, platform specific
libraries required to interface between DFCI and a particular platform.
The required DFCI libraries are in PR 471. A convenience PR for booting
to FrontPage or with certain USB device mounted is also require (PR
473).

- [x] Impacts functionality?

- [ ] Impacts security?

- [ ] Breaking change?

- [ ] Includes tests?

- [x] Includes documentation?


## How This Was Tested

With all of the prerequisites included, a Q35 Virtual System was used to
run the Dfci End to End UnitTest with satisfactory results. That is, all
of the test cases ran will full success except Dfci_IntuneSettings -
which exhibits some know errors. This is not fixed due to another
pending change.

## Integration Instructions

N/A
  • Loading branch information
mikeytdisco authored May 26, 2023
1 parent 3c7273a commit a5f312d
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 16 deletions.
25 changes: 25 additions & 0 deletions DfciDutFiles/BuildDfci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
##
# This command make it easier to build with DFCI enabled and match the parameters with RunDfci.py.
#
# See the ReadMe.md file in this directory on how to use the BuildDfci script.
#
# Copyright (c) Microsoft Corporation
# SPDX-License-Identifier: BSD-2-Clause-Patent
##

if __name__ == "__main__":
import os
from pathlib import Path

dfci_directory = Path(__file__).parent.absolute()
build_directory = dfci_directory.parent.absolute()
platformbuild = os.path.join(build_directory, "Platforms", "QemuQ35Pkg", "PlatformBuild.py")

args = " BLD_*_GUI_FRONT_PAGE=TRUE"
args += " BLD_*_NETWORK_ALLOW_HTTP_CONNECTIONS=TRUE"
args += " BLD_*_QEMU_CORE_NUM=4"
args += " BLD_*_SMM_ENABLED=TRUE"
args += " --clean"

cmd = platformbuild + args
os.system(cmd)
66 changes: 66 additions & 0 deletions DfciDutFiles/RunDfci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
##
# This command make it easier to boot to a Windows device under test.
#
# See the ReadMe.md file in this directory on how to use the RunDfci script.
#
# Copyright (c) Microsoft Corporation
# SPDX-License-Identifier: BSD-2-Clause-Patent
##

if __name__ == "__main__":
import os
import argparse
from pathlib import Path

parser = argparse.ArgumentParser(description='Start Qemu with DFCI Options')

# Add a usb drive with OS Install Files, or Dfci Setup files
parse_group = parser.add_mutually_exclusive_group()
parse_group.add_argument("-f", "--frontpage", dest="frontpage", action='store_true', help="Boot to FrontPage")
parse_group.add_argument("-a", "--alt_boot", dest="alt_boot", action='store_true', help="Boot to Alternate source (USB/Network)")

# Choose to boot to front page, or a usb/network device.
parse_group2 = parser.add_mutually_exclusive_group()
parse_group2.add_argument("-i", "--install", dest="install", action='store_true', help="Add drive with install files")
parse_group2.add_argument("-d", "--dfcisetup", dest="dfcisetup", action='store_true', help="Add DfciSetup directory")

options = parser.parse_args()

dfci_directory = Path(__file__).parent.absolute()
build_directory = dfci_directory.parent.absolute()

platformbuild = os.path.join(build_directory, "Platforms", "QemuQ35Pkg", "PlatformBuild.py")

dfci_var_store = os.path.join(dfci_directory, "DFCI_DUT_VARS.fd")

args = " --FlashOnly"
args += " DFCI_VAR_STORE=" + "\"" + dfci_var_store + "\""

dfci_files = None
install_files = None
if options.install:
install_files = os.path.join(dfci_directory, "OsInstallFiles.vhd")
args += " INSTALL_FILES=" + "\"" + install_files + "\""

if options.dfcisetup:
dfci_files = os.path.join(dfci_directory, "DfciSetup")
args += " DFCI_FILES=" + "\"" + dfci_files + "\""

dfci_os_disk = os.path.join(dfci_directory, "Windows.vhd")

if not os.path.exists(dfci_os_disk):
raise Exception("The Windows.vhd file must exist")

args += " PATH_TO_OS=" + "\"" + dfci_os_disk + "\""

if options.frontpage:
args += " BOOT_TO_FRONT_PAGE=TRUE"

if options.alt_boot:
args += " ALT_BOOT_ENABLE=TRUE"

args += " BLD_*_QEMU_CORE_NUM=4"
args += " BLD_*_SMM_ENABLED=TRUE"

cmd = platformbuild + args
os.system(cmd)
82 changes: 66 additions & 16 deletions Platforms/QemuQ35Pkg/Plugins/QemuRunner/QemuRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import subprocess
import re
import io
import shutil
from edk2toolext.environment import plugin_manager
from edk2toolext.environment.plugintypes import uefi_helper_plugin
from edk2toollib import utility_functions
Expand Down Expand Up @@ -69,15 +70,6 @@ def Runner(env):
args += " -global isa-debugcon.iobase=0x402"
# Turn off S3 support
args += " -global ICH9-LPC.disable_s3=1"
# turn off network
args += " -net none"
# Mount disk with startup.nsh
if os.path.isfile(VirtualDrive):
args += f" -hdd {VirtualDrive}"
elif os.path.isdir(VirtualDrive):
args += f" -drive file=fat:rw:{VirtualDrive},format=raw,media=disk"
else:
logging.critical("Virtual Drive Path Invalid")

if env.GetBuildValue("SMM_ENABLED") is None or env.GetBuildValue("SMM_ENABLED").lower() == "true":
smm_enabled = "on"
Expand All @@ -94,29 +86,87 @@ def Runner(env):
accel = ",accel=whpx"

args += " -machine q35,smm=" + smm_enabled + accel
if env.GetValue("PATH_TO_OS") is not None:
path_to_os = env.GetValue("PATH_TO_OS")
if path_to_os is not None:
# Potentially dealing with big daddy, give it more juice...
args += " -m 8192"
args += " -hda \"" + env.GetValue("PATH_TO_OS") + "\""
#args += " -hda \"" + path_to_os + "\""
args += " -drive format=raw,index=0,media=disk,file=\"" + path_to_os + "\""
else:
args += " -m 2048"
args += " -cpu qemu64,+rdrand,umip,+smep,+popcnt" # most compatible x64 CPU model + RDRAND + UMIP + SMEP + POPCNT support (not included by default)

#args += " -cpu qemu64,+rdrand,umip,+smep,+popcnt" # most compatible x64 CPU model + RDRAND + UMIP + SMEP +POPCNT support (not included by default)
args += " -cpu qemu64,rdrand=on,umip=on,smep=on,pdpe1gb=on,popcnt=on" # most compatible x64 CPU model + RDRAND + UMIP + SMEP + PDPE1GB + POPCNT support (not included by default)

if env.GetBuildValue ("QEMU_CORE_NUM") is not None:
args += " -smp " + env.GetBuildValue ("QEMU_CORE_NUM")
if smm_enabled == "on":
args += " -global driver=cfi.pflash01,property=secure,value=on"
args += " -drive if=pflash,format=raw,unit=0,file=" + \
os.path.join(OutputPath_FV, "QEMUQ35_CODE.fd") + ",readonly=on"
args += " -drive if=pflash,format=raw,unit=1,file=" + \
os.path.join(OutputPath_FV, "QEMUQ35_VARS.fd")

orig_var_store = os.path.join(OutputPath_FV, "QEMUQ35_VARS.fd")
dfci_var_store =env.GetValue("DFCI_VAR_STORE")
if dfci_var_store is not None:
if not os.path.isfile(dfci_var_store):
shutil.copy(orig_var_store, dfci_var_store)
use_this_varstore = dfci_var_store
else:
use_this_varstore = orig_var_store
args += " -drive if=pflash,format=raw,unit=1,file=" + use_this_varstore

# Add XHCI USB controller and mouse
args += " -device qemu-xhci,id=usb"
args += " -device usb-mouse,id=input0,bus=usb.0,port=1" # add a usb mouse
#args += " -device usb-kbd,id=input1,bus=usb.0,port=2" # add a usb keyboar

dfci_files = env.GetValue("DFCI_FILES")
if dfci_files is not None:
args += f" -drive file=fat:rw:{dfci_files},format=raw,media=disk,if=none,id=dfci_disk"
args += " -device usb-storage,bus=usb.0,drive=dfci_disk"

install_files = env.GetValue("INSTALL_FILES")
if install_files is not None:
args += f" -drive file={install_files},format=raw,media=disk,if=none,id=install_disk"
args += " -device usb-storage,bus=usb.0,drive=install_disk"

boot_selection = ''
boot_to_front_page = env.GetValue("BOOT_TO_FRONT_PAGE")
if boot_to_front_page is not None:
if (boot_to_front_page.upper() == "TRUE"):
boot_selection += ",version=Vol+"

alt_boot_enable = env.GetValue("ALT_BOOT_ENABLE")
if alt_boot_enable is not None:
if alt_boot_enable.upper() == "TRUE":
boot_selection += ",version=Vol-"

# If DFCI_VAR_STORE is enabled, don't enable the Virtual Drive, and enable the network
dfci_var_store = env.GetValue("DFCI_VAR_STORE")
if dfci_var_store is None:
# turn off network
args += " -net none"
# Mount disk with startup.nsh
if os.path.isfile(VirtualDrive):
args += f" -hdd {VirtualDrive}"
elif os.path.isdir(VirtualDrive):
args += f" -drive file=fat:rw:{VirtualDrive},format=raw,media=disk"
else:
logging.critical("Virtual Drive Path Invalid")
else:
if boot_to_front_page is None:
# Booting to Windows, use a PCI nic
args += " -device e1000,netdev=net0"
else:
# Booting to UEFI, use virtio-net-pci
args += " -device virtio-net-pci,netdev=net0"

# forward ports for robotframework 8270 and 8271
args += " -netdev user,id=net0,hostfwd=tcp::8270-:8270,hostfwd=tcp::8271-:8271"

args += " -smbios type=0,vendor=Palindrome,uefi=on"
args += " -smbios type=1,manufacturer=Palindrome,product=MuQemuQ35,serial=42-42-42-42"
args += f" -smbios type=3,manufacturer=Palindrome,version={version},serial=42-42-42-42,asset=Q35,sku=Q35"
args += " -smbios type=1,manufacturer=Palindrome,product=MuQemuQ35,serial=42-42-42-42,uuid=9de555c0-05d7-4aa1-84ab-bb511e3a8bef"
args += f" -smbios type=3,manufacturer=Palindrome,serial=42-42-42-42{boot_selection}"

if (env.GetValue("QEMU_HEADLESS").upper() == "TRUE"):
args += " -display none" # no graphics
Expand Down
3 changes: 3 additions & 0 deletions Platforms/QemuQ35Pkg/QemuQ35Pkg.dsc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
DEFINE PEI_MM_IPL_ENABLED = TRUE
DEFINE GUI_FRONT_PAGE = FALSE

DEFINE NETWORK_HTTP_ENABLE = TRUE
DEFINE NETWORK_ALLOW_HTTP_CONNECTIONS = TRUE

# Configure Shared Crypto
!ifndef ENABLE_SHARED_CRYPTO # by default true
ENABLE_SHARED_CRYPTO = TRUE
Expand Down

0 comments on commit a5f312d

Please sign in to comment.