6 # TODO: Most of the telnet stuff need to be replaced by stdio/pexpect to discuss
7 # with the qemu machine.
8 class Emulator(object):
10 def __init__(self, builddir, downloaddir, logtofile):
13 self.downloaddir = downloaddir
15 self.logfile = infra.open_log_file(builddir, "run", logtofile)
17 # Start Qemu to boot the system
19 # arch: Qemu architecture to use
21 # kernel: path to the kernel image, or the special string
22 # 'builtin'. 'builtin' means a pre-built kernel image will be
23 # downloaded from ARTEFACTS_URL and suitable options are
24 # automatically passed to qemu and added to the kernel cmdline. So
25 # far only armv5, armv7 and i386 builtin kernels are available.
26 # If None, then no kernel is used, and we assume a bootable device
29 # kernel_cmdline: array of kernel arguments to pass to Qemu -append option
31 # options: array of command line options to pass to Qemu
33 def boot(self, arch, kernel=None, kernel_cmdline=None, options=None):
34 if arch in ["armv7", "armv5"]:
39 qemu_cmd = ["qemu-system-{}".format(qemu_arch),
40 "-serial", "telnet::1234,server",
46 if kernel_cmdline is None:
50 if kernel == "builtin":
51 if arch in ["armv7", "armv5"]:
52 kernel_cmdline.append("console=ttyAMA0")
55 kernel = infra.download(self.downloaddir,
57 dtb = infra.download(self.downloaddir,
58 "vexpress-v2p-ca9.dtb")
59 qemu_cmd += ["-dtb", dtb]
60 qemu_cmd += ["-M", "vexpress-a9"]
62 kernel = infra.download(self.downloaddir,
64 qemu_cmd += ["-M", "versatilepb"]
66 qemu_cmd += ["-kernel", kernel]
69 qemu_cmd += ["-append", " ".join(kernel_cmdline)]
71 self.logfile.write("> starting qemu with '%s'\n" % " ".join(qemu_cmd))
72 self.qemu = pexpect.spawn(qemu_cmd[0], qemu_cmd[1:])
74 # Wait for the telnet port to appear and connect to it.
75 self.qemu.expect("waiting for connection")
76 telnet_cmd = ["telnet", "localhost", "1234"]
77 self.__tn = pexpect.spawn(telnet_cmd[0], telnet_cmd[1:])
79 def __read_until(self, waitstr, timeout=5):
80 index = self.__tn.expect([waitstr, pexpect.TIMEOUT], timeout=timeout)
81 data = self.__tn.before
83 data += self.__tn.after
85 self.logfile.write(data)
88 def __write(self, wstr):
91 # Wait for the login prompt to appear, and then login as root with
92 # the provided password, or no password if not specified.
93 def login(self, password=None):
94 self.__read_until("buildroot login:", 10)
95 if "buildroot login:" not in self.log:
96 self.logfile.write("==> System does not boot")
97 raise SystemError("System does not boot")
99 self.__write("root\n")
101 self.__read_until("Password:")
102 self.__write(password + "\n")
103 self.__read_until("# ")
104 if "# " not in self.log:
105 raise SystemError("Cannot login")
106 self.run("dmesg -n 1")
108 # Run the given 'cmd' on the target
109 # return a tuple (output, exit_code)
111 self.__write(cmd + "\n")
112 output = self.__read_until("# ")
113 output = output.strip().splitlines()
114 output = output[1:len(output)-1]
116 self.__write("echo $?\n")
117 exit_code = self.__read_until("# ")
118 exit_code = exit_code.strip().splitlines()[1]
119 exit_code = int(exit_code)
121 return output, exit_code
125 self.__tn.terminate(force=True)
126 if self.qemu is None:
128 self.qemu.terminate(force=True)