diff --git a/Platform/QemuBoardPkg/Script/qemu_fwu.py b/Platform/QemuBoardPkg/Script/TestCases/firmware_update.py similarity index 79% rename from Platform/QemuBoardPkg/Script/qemu_fwu.py rename to Platform/QemuBoardPkg/Script/TestCases/firmware_update.py index 043ce7c6..d7f8f12b 100644 --- a/Platform/QemuBoardPkg/Script/qemu_fwu.py +++ b/Platform/QemuBoardPkg/Script/TestCases/firmware_update.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -## @ qemu_fwu.py +## @ firmware_update.py # -# QEMU firmware update test script +# Test firmware update on QEMU # # Copyright (c) 2020, Intel Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent @@ -14,7 +14,8 @@ import struct import signal import subprocess from threading import Timer -from ctypes import Structure, c_char, c_uint32, c_uint8, c_uint64, c_uint16, sizeof, ARRAY +from ctypes import Structure, c_char, c_uint32, c_uint8, c_uint64, c_uint16, sizeof, ARRAY +from test_base import * class FlashMapDesc(Structure): @@ -75,16 +76,17 @@ def get_check_lines (bp = 0, mode = 0): ]) return lines -def check_result (lines): + +def check_fwu_result (output): ret = 0 index = 0 cycle = 1 - count = len(lines) + count = len(output) for bp, mode in [(0, 0x12), (1, 0x12), (0, 0)]: for line in get_check_lines (bp, mode): found = False while not found and index < count: - if line in lines[index]: + if line in output[index]: found = True break else: @@ -93,7 +95,7 @@ def check_result (lines): index += 1 continue else: - print ("Failed locatting '%s' in cycke %d !" % (line, cycle)) + print ("Failed locating '%s' in cycle %d !" % (line, cycle)) ret = -1 break if ret < 0: @@ -227,46 +229,6 @@ def handle_ts(bios_image, set_ts_val=0): return fwu_flg -def run_process (cmd, timeout = 0): - def timerout (p): - timer.cancel() - os.kill(p.pid, signal.SIGTERM) - - lines = [] - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, universal_newlines=True) - if timeout: - timer = Timer(timeout, timerout, args=[p]) - timer.start() - for line in iter(p.stdout.readline, ''): - line = line.rstrip() - print (line) - lines.append (line) - p.stdout.close() - retcode = p.wait() - if timeout: - timer.cancel() - - return lines - - -def run_qemu(bios_img, fwu_path, fwu_mode=False, timeout=0): - if os.name == 'nt': - path = r"C:\Program Files\qemu\qemu-system-x86_64" - else: - path = r"qemu-system-x86_64" - cmd_list = [ - path, "-nographic", "-machine", "q35,accel=tcg", - "-serial", "mon:stdio", - "-m", "256M", "-drive", - "id=mydrive,if=none,format=raw,file=fat:rw:%s" % fwu_path, "-device", - "ide-hd,drive=mydrive", "-boot", "order=d%s" % ('an' if fwu_mode else ''), - "-no-reboot", "-drive", "file=%s,if=pflash,format=raw" % bios_img - ] - - lines = run_process (cmd_list, timeout) - return lines - - def usage(): print("usage:\n python %s bios_image fwu_cap_dir\n" % sys.argv[0]) print(" bios_image : QEMU Slim Bootloader firmware image.") @@ -290,6 +252,22 @@ def main(): print("Firmware update for Slim BootLoader") + # create FWU capsule + create_dirs ([fwu_dir]) + cmd = [ sys.executable, + 'BootloaderCorePkg/Tools/GenCapsuleFirmware.py', + '-p', 'BIOS', bios_img, + '-k', 'BootloaderCorePkg/Tools/Keys/TestSigningPrivateKey.pem', + '-o', '%s/FwuImage.bin' % fwu_dir + ] + try: + output = subprocess.run (cmd) + output.check_returncode() + except subprocess.CalledProcessError: + print ('Failed to generate QEMU SlimBootloader capsule image !') + return -3 + + # run FWU output = [] fwu_mode = 2 lines = run_qemu(bios_img, fwu_dir, True if fwu_mode != 0 else False) @@ -309,7 +287,7 @@ def main(): output.extend(lines) # check test result - ret = check_result (output) + ret = check_fwu_result (output) print ('\nQEMU FWU test %s !\n' % ('PASSED' if ret == 0 else 'FAILED')) diff --git a/Platform/QemuBoardPkg/Script/TestCases/linux_boot.py b/Platform/QemuBoardPkg/Script/TestCases/linux_boot.py new file mode 100644 index 00000000..b32df0b6 --- /dev/null +++ b/Platform/QemuBoardPkg/Script/TestCases/linux_boot.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +## @ linux_boot.py +# +# Test boot linux on QEMU +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +import os +import sys +import struct +from ctypes import Structure, c_char, c_uint32, c_uint8, c_uint64, c_uint16, sizeof, ARRAY +from test_base import * + +def get_check_lines (): + lines = [ + "===== Intel Slim Bootloader STAGE1A =====", + "===== Intel Slim Bootloader STAGE1B =====", + "===== Intel Slim Bootloader STAGE2 ======", + "Jump to payload", + "Starting Kernel ...", + "Linux version", + "Freeing unused kernel image", + 'Welcome to "Minimal Linux"', + ] + return lines + +def usage(): + print("usage:\n python %s bios_image os_image_dir\n" % sys.argv[0]) + print(" bios_image : QEMU Slim Bootloader firmware image.") + print(" This image can be generated through the normal Slim Bootloader build process.") + print(" os_image_dir: Directory containing bootable OS image.") + print(" This image can be generated using GenContainer.py tool.") + print("") + + +def main(): + if sys.version_info.major < 3: + print ("This script needs Python3 !") + return -1 + + if len(sys.argv) != 3: + usage() + return -2 + + bios_img = sys.argv[1] + os_dir = sys.argv[2] + + print("Linux boot test for Slim BootLoader") + + # download and unzip OS image + tmp_dir = os.path.dirname(os_dir) + '/temp' + create_dirs ([tmp_dir, os_dir]) + local_file = tmp_dir + '/QemuLinux.zip' + download_url ( + 'https://github.com/slimbootloader/slimbootloader/files/4463548/QemuLinux.zip', + local_file + ) + unzip_file (local_file, os_dir) + + # run QEMU boot with timeout + output = [] + lines = run_qemu(bios_img, os_dir, timeout = 8) + output.extend(lines) + + # check test result + ret = check_result (output, get_check_lines()) + + print ('\nLinux Boot test %s !\n' % ('PASSED' if ret == 0 else 'FAILED')) + + return ret + +if __name__ == '__main__': + sys.exit(main()) diff --git a/Platform/QemuBoardPkg/Script/TestCases/test_base.py b/Platform/QemuBoardPkg/Script/TestCases/test_base.py new file mode 100644 index 00000000..b61ec464 --- /dev/null +++ b/Platform/QemuBoardPkg/Script/TestCases/test_base.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +## @ test_base.py +# +# Provide common functions for test script +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +import os +import sys +import struct +import signal +import subprocess +import zipfile +import urllib.request +from threading import Timer + + +def unzip_file (zip_file, tgt_dir): + with zipfile.ZipFile(zip_file, 'r') as zip_ref: + zip_ref.extractall (tgt_dir) + + +def download_url (url, save_path): + urllib.request.urlretrieve (url, save_path) + + +def create_dirs (dirs): + # create dirs + for dir_name in dirs: + if not os.path.exists(dir_name): + os.mkdir (dir_name) + + +def run_qemu (bios_img, fwu_path, fwu_mode=False, timeout=0): + if os.name == 'nt': + path = r"C:\Program Files\qemu\qemu-system-x86_64" + else: + path = r"qemu-system-x86_64" + cmd_list = [ + path, "-nographic", "-machine", "q35,accel=tcg", + "-cpu", "max", "-serial", "mon:stdio", + "-m", "256M", "-drive", + "id=mydrive,if=none,format=raw,file=fat:rw:%s" % fwu_path, "-device", + "ide-hd,drive=mydrive", "-boot", "order=d%s" % ('an' if fwu_mode else ''), + "-no-reboot", "-drive", "file=%s,if=pflash,format=raw" % bios_img + ] + + lines = run_process (cmd_list, timeout) + return lines + + +def run_process (cmd, timeout = 0): + def timerout (p): + timer.cancel() + os.kill(p.pid, signal.SIGTERM) + + lines = [] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, universal_newlines=True) + if timeout: + timer = Timer(timeout, timerout, args=[p]) + timer.start() + for line in iter(p.stdout.readline, ''): + line = line.rstrip() + print (line) + lines.append (line) + p.stdout.close() + retcode = p.wait() + if timeout: + timer.cancel() + + return lines + + +def check_result (output, check_lines): + ret = 0 + index = 0 + count = len (output) + for line in check_lines: + found = False + while not found and index < count: + if line in output[index]: + found = True + break + else: + index += 1 + if found: + index += 1 + continue + else: + print ("Failed locating '%s' !" % (line)) + ret = -1 + break + return ret diff --git a/Platform/QemuBoardPkg/Script/qemu_test.py b/Platform/QemuBoardPkg/Script/qemu_test.py index f4cee1f2..f00efae2 100644 --- a/Platform/QemuBoardPkg/Script/qemu_test.py +++ b/Platform/QemuBoardPkg/Script/qemu_test.py @@ -12,48 +12,40 @@ import sys import shutil import subprocess + def main(): sbl_img = 'Outputs/qemu/SlimBootloader.bin' tst_img = 'Outputs/qemu/SblFwuTest.bin' - fwu_dir = 'Outputs/qemu/temp' + tmp_dir = 'Outputs/qemu/temp' + fwu_dir = 'Outputs/qemu/fwu' + img_dir = 'Outputs/qemu/image' # check QEMU SlimBootloader.bin if not os.path.exists(sbl_img): print ('Could not find QEMU SlimBootloader.bin image !') return -1 - # copy a test image so that the original image will not change - shutil.copyfile (sbl_img, tst_img) + # run test cases + test_cases = [ + ('firmware_update.py', [tst_img, fwu_dir]), + ('linux_boot.py' , [tst_img, img_dir]) + ] - # generate QEMU FWU capsule - if not os.path.exists(fwu_dir): - os.mkdir (fwu_dir) - cmd = [ sys.executable, - 'BootloaderCorePkg/Tools/GenCapsuleFirmware.py', - '-p', 'BIOS', tst_img, - '-k', 'BootloaderCorePkg/Tools/Keys/TestSigningPrivateKey.pem', - '-o', '%s/FwuImage.bin' % fwu_dir - ] - try: - output = subprocess.run (cmd) - output.check_returncode() - except subprocess.CalledProcessError: - print ('Failed to generate QEMU SlimBootloader capsule image !') - return -2 + for test_file, test_args in test_cases: + print ('######### Running run test %s' % test_file) + # copy a test image so that the original image will not change + shutil.copyfile (sbl_img, tst_img) - # run QEMU FWU test - cmd = [ sys.executable, - 'Platform/QemuBoardPkg/Script/qemu_fwu.py', - tst_img, - fwu_dir - ] - try: - output = subprocess.run (cmd) - output.check_returncode() - except subprocess.CalledProcessError: - print ('Failed to run QEMU firmware update test !') - return -3 + # run QEMU test cases + cmd = [ sys.executable, 'Platform/QemuBoardPkg/Script/TestCases/%s' % test_file] + test_args + try: + output = subprocess.run (cmd) + output.check_returncode() + except subprocess.CalledProcessError: + print ('Failed to run test %s !' % test_file) + return -3 + print ('######### Completed test %s\n\n' % test_file) print ('\nAll tests passed !\n')