1"""Generate QEMU options for Trusty test framework""" 2 3import subprocess 4import tempfile 5 6from qemu_error import RunnerGenericError 7 8 9class QemuArm64Options(object): 10 11 MACHINE = "virt,secure=on,virtualization=on" 12 13 BASIC_ARGS = [ 14 "-nographic", "-cpu", "cortex-a57", "-smp", "4", "-m", "1024", "-d", 15 "unimp", "-semihosting-config", "enable,target=native", "-no-acpi", 16 ] 17 18 LINUX_ARGS = ( 19 "earlyprintk console=ttyAMA0,38400 keep_bootcon " 20 "root=/dev/vda ro init=/init androidboot.hardware=qemu_trusty " 21 "trusty-log.log_ratelimit_interval=0 trusty-log.log_to_dmesg=always") 22 23 def __init__(self, config): 24 self.args = [] 25 self.config = config 26 27 def rpmb_data_path(self): 28 return f"{self.config.atf}/RPMB_DATA" 29 30 def rpmb_options(self, sock): 31 return [ 32 "-device", "virtio-serial", 33 "-device", "virtserialport,chardev=rpmb0,name=rpmb0", 34 "-chardev", f"socket,id=rpmb0,path={sock}"] 35 36 def gen_dtb(self, args, dtb_tmp_file): 37 """Computes a trusty device tree, returning a file for it""" 38 with tempfile.NamedTemporaryFile() as dtb_gen: 39 dump_dtb_cmd = [ 40 self.config.qemu, "-machine", 41 f"{self.MACHINE},dumpdtb={dtb_gen.name}" 42 ] + [arg for arg in args if arg != "-S"] 43 returncode = subprocess.call(dump_dtb_cmd) 44 if returncode != 0: 45 raise RunnerGenericError( 46 f"dumping dtb failed with {returncode}") 47 dtc = f"{self.config.linux}/scripts/dtc/dtc" 48 dtb_to_dts_cmd = [dtc, "-q", "-O", "dts", dtb_gen.name] 49 # pylint: disable=consider-using-with 50 with subprocess.Popen(dtb_to_dts_cmd, 51 stdout=subprocess.PIPE, 52 universal_newlines=True) as dtb_to_dts: 53 dts = dtb_to_dts.communicate()[0] 54 if dtb_to_dts.returncode != 0: 55 raise RunnerGenericError( 56 f"dtb_to_dts failed with {dtb_to_dts.returncode}") 57 58 firmware = f"{self.config.atf}/firmware.android.dts" 59 with open(firmware, "r", encoding="utf-8") as firmware_file: 60 dts += firmware_file.read() 61 62 # Subprocess closes dtb, so we can't allow it to autodelete 63 dtb = dtb_tmp_file 64 dts_to_dtb_cmd = [dtc, "-q", "-O", "dtb"] 65 with subprocess.Popen(dts_to_dtb_cmd, 66 stdin=subprocess.PIPE, 67 stdout=dtb, 68 universal_newlines=True) as dts_to_dtb: 69 dts_to_dtb.communicate(dts) 70 dts_to_dtb_ret = dts_to_dtb.wait() 71 72 if dts_to_dtb_ret: 73 raise RunnerGenericError(f"dts_to_dtb failed with {dts_to_dtb_ret}") 74 return ["-dtb", dtb.name] 75 76 def drive_args(self, image, index): 77 """Generates arguments for mapping a drive""" 78 index_letter = chr(ord('a') + index) 79 image_dir = f"{self.config.android}/target/product/trusty" 80 return [ 81 "-drive", 82 # pylint: disable=line-too-long 83 f"file={image_dir}/{image}.img,index={index},if=none,id=hd{index_letter},format=raw,snapshot=on", 84 "-device", 85 f"virtio-blk-device,drive=hd{index_letter}" 86 ] 87 88 def android_drives_args(self): 89 """Generates arguments for mapping all default drives""" 90 args = [] 91 # This is order sensitive due to using e.g. root=/dev/vda 92 args += self.drive_args("userdata", 2) 93 args += self.drive_args("vendor", 1) 94 args += self.drive_args("system", 0) 95 return args 96 97 def machine_options(self): 98 return ["-machine", self.MACHINE] 99 100 def basic_options(self): 101 return list(self.BASIC_ARGS) 102 103 def bios_options(self): 104 return ["-bios", f"{self.config.atf}/bl1.bin"] 105 106 def linux_options(self): 107 return [ 108 "-kernel", 109 f"{self.config.linux}/arch/{self.config.linux_arch}/boot/Image", 110 "-append", self.LINUX_ARGS 111 ] 112 113 def android_trusty_user_data(self): 114 return f"{self.config.android}/target/product/trusty/data" 115