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