harness: machines: define custom buildall targets for armv7/armv8 machines
[barrelfish] / tools / harness / machines / pandaboard.py
1 ##########################################################################
2 # Copyright (c) 2014-2016 ETH Zurich.
3 # All rights reserved.
4 #
5 # This file is distributed under the terms in the attached LICENSE file.
6 # If you do not find this file, copies can be found by writing to:
7 # ETH Zurich D-INFK, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
8 ##########################################################################
9
10 import debug, eth_machinedata
11 import subprocess, os, socket, sys, shutil, tempfile, pty
12 from machines import ARMMachineBase, MachineFactory, MachineOperations
13 from machines.eth import ETHBaseMachineOperations
14
15 PANDA_ROOT='/mnt/local/nfs/pandaboot'
16 PANDA_BOOT_HOST='masterpanda.in.barrelfish.org'
17 PANDA_PORT=10000
18 TOOLS_PATH='/home/netos/tools/bin'
19 RACKBOOT=os.path.join(TOOLS_PATH, 'rackboot.sh')
20 RACKPOWER=os.path.join(TOOLS_PATH, 'rackpower')
21
22
23 class PandaboardMachine(ARMMachineBase):
24     '''Machine to run tests on locally attached pandaboard. Assumes your
25     pandaboard's serial port is attached to /dev/ttyUSB0'''
26     name = 'panda_local'
27     imagename = "armv7_omap44xx_image"
28
29     def __init__(self, options, **kwargs):
30         super(PandaboardMachine, self).__init__(options, PandaboardOperations(self), **kwargs)
31         self.menulst_template = "menu.lst.armv7_omap44xx"
32
33     def setup(self, builddir=None):
34         pass
35
36     def get_buildall_target(self):
37         return "PandaboardES"
38
39 class PandaboardOperations(MachineOperations):
40
41     def __init__(self, machine):
42         super(PandaboardOperations, self).__init__(machine)
43         self.picocom = None
44         self.tftp_dir = None
45         self.masterfd = None
46
47     def get_tftp_dir(self):
48         if self.tftp_dir is None:
49             self.tftp_dir = tempfile.mkdtemp(prefix="panda_")
50         return self.tftp_dir
51
52     def set_bootmodules(self, modules):
53         menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
54                 "platforms", "arm", self._machine.menulst_template)
55         self._machine._write_menu_lst(modules.get_menu_data("/"), menulst_fullpath)
56         debug.verbose("building proper pandaboard image")
57         debug.checkcmd(["make", self._machine.imagename],
58                 cwd=self._machine.options.builds[0].build_dir)
59
60     def __usbboot(self):
61         debug.verbose("Usbbooting pandaboard; press reset")
62         debug.verbose("build dir: %s" % self._machine.options.builds[0].build_dir)
63         debug.checkcmd(["make", "usbboot_panda"],
64                 cwd=self._machine.options.builds[0].build_dir)
65
66     def lock(self):
67         pass
68
69     def unlock(self):
70         pass
71
72     def reboot(self):
73         self.__usbboot()
74
75     def shutdown(self):
76         '''shutdown: close picocom'''
77         # FIXME: sending C-A C-X to close picocom does not seem to work
78         #if self.masterfd is not None:
79         #    debug.verbose("Sending C-A C-X to picocom")
80         #    os.write(self.masterfd, "\x01\x24")
81         if self.picocom is not None:
82             debug.verbose("Killing picocom")
83             self.picocom.kill()
84             try:
85                 os.unlink("/var/lock/LCK..ttyUSB0")
86             except OSError:
87                 pass
88         self.picocom = None
89         self.masterfd = None
90
91     def get_output(self):
92         '''Use picocom to get output. This replicates part of
93         ETHMachine.lock()'''
94         (self.masterfd, slavefd) = pty.openpty()
95         self.picocom = subprocess.Popen(
96                 ["picocom", "-b", "115200", "/dev/ttyUSB0"],
97                 close_fds=True, stdout=slavefd, stdin=slavefd)
98         os.close(slavefd)
99         self.console_out = os.fdopen(self.masterfd, 'rb', 0)
100         return self.console_out
101
102
103 class ETHRackPandaboardMachine(ARMMachineBase):
104     _machines = eth_machinedata.pandaboards
105     imagename = "armv7_omap44xx_image"
106
107     def __init__(self, options, **kwargs):
108         super(ETHRackPandaboardMachine, self).__init__(options, ETHRackPandaboardMachineOperations(self), **kwargs)
109         self.menulst_template = "menu.lst.armv7_omap44xx"
110
111     def setup(self, builddir=None):
112         pass
113
114     # pandaboard specifics
115     def get_platform(self):
116         return 'omap44xx'
117
118     def get_buildall_target(self):
119         return "PandaboardES"
120
121 class ETHRackPandaboardMachineOperations(ETHBaseMachineOperations):
122
123     def __init__(self, machine):
124         super(ETHRackPandaboardMachineOperations, self).__init__(machine)
125         self._tftp_dir = None
126         self.targe_name = None
127
128     def __chmod_ar(self, file):
129         '''make file/directory readable by all'''
130         import stat
131         extra = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH
132         if os.path.isdir(file):
133             extra |= stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
134         os.chmod(file, os.stat(file).st_mode | extra)
135
136     def get_tftp_dir(self):
137         if self._tftp_dir is None:
138             self._tftp_dir = tempfile.mkdtemp(dir=PANDA_ROOT, prefix="%s_" % self._machine.getName())
139             self.__chmod_ar(self._tftp_dir)
140         return self._tftp_dir
141
142     def set_bootmodules(self, modules):
143         menulst_fullpath = os.path.join(self._machine.options.builds[0].build_dir,
144                 "platforms", "arm", self._machine.menulst_template)
145         self._machine._write_menu_lst(modules.get_menu_data("/"), menulst_fullpath)
146         source_name = os.path.join(self._machine.options.builds[0].build_dir, self._machine.imagename)
147         self.target_name = os.path.join(self.get_tftp_dir(), self._machine.imagename)
148         debug.verbose("building proper pandaboard image")
149         debug.checkcmd(["make", self._machine.imagename],
150                 cwd=self._machine.options.builds[0].build_dir)
151         debug.verbose("copying %s to %s" % (source_name, self.target_name))
152         shutil.copyfile(source_name, self.target_name)
153         self.__chmod_ar(self.target_name)
154
155     def __usbboot(self):
156         pandanum = self._machine.get_machine_name()[5:]
157         imagename = os.path.relpath(self.target_name, PANDA_ROOT)
158         # send "boot PANDANUM pandaboot/$tempdir/IMAGE_NAME" to
159         # masterpanda:10000
160         debug.verbose("sending boot command for pandaboard %s; pandaboard_image %s" % (pandanum, imagename))
161         masterpanda_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
162         masterpanda_sock.connect((PANDA_BOOT_HOST, PANDA_PORT))
163         masterpanda_sock.send('boot %s pandaboot/%s\n' %
164                 (pandanum, imagename))
165         masterpanda_sock.shutdown(socket.SHUT_WR)
166         while True:
167             data = masterpanda_sock.recv(1024)
168             os.write(sys.stdout.fileno(), data)
169             if data == "":
170                 break
171
172     def _get_console_status(self):
173         # for Pandaboards we cannot do console -i <machine> so we grab full -i
174         # output and find relevant line here
175         proc = subprocess.Popen(["console", "-i"], stdout=subprocess.PIPE)
176         output = proc.communicate()[0]
177         assert(proc.returncode == 0)
178         output = map(str.strip, output.split("\n"))
179         return filter(lambda l: l.startswith(self._machine.get_machine_name()), output)[0]
180
181     def __rackpower(self, arg):
182         try:
183             debug.checkcmd([RACKPOWER, arg, self._machine.get_machine_name()])
184         except subprocess.CalledProcessError:
185             debug.warning("rackpower %s %s failed" %
186                           (arg, self._machine.get_machine_name()))
187
188     def reboot(self):
189         self.__usbboot()
190
191     def shutdown(self):
192         self.__rackpower('-d')
193
194 for pb in ETHRackPandaboardMachine._machines:
195     class TmpMachine(ETHRackPandaboardMachine):
196         name = pb
197     MachineFactory.addMachine(pb, TmpMachine, **ETHRackPandaboardMachine._machines[pb])
198
199 MachineFactory.addMachine("panda_local", PandaboardMachine,
200                           bootarch='armv7',
201                           platform='omap44xx',
202                           ncores=2)