Revision da3450c23a675fb515ea0a73e95e6c4a7462d4a0 authored by rpls on 06 June 2021, 20:06:52 UTC, committed by GitHub on 06 June 2021, 20:06:52 UTC
* Make entire platform running code abstract * Make size benchmark use the new build system * Support for building Intel HEX files (or other formats) * Remove infinite loops at the end of tests Leave this to the specific platforms. Most startup files for embedded systems have an infinite loop after the main call anyway. But if we allow for a propper exit, we can, e.g., indicate an exit via semihosting. * Add new interface to query maximum stack size. * Add reusable buildsystem scripts * Add reusable platform implementations * Define proper targets for testvector generation * Add a documentation for the build system * Make all-in-one compilation the default * Remove references to pqm3 * Fix for older make versions * adjust mupq to run multiple iterations in a single binary * Depend on config file to trigger rebuild instead of an error * Objcopy call doesn't need to depend on config * Fix waiting for start * Reorganize symmetric crypto sources * Set C standard explicitly * Allow for second expansion * Reset input buffer before flashing * Let the platform decide whether to use function/data sections * Flip the order of source files to match the old PQM4 build behaviour * Output the plus seperators as a pseudo-progress bar * Add an environment variable to add optional extra args for st-flash Co-authored-by: Matthias J. Kannwischer <matthias@kannwischer.eu>
1 parent f1943b6
platforms.py
from mupq import mupq
import abc
import re
import serial
import subprocess
import time
import os
try:
import chipwhisperer as cw
except ImportError:
pass
class Qemu(mupq.Platform):
start_pat = re.compile(b'.*={4,}\n', re.DOTALL)
end_pat = re.compile(b'#\n', re.DOTALL)
def __init__(self, qemu, machine):
super().__init__()
self.qemu = qemu
self.machine = machine
self.platformname = "qemu"
def __enter__(self):
return super().__enter__()
def __exit__(self, *args, **kwargs):
return super().__exit__(*args, **kwargs)
def run(self, binary_path):
args = [
self.qemu,
"-M",
self.machine,
"-nographic",
"-semihosting",
"-kernel",
binary_path,
]
self.log.info(f'Running QEMU: {" ".join(args)}')
output = subprocess.check_output(args,
stdin=subprocess.DEVNULL)
start = self.start_pat.search(output)
end = self.end_pat.search(output, start.end())
if end is None:
return 'ERROR'
return output[start.end():end.start()].decode('utf-8', 'ignore')
class SerialCommsPlatform(mupq.Platform):
# Start pattern is at least five equal signs
start_pat = re.compile(b'.*={4,}\n', re.DOTALL)
def __init__(self, tty="/dev/ttyACM0", baud=38400, timeout=60):
super().__init__()
self._dev = serial.Serial(tty, baud, timeout=timeout)
def __enter__(self):
return super().__enter__()
def __exit__(self, *args, **kwargs):
self._dev.close()
return super().__exit__(*args, **kwargs)
def run(self, binary_path):
self._dev.reset_input_buffer()
self.flash(binary_path)
# Wait for the first equal sign
if self._dev.read_until(b'=')[-1] != b'='[0]:
raise Exception('Timout waiting for start')
# Wait for the end of the equal delimiter
start = self._dev.read_until(b'\n')
self.log.debug(f'Found start pattern: {start}')
if self.start_pat.fullmatch(start) is None:
raise Exception('Start does not match')
# Wait for the end
output = bytearray()
while len(output) == 0 or output[-1] != b'#'[0]:
data = self._dev.read_until(b'#')
if b"+" in data:
print("+" * data.count(b"+"), end='', flush=True)
output.extend(data)
print()
return output[:-1].decode('utf-8', 'ignore')
@abc.abstractmethod
def flash(self, binary_path):
pass
class OpenOCD(SerialCommsPlatform):
def __init__(self, script, tty="/dev/ttyACM0", baud=38400, timeout=60):
super().__init__(tty, baud, timeout)
self.script = script
def flash(self, binary_path):
subprocess.check_call(
["openocd", "-f", self.script, "-c", f"program {binary_path} verify reset exit"],
# stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
class StLink(SerialCommsPlatform):
def flash(self, binary_path):
if os.getenv("MUPQ_ST_FLASH_ARGS") is not None:
extraargs = os.getenv("MUPQ_ST_FLASH_ARGS").split()
subprocess.check_call(
["st-flash"] + extraargs + ["--reset", "write", binary_path, "0x8000000"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
class ChipWhisperer(mupq.Platform):
# Start pattern is at least five equal signs
start_pat = re.compile('.*={4,}\n', re.DOTALL)
# End pattern is a hash with a newline
end_pat = re.compile('.*#\n', re.DOTALL)
def __init__(self):
super().__init__()
self.platformname = "cw"
self.scope = cw.scope()
self.target = cw.target(self.scope)
self.scope.default_setup()
def __enter__(self):
return super().__enter__()
def __exit__(self, *args, **kwargs):
self.target.close()
return super().__exit__(*args, **kwargs)
def device(self):
return self.wrapper
def reset_target(self):
self.scope.io.nrst = 'low'
time.sleep(0.05)
self.scope.io.nrst = 'high'
time.sleep(0.05)
def flash(self, binary_path):
prog = cw.programmers.STM32FProgrammer()
prog.scope = self.scope
prog.open()
prog.find()
prog.erase()
prog.program(binary_path, memtype="flash", verify=False)
prog.close()
def run(self, binary_path):
self.flash(binary_path)
self.target.flush()
self.reset_target()
data = ''
# Wait for the first equal sign
while '=' not in data:
data += self.target.read()
# Wait for the end of the equal delimiter
match = None
while match is None:
data += self.target.read()
match = self.start_pat.match(data)
# Remove the start pattern
data = data[:match.end()]
# Wait for the end
match = None
while match is None:
data += self.target.read()
match = self.end_pat.match(data)
# Remove stop pattern and return
return data[:match.end() - 2]
Computing file changes ...