@@ -0,0 +1,2 @@ | |||
*.pyc | |||
elmo/* |
@@ -0,0 +1,11 @@ | |||
# ELMO Online | |||
ELMO Online is a Python library which proposes an encapsulation of the binary project ELMO. | |||
[MOW17] **Towards Practical Tools for Side | |||
Channel Aware Software Engineering : ’Grey Box’ Modelling for Instruction Leakages** | |||
by _David McCann, Elisabeth Oswald et Carolyn Whitnall_. | |||
https://www.usenix.org/conference/ | |||
usenixsecurity17/technical-sessions/presentation/mccann. | |||
**ELMO GitHub**: https://github.com/sca-research/ELMO |
@@ -0,0 +1,192 @@ | |||
import numpy as np | |||
import os | |||
def hweight(n): | |||
c = 0 | |||
while n>0: | |||
c += (n & 1) | |||
n >>= 1 | |||
return c | |||
def hdistance(x,y): | |||
return hweight(x^y) | |||
def binary_writing(n, nb_bits=32, with_hamming=False): | |||
n = np.array(n) | |||
w, h = np.zeros((nb_bits, len(n))), np.zeros((len(n))) | |||
for ind in range(nb_bits): | |||
w[ind] = (n & 1) | |||
h += w[ind] | |||
n >>= 1 | |||
ind += 1 | |||
return (w, h) if with_hamming else w | |||
PREVIOUS = 0 | |||
CURRENT = 1 | |||
SUBSEQUENT = 2 | |||
class ELMOEngine: | |||
def __init__(self): | |||
self.load_coefficients() | |||
self.reset_points() | |||
def _extract_data(self, nb): | |||
coeffs = self.coefficients[self.pos:self.pos+nb] | |||
self.pos += nb | |||
return coeffs | |||
def load_coefficients(self): | |||
filename = os.path.dirname(os.path.abspath(__file__))+'/elmo/coeffs.txt' | |||
self.coefficients = None | |||
with open(filename, 'r') as _file: | |||
self.coefficients = np.array([list(map(float, line.split())) for line in _file.readlines()[:2153]]) | |||
if self.coefficients is None: | |||
raise IOError('Problem to read the coefficients.') | |||
self.pos = 0 | |||
self.constant = np.squeeze(self._extract_data(1)) | |||
self.PrvInstr = self._extract_data(4) | |||
self.SubInstr = self._extract_data(4) | |||
self.Operand1 = self._extract_data(32) | |||
self.Operand2 = self._extract_data(32) | |||
self.BitFlip1 = self._extract_data(32) | |||
self.BitFlip2 = self._extract_data(32) | |||
self.HWOp1PrvInstr = self._extract_data(4) | |||
self.HWOp2PrvInstr = self._extract_data(4) | |||
self.HDOp1PrvInstr = self._extract_data(4) | |||
self.HDOp2PrvInstr = self._extract_data(4) | |||
self.HWOp1SubInstr = self._extract_data(4) | |||
self.HWOp2SubInstr = self._extract_data(4) | |||
self.HDOp1SubInstr = self._extract_data(4) | |||
self.HDOp2SubInstr = self._extract_data(4) | |||
self.Operand1_bitinteractions = self._extract_data(496) | |||
self.Operand2_bitinteractions = self._extract_data(496) | |||
self.BitFlip1_bitinteractions = self._extract_data(496) | |||
self.BitFlip2_bitinteractions = self._extract_data(496) | |||
def reset_points(self): | |||
self.points = [] | |||
self.power = None | |||
def add_point(self, triplet, previous_ops, current_ops): | |||
self.points.append((triplet, previous_ops, current_ops)) | |||
def _dot(self, a, b): | |||
return np.sum(a * b, axis=0) | |||
def calculate_point(self, triplet, previous_ops, current_ops, debug=False): | |||
nb_points = triplet.shape[1] | |||
instructiontype = triplet[CURRENT] | |||
instructiontype = instructiontype % 5 # Type 5 = Instruction was not profiled | |||
# Previous | |||
previous_instruction_typedec = triplet[PREVIOUS] | |||
previous_instruction_type = np.zeros((5, nb_points)) | |||
for i in range(nb_points): | |||
if previous_instruction_typedec[i] < 5: | |||
previous_instruction_type[previous_instruction_typedec[i],i] = 1 | |||
# Current | |||
(current_op1_binary, hw_op1) = binary_writing(current_ops[0], with_hamming=True) | |||
(current_op2_binary, hw_op2) = binary_writing(current_ops[1], with_hamming=True) | |||
(current_op1_bitflip, hd_op1) = binary_writing(previous_ops[0] ^ current_ops[0], with_hamming=True) | |||
(current_op2_bitflip, hd_op2) = binary_writing(previous_ops[1] ^ current_ops[1], with_hamming=True) | |||
current_instruction_typedec = instructiontype | |||
current_instruction_type = np.zeros((5, nb_points)) | |||
for i in range(nb_points): | |||
if triplet[CURRENT,i] < 5: | |||
current_instruction_type[current_instruction_typedec[i],i] = 1 | |||
# Subsequent | |||
subsequent_instruction_typedec = triplet[SUBSEQUENT] | |||
subsequent_instruction_type = np.zeros((5, nb_points)) | |||
for i in range(nb_points): | |||
if subsequent_instruction_typedec[i] < 5: | |||
subsequent_instruction_type[subsequent_instruction_typedec[i],i] = 1 | |||
# Component variables | |||
PrvInstr_data = self._dot( previous_instruction_type[1:], self.PrvInstr[:,instructiontype] ) | |||
SubInstr_data = self._dot( subsequent_instruction_type[1:], self.SubInstr[:,instructiontype] ) | |||
Operand1_data = self._dot( current_op1_binary, self.Operand1[:,instructiontype] ) | |||
Operand2_data = self._dot( current_op2_binary, self.Operand2[:,instructiontype] ) | |||
BitFlip1_data = self._dot( current_op1_bitflip, self.BitFlip1[:,instructiontype] ) | |||
BitFlip2_data = self._dot( current_op2_bitflip, self.BitFlip2[:,instructiontype] ) | |||
HWOp1PrvInstr_data = hw_op1 * self._dot(previous_instruction_type[1:], self.HWOp1PrvInstr[:,instructiontype]) | |||
HWOp2PrvInstr_data = hw_op2 * self._dot(previous_instruction_type[1:], self.HWOp2PrvInstr[:,instructiontype]) | |||
HDOp1PrvInstr_data = hd_op1 * self._dot(previous_instruction_type[1:], self.HDOp1PrvInstr[:,instructiontype]) | |||
HDOp2PrvInstr_data = hd_op2 * self._dot(previous_instruction_type[1:], self.HDOp2PrvInstr[:,instructiontype]) | |||
HWOp1SubInstr_data = hw_op1 * self._dot(subsequent_instruction_type[1:], self.HWOp1SubInstr[:,instructiontype]) | |||
HWOp2SubInstr_data = hw_op2 * self._dot(subsequent_instruction_type[1:], self.HWOp2SubInstr[:,instructiontype]) | |||
HDOp1SubInstr_data = hd_op1 * self._dot(subsequent_instruction_type[1:], self.HDOp1SubInstr[:,instructiontype]) | |||
HDOp2SubInstr_data = hd_op2 * self._dot(subsequent_instruction_type[1:], self.HDOp2SubInstr[:,instructiontype]) | |||
Operand1_bitinteractions_data = np.zeros((nb_points)) | |||
Operand2_bitinteractions_data = np.zeros((nb_points)) | |||
BitFlip1_bitinteractions_data = np.zeros((nb_points)) | |||
BitFlip2_bitinteractions_data = np.zeros((nb_points)) | |||
count = 0 | |||
for i in range(32): | |||
for j in range(i+1,32): | |||
Operand1_bitinteractions_data += self.Operand1_bitinteractions[count,instructiontype] * current_op1_binary[i] * current_op1_binary[j] | |||
Operand2_bitinteractions_data += self.Operand2_bitinteractions[count,instructiontype] * current_op2_binary[i] * current_op2_binary[j] | |||
BitFlip1_bitinteractions_data += self.BitFlip1_bitinteractions[count,instructiontype] * current_op1_bitflip[i] * current_op1_bitflip[j] | |||
BitFlip2_bitinteractions_data += self.BitFlip2_bitinteractions[count,instructiontype] * current_op2_bitflip[i] * current_op2_bitflip[j] | |||
count += 1 | |||
power = self.constant[instructiontype] \ | |||
+ PrvInstr_data + SubInstr_data \ | |||
+ Operand1_data + Operand2_data \ | |||
+ BitFlip1_data + BitFlip2_data \ | |||
+ HWOp1PrvInstr_data + HWOp2PrvInstr_data \ | |||
+ HDOp1PrvInstr_data + HDOp2PrvInstr_data \ | |||
+ HWOp1SubInstr_data + HWOp2SubInstr_data \ | |||
+ HDOp1SubInstr_data + HDOp2SubInstr_data \ | |||
+ Operand1_bitinteractions_data + Operand2_bitinteractions_data \ | |||
+ BitFlip1_bitinteractions_data + BitFlip2_bitinteractions_data | |||
for i in range(nb_points): | |||
if triplet[CURRENT,i] == 5: | |||
power[i] = self.constant[triplet[CURRENT,i]] | |||
if debug: | |||
print([self.constant[instructiontype], \ | |||
PrvInstr_data, SubInstr_data, \ | |||
Operand1_data, Operand2_data, \ | |||
BitFlip1_data, BitFlip2_data, \ | |||
HWOp1PrvInstr_data, HWOp2PrvInstr_data, \ | |||
HDOp1PrvInstr_data, HDOp2PrvInstr_data, \ | |||
HWOp1SubInstr_data, HWOp2SubInstr_data, \ | |||
HDOp1SubInstr_data, HDOp2SubInstr_data, \ | |||
Operand1_bitinteractions_data, Operand2_bitinteractions_data, \ | |||
BitFlip1_bitinteractions_data, BitFlip2_bitinteractions_data]) | |||
return power | |||
def run(self): | |||
nb_points = len(self.points) | |||
triplet = np.array([p[0] for p in self.points]).T # shape = (3, nb_points) | |||
previous_ops = np.array([p[1] for p in self.points]).T # shape = (2, nb_points) | |||
current_ops = np.array([p[2] for p in self.points]).T # shape = (2, nb_points) | |||
self.power = self.calculate_point(triplet, previous_ops, current_ops) | |||
def oneshot_point(self, triplet, previous_ops, current_ops): | |||
self.reset_points() | |||
self.add_point(triplet, previous_ops, current_ops) | |||
self.run() | |||
return self.power |
@@ -0,0 +1,66 @@ | |||
from servicethread import OneShotServiceThread | |||
import subprocess | |||
import shutil | |||
from project_reader import ProjectReader | |||
global_variables = {} | |||
class ExecutorThread(OneShotServiceThread): | |||
def __init__(self, ip, port, clientsocket, **kwargs): | |||
super().__init__(ip, port, clientsocket) | |||
self.projects = kwargs['projects'] if 'projects' in kwargs else None | |||
def execute(self): | |||
projects = self.projects | |||
if project is None: | |||
reader = ProjectReader() | |||
projects = {sc.get_project_label(): sc for sc in reader.get_project_classes()} | |||
print('Warning: need to research the projects.') | |||
else: | |||
print('Already have projects') | |||
data = self.protocol.get_data() | |||
self.protocol.please_assert(data) | |||
self.protocol.please_assert('project' in data) | |||
self.protocol.please_assert(data['project'] in projects) | |||
self.protocol.send_ack() | |||
# Get the project | |||
project = projects[data['project']] | |||
# Make the compilation | |||
if False: | |||
print('Compiling binary...') | |||
# Adapt the project source | |||
with open('binaries/Frodo/frodo-base.c', 'r') as _src_file: | |||
content = _src_file.read() | |||
with open('binaries/Frodo/frodo.c', 'w') as _dst_file: | |||
_dst_file.write(content.replace('%NEED_TO_FILL%', str(n))) | |||
# Compile the project | |||
make_directory = 'projects/{}/{}'.format(project.get_project_directory(), project.get_make_directory()) | |||
process = subprocess.Popen('make', shell=True, cwd=make_directory, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||
output, error = process.communicate() | |||
if error and ('error' in error.decode('latin-1')): | |||
print("Error to compile") | |||
print(error) | |||
raise Exception() | |||
# Save last compilation data | |||
global_variables[project_name] = { | |||
'last_n': n, | |||
} | |||
# Generate the trace by launching ELMO | |||
command = './elmo ../projects/{}/{}'.format(project.get_project_directory(), project.get_binary()) | |||
process = subprocess.Popen(command, shell=True, cwd='elmo_online/elmo/', executable='/bin/bash', stdout=subprocess.PIPE) | |||
output, error = process.communicate() | |||
# Send results | |||
self.protocol.send_data({ | |||
'output': output.decode('latin-1') if output else None, | |||
'error': error.decode('latin-1') if error else None, | |||
}) | |||
self.protocol.close() |
@@ -0,0 +1,6 @@ | |||
from .project_reader import Project | |||
reader = ProjectReader() | |||
projects = reader.get_projects() | |||
for key, project in projects.items(): | |||
globals()[key] = project |
@@ -0,0 +1,39 @@ | |||
from servicethread import PermanentServiceThread | |||
import socket | |||
class ListeningThread(PermanentServiceThread): | |||
def __init__(self, host, port, threadclass, **kwargs): | |||
super().__init__() | |||
self.hostname = host | |||
self.port = port | |||
self.threadclass = threadclass | |||
self.kwargs = kwargs | |||
def execute(self): | |||
self.tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |||
self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) | |||
# self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_ATTACH_REUSEPORT_CBPF, 1) | |||
self.tcpsock.bind((self.hostname, self.port)) | |||
self.tcpsock.listen(5) | |||
print('[port][%s] Listening' % self.port) | |||
while self.is_running(): | |||
try: | |||
(clientsocket, (ip, port)) = self.tcpsock.accept() | |||
print('[port][{}] Accepted: {} <=> {}'.format( | |||
self.port, | |||
clientsocket.getsockname(), | |||
clientsocket.getpeername(), | |||
)) | |||
newthread = self.threadclass(ip, port, clientsocket, **self.kwargs) | |||
newthread.start() | |||
except socket.timeout: | |||
pass | |||
def stop(self): | |||
super().stop() | |||
clientsocker = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
clientsocker.connect( (self.hostname, self.port) ) | |||
self.tcpsock.close() | |||
print('[port][%s] Stop listening' % self.port) |
@@ -0,0 +1,214 @@ | |||
import os, re | |||
import socket | |||
from protocol import SocketTool | |||
import numpy as np | |||
def to_hex(v, nb_bits=16): | |||
try: | |||
v_hex = v.hex() | |||
except AttributeError: | |||
v_hex = hex(v)[2:] | |||
return '0'*(nb_bits//4-len(v_hex)) + v_hex | |||
def split_octet(hexstr): | |||
return [hexstr[i:i+2] for i in range(0, len(hexstr), 2)] | |||
def to_signed_hex(v, nb_bits=16): | |||
return split_octet(to_hex(v & (2**nb_bits-1), nb_bits=nb_bits)) | |||
def write(_input, uintXX, nb_bits=16): | |||
uintXX = to_signed_hex(uintXX, nb_bits=nb_bits) | |||
for i in range(nb_bits//8): | |||
_input.write(uintXX[i]+'\n') | |||
def write_list(_input, uint16_list): | |||
for uint16 in uint16_list: | |||
write(_input, uint16) | |||
def launch_simulation(quiet=False, **kwargs): | |||
try: | |||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
s.connect(('localhost', 5000)) | |||
SocketTool.send_data(s, kwargs) | |||
if not SocketTool.get_ack(s): | |||
raise RuntimeError("The request has been refused !") | |||
else: | |||
data = SocketTool.get_data(s) | |||
if data['error'] and not quiet: | |||
raise Exception("The simulation return an error") | |||
return data['output'], data['error'] | |||
s.close() | |||
except IOError: | |||
raise RuntimeError("The connection refused. Has the ELMO server been switch on ?") | |||
class SimulationProject: | |||
_nb_bits_for_nb_challenges = 16 | |||
_project_directory = None | |||
### Define the project | |||
@classmethod | |||
def get_project_directory(cl): | |||
if cl._project_directory: | |||
return cl._project_directory | |||
else: | |||
raise NotImplementedError() | |||
@classmethod | |||
def set_project_directory(cl, project_directory): | |||
cl._project_directory = project_directory | |||
@classmethod | |||
def get_project_label(cl): | |||
return cl.get_project_directory() | |||
@classmethod | |||
def get_make_directory(cl): | |||
return '' | |||
@classmethod | |||
def get_binary(cl): | |||
raise NotImplementedError() | |||
@classmethod | |||
def get_parameters_names(cl): | |||
return set() | |||
@classmethod | |||
def adapt_project(cl, parameters): | |||
return | |||
def get_challenge_format(self): | |||
raise NotImplementedError() | |||
### Tools to realize the simulation of the project | |||
def __init__(self, challenges=None): | |||
self.elmo_folder = os.path.dirname(os.path.abspath(__file__))+'/elmo' | |||
self.challenges = challenges | |||
self.is_executed = False | |||
def set_challenges(self, challenges): | |||
self.challenges = challenges | |||
def get_writable_input_file(self): | |||
return open('{}/input.txt'.format(self.elmo_folder), 'w') | |||
def set_input_for_each_challenge(self, input, challenge): | |||
format = self.get_challenge_format() | |||
def aux(sizes, data): | |||
if len(sizes) == 0: | |||
write(input, data) | |||
else: | |||
assert len(data) == sizes[0], 'Incorrect format for challenge. Get {} instead of {}'.format(len(data), sizes[0]) | |||
for i in range(sizes[0]): | |||
aux(sizes[1:], data[i]) | |||
for num_part in range(len(format)): | |||
aux(format[num_part], challenge[num_part]) | |||
def set_input(self, input): | |||
assert len(self.challenges) < 2**16, 'The number of challenges must be strictly lower than 65536. Currently, there are {} challenges.'.format(len(self.challenges)) | |||
write(input, len(self.challenges), nb_bits=self._nb_bits_for_nb_challenges) | |||
for challenge in self.challenges: | |||
self.set_input_for_each_challenge(input, challenge) | |||
def run(self): | |||
with open('{}/input.txt'.format(self.elmo_folder), 'w') as _input: | |||
self.set_input(_input) | |||
launch_simulation(project=self.get_project_label(), quiet=False) | |||
self.is_executed = True | |||
def get_asmtrace_filename(self): | |||
return '{}/output/asmoutput/asmtrace00001.txt'.format(self.elmo_folder) | |||
def get_indexes_of(self, condition): | |||
with open(self.get_asmtrace_filename(), 'r') as _file: | |||
asmtrace = _file.readlines() | |||
return [i for i, instr in enumerate(asmtrace) if condition(instr)] | |||
def get_number_of_traces(self): | |||
return len(self.challenges) | |||
def get_results(self, only_filenames=False, reorganise=None, indexes=None): | |||
assert self.is_executed | |||
nb_traces = self.get_number_of_traces() | |||
trace_filenames = [] | |||
for filename in os.listdir('{}/output/traces/'.format(self.elmo_folder)): | |||
if re.search(r'^trace\d+\.trc$', filename): | |||
trace_filenames.append('{}/output/traces/{}'.format(self.elmo_folder, filename)) | |||
if len(trace_filenames) >= nb_traces: | |||
break | |||
assert len(trace_filenames) == nb_traces | |||
results = trace_filenames | |||
if not only_filenames: | |||
for i in range(len(results)): | |||
with open(results[i], 'r') as _file: | |||
if indexes is not None: | |||
results[i] = list(map(float, _file.readlines()[indexes])) | |||
else: | |||
results[i] = list(map(float, _file.readlines())) | |||
if reorganise is not None: | |||
results = reorganise(results) | |||
return results | |||
def get_traces(self, reorganise=None, indexes=None): | |||
results = self.get_results(only_filenames=False, reorganise=reorganise,indexes=indexes) | |||
nb_traces = self.get_number_of_traces() | |||
trace_length = len(results[0]) | |||
traces = np.zeros((nb_traces, trace_length)) | |||
for i in range(nb_traces): | |||
traces[i,:] = results[i] | |||
if reorganise is not None: | |||
traces = reorganise(traces) | |||
return traces | |||
def get_printed_data(self): | |||
with open('{}/output/printdata.txt'.format(self.elmo_folder), 'r') as _file: | |||
data = list(map(lambda x: int(x, 16), _file.readlines())) | |||
nb_traces = self.get_number_of_traces() | |||
nb_data_per_trace = len(data) // nb_traces | |||
return [data[nb_data_per_trace*i:nb_data_per_trace*(i+1)] for i in range(nb_traces)] | |||
def analyse_operands(self, num_line, num_trace=1): | |||
num_str = str(num_trace) | |||
num_str = '0'*(5-len(num_str)) + num_str | |||
operands_filename = self.elmo_folder + '/output/operands/operands{}.txt'.format(num_str) | |||
trace_filename = self.elmo_folder + '/output/traces/trace0000{}.trc'.format(num_trace) | |||
is_multiple = (type(num_line) is list) | |||
if not is_multiple: | |||
num_line = [num_line] | |||
output = [{}]*len(num_line) | |||
with open(operands_filename, 'r') as _file: | |||
lines = _file.readlines() | |||
for i, num in enumerate(num_line): | |||
line = lines[num].split() | |||
data = list(map(int, line[0:7])) | |||
output[i]['previous'] = data[0:2] | |||
output[i]['current'] = data[2:4] | |||
output[i]['triplet'] = data[4:7] | |||
output[i]['other'] = list(map(float, line[7:])) | |||
with open(trace_filename, 'r') as _file: | |||
lines = _file.readlines() | |||
for i, num in enumerate(num_line): | |||
line = lines[num] | |||
output[i]['power'] = float(line) | |||
return output if is_multiple else output[0] | |||
@@ -0,0 +1,42 @@ | |||
from project_base import SimulationProject | |||
import os, re | |||
import inspect | |||
PROJECTS_REPOSITORY = 'projects' | |||
class ProjectReader: | |||
def __init__(self): | |||
pass | |||
def get_projects(self): | |||
projects = {} | |||
for root, repositories, files in os.walk(PROJECTS_REPOSITORY): | |||
for filename in files: | |||
if re.fullmatch(r'.*project.*\.py', filename): | |||
# Encapsulation the project | |||
complete_filename = root+'/'+filename | |||
globals = { | |||
#'__builtins__': {'__build_class__': __build_class__}, | |||
'SimulationProject': SimulationProject, | |||
} | |||
locals = {} | |||
# Read the project code | |||
with open(complete_filename, 'r') as _file: | |||
project = '\n'.join(_file.readlines()) | |||
exec(project, globals, locals) | |||
# Extract the simulations | |||
for key, obj in locals.item(): | |||
if inspect.isclass(obj) and issubclass(obj, SimulationProject): | |||
if key in projects: | |||
print('Warning! Multiplie simulation with the same name. Simulation ignored: {} in {}'.format(key, complete_filename[len(PROJECTS_REPOSITORY)+1:])) | |||
else: | |||
obj.set_project_directory(root[len(PROJECTS_REPOSITORY)+1:]) | |||
projects[key] = obj | |||
return projects | |||
def get_project_classes(self): | |||
return self.get_projects().values() |
@@ -0,0 +1,3 @@ | |||
* | |||
!.gitignore | |||
!elmoasmfunctions* |
@@ -0,0 +1,257 @@ | |||
## | |||
## University of Bristol – Open Access Software Licence | |||
## Copyright (c) 2016, The University of Bristol, a chartered | |||
## corporation having Royal Charter number RC000648 and a charity | |||
## (number X1121) and its place of administration being at Senate | |||
## House, Tyndall Avenue, Bristol, BS8 1TH, United Kingdom. | |||
## All rights reserved | |||
## | |||
## Redistribution and use in source and binary forms, with or without | |||
## modification, are permitted provided that the following conditions | |||
## are met: | |||
## | |||
## 1. Redistributions of source code must retain the above copyright | |||
## notice, this list of conditions and the following disclaimer. | |||
## | |||
## 2. Redistributions in binary form must reproduce the above | |||
## copyright notice, this list of conditions and the following | |||
## disclaimer in the documentation and/or other materials provided | |||
## with the distribution. | |||
## | |||
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||
## FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||
## COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
## INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
## (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
## OF THE POSSIBILITY OF SUCH DAMAGE. | |||
## | |||
## Any use of the software for scientific publications or commercial | |||
## purposes should be reported to the University of Bristol | |||
## (OSI-notifications@bristol.ac.uk and quote reference 2668). This is | |||
## for impact and usage monitoring purposes only. | |||
## | |||
## Enquiries about further applications and development opportunities | |||
## are welcome. Please contact elisabeth.oswald@bristol.ac.uk | |||
## | |||
.syntax unified | |||
.text | |||
.thumb | |||
.func starttrigger | |||
.global starttrigger | |||
starttrigger: | |||
push {r0-r7} | |||
movs r4, #0xE0 | |||
lsls r4, #24 | |||
movs r5, #0x04 | |||
eors r4, r5 | |||
movs r5, #1 | |||
str r5, [r4, #0] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func endtrigger | |||
.global endtrigger | |||
endtrigger: | |||
push {r0-r7} | |||
movs r4, #0xE0 | |||
lsls r4, #24 | |||
movs r5, #0x04 | |||
eors r4, r5 | |||
movs r5, #0 | |||
str r5, [r4, #0] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func readbyte | |||
.global readbyte | |||
readbyte: | |||
push {r0-r7} | |||
movs r4, #0xE1 | |||
lsls r4, #24 | |||
ldr r1, [r4, #0] | |||
strb r1, [r0, #0] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func LoadN | |||
.global LoadN | |||
LoadN: | |||
push {r0-r7} | |||
movs r4, #0xE1 | |||
lsls r4, #24 | |||
movs r5, #0x10 | |||
eors r4, r5 | |||
ldr r1, [r4, #0] | |||
str r1, [r0, #0] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func randbyte | |||
.global randbyte | |||
randbyte: | |||
push {r0-r7} | |||
movs r4, #0xE1 | |||
lsls r4, #24 | |||
movs r5, #0x04 | |||
eors r4, r5 | |||
ldr r1, [r4, #0] | |||
strb r1, [r0, #0] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func getstart | |||
.global getstart | |||
getstart: | |||
push {r0-r7} | |||
movs r4, #0xE1 | |||
lsls r4, #24 | |||
movs r5, #0x08 | |||
eors r4, r5 | |||
ldr r1, [r4, #0] | |||
str r1, [r0, #0] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func getruncount | |||
.global getruncount | |||
getruncount: | |||
push {r0-r7} | |||
movs r4, #0xE1 | |||
lsls r4, #24 | |||
movs r5, #0x0C | |||
eors r4, r5 | |||
ldr r1, [r4, #0] | |||
str r1, [r0, #0] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func printbyte | |||
.global printbyte | |||
printbyte: | |||
push {r0-r7} | |||
movs r4, #0xE0 | |||
lsls r4, #24 | |||
ldrb r5, [r0] | |||
str r5, [r4] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func endprogram | |||
.global endprogram | |||
endprogram: | |||
push {r0-r7} | |||
movs r4, #0xF0 | |||
lsls r4, #24 | |||
movs r5, #0 | |||
str r5, [r4] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func initialisemaskflow | |||
.global initialisemaskflow | |||
# Takes address of key as input (r0) | |||
initialisemaskflow: | |||
push {r0-r7} | |||
movs r4, #0xE0 | |||
lsls r4, #24 | |||
movs r5, #0x40 | |||
eors r4, r5 | |||
str r0, [r4] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func resetmaskflow | |||
.global resetmaskflow | |||
resetmaskflow: | |||
push {r0-r7} | |||
movs r4, #0xE0 | |||
lsls r4, #24 | |||
movs r5, #0x42 | |||
eors r4, r5 | |||
movs r5, #0 | |||
str r5, [r4] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func setmaskflowstart | |||
.global setmaskflowstart | |||
# Takes r0 as start number | |||
setmaskflowstart: | |||
push {r0-r7} | |||
movs r4, #0xE0 | |||
lsls r4, #24 | |||
movs r5, #0x44 | |||
eors r4, r5 | |||
str r0, [r4] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc | |||
.func resetdatafile | |||
.global resetdatafile | |||
resetdatafile: | |||
push {r0-r7} | |||
movs r4, #0xE0 | |||
lsls r4, #24 | |||
movs r5, #0x46 | |||
eors r4, r5 | |||
movs r5, #0 | |||
str r5, [r4] | |||
pop {r0-r7} | |||
bx lr | |||
.endfunc |
@@ -0,0 +1,55 @@ | |||
/* | |||
* University of Bristol – Open Access Software Licence | |||
* Copyright (c) 2016, The University of Bristol, a chartered | |||
* corporation having Royal Charter number RC000648 and a charity | |||
* (number X1121) and its place of administration being at Senate | |||
* House, Tyndall Avenue, Bristol, BS8 1TH, United Kingdom. | |||
* All rights reserved | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above | |||
* copyright notice, this list of conditions and the following | |||
* disclaimer in the documentation and/or other materials provided | |||
* with the distribution. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
* OF THE POSSIBILITY OF SUCH DAMAGE. | |||
* | |||
* Any use of the software for scientific publications or commercial | |||
* purposes should be reported to the University of Bristol | |||
* (OSI-notifications@bristol.ac.uk and quote reference 2668). This is | |||
* for impact and usage monitoring purposes only. | |||
* | |||
* Enquiries about further applications and development opportunities | |||
* are welcome. Please contact elisabeth.oswald@bristol.ac.uk | |||
*/ | |||
extern void starttrigger(void); | |||
extern void endtrigger(void); | |||
extern void randbyte(unsigned char * pointer); | |||
extern void LoadN(void* addr); | |||
extern void readbyte(unsigned char * pointer); | |||
extern void printbyte(unsigned char * pointer); | |||
extern void endprogram(void); | |||
extern void getstart(unsigned int * pointer); | |||
extern void getruncount(unsigned int * pointer); | |||
extern void initialisemaskflow(unsigned char * pointer); | |||
extern void resetmaskflow(void); | |||
extern void setmaskflowstart(unsigned int start); | |||
extern void resetdatafile(void); |
@@ -0,0 +1,134 @@ | |||
import os | |||
import json | |||
class ClosureException(Exception): | |||
pass | |||
# https://stackoverflow.com/questions/20007319/how-to-do-a-large-text-file-transfer-in-python | |||
class SocketTool: | |||
@classmethod | |||
def convert_to_bytes(cl, no): | |||
result = bytearray() | |||
result.append(no & 255) | |||
for i in range(3): | |||
no = no >> 8 | |||
result.append(no & 255) | |||
return result | |||
@classmethod | |||
def bytes_to_number(cl, b): | |||
import sys | |||
b = b if (sys.version_info > (3, 0)) else map(ord, b) | |||
res = 0 | |||
for i in range(4): | |||
res += b[i] << (i*8) | |||
return res | |||
@classmethod | |||
def send_file(cl, s, filename, mode='rb'): | |||
length = os.path.getsize(filename) | |||
s.send(cl.convert_to_bytes(length)) # has to be 4 bytes | |||
with open(filename, mode) as infile: | |||
d = infile.read(1024*64) # We send by pack of 64 ko | |||
while d: | |||
s.send(d) | |||
d = infile.read(1024*64) | |||
@classmethod | |||
def get_file(cl, s): | |||
size = s.recv(4) # assuming that the size won't be bigger then 1GB | |||
size = cl.bytes_to_number(size) | |||
current_size = 0 | |||
buffer = b'' | |||
while current_size < size: | |||
data = s.recv(1024*64) | |||
if not data: | |||
break | |||
if len(data) + current_size > size: | |||
data = data[:size-current_size] # trim additional data | |||
buffer += data | |||
# you can stream here to disk | |||
current_size += len(data) | |||
# you have entire file in memory | |||
return buffer | |||
@classmethod | |||
def send_data(cl, s, data): | |||
data = json.dumps(data) | |||
data = data.encode('utf-8') | |||
s.send(cl.convert_to_bytes(len(data))) # has to be 4 bytes | |||
s.send(data) | |||
@classmethod | |||
def get_data(cl, s): | |||
import sys | |||
exception_class = json.decoder.JSONDecodeError if (sys.version_info > (3, 0)) else ValueError | |||
try: | |||
size = s.recv(4) | |||
if not size: | |||
return None | |||
size = cl.bytes_to_number(size) | |||
data = s.recv(size) | |||
data = data.decode('utf-8') | |||
data = json.loads(data) | |||
return data | |||
except exception_class: | |||
return None | |||
@classmethod | |||
def send_ack(cl, s, positive=True): | |||
data = 'OK' if positive else 'NO' | |||
s.send(data.encode('ascii')) | |||
@classmethod | |||
def get_ack(cl, s): | |||
data = s.recv(2).decode('ascii') | |||
return (data == 'OK') | |||
class Protocol: | |||
def __init__(self, clientsocket): | |||
self.clientsocket = clientsocket | |||
def send_file(self, filename, mode='rb'): | |||
SocketTool.send_file(self.clientsocket, filename, mode) | |||
def get_file(self): | |||
return SocketTool.get_file(self.clientsocket) | |||
def send_data(self, data): | |||
SocketTool.send_data(self.clientsocket, data) | |||
def get_data(self): | |||
return SocketTool.get_data(self.clientsocket) | |||
def send_ack(self, positive=True): | |||
SocketTool.send_ack(self.clientsocket, positive) | |||
def send_nack(self, positive=True): | |||
SocketTool.send_ack(self.clientsocket, not positive) | |||
def get_ack(self): | |||
return SocketTool.get_ack(self.clientsocket) | |||
def please_assert(self, condition): | |||
if not condition: | |||
self.send_nack() | |||
self.clientsocket.close() | |||
raise ClosureException | |||
def get_object_or_nack(self, model, **kwargs): | |||
try: | |||
return model.objects.get(**kwargs) | |||
except model.DoesNotExist: | |||
self.send_nack() | |||
self.clientsocket.close() | |||
raise ClosureException | |||
def close(self): | |||
self.clientsocket.close() |
@@ -0,0 +1,24 @@ | |||
elmo_repository="elmo" | |||
elmo_source="https://github.com/sca-research/ELMO.git" | |||
echo "====== ELMO Online ======" | |||
if [ -d ${elmo_repository} ]; then | |||
echo " - ELMO tool already installed." | |||
else | |||
# Download the tool | |||
git clone --depth=1 --branch=master ${elmo_source} ${elmo_repository} | |||
rm -rf ./${elmo_repository}/.git | |||
# Compile the tool | |||
cd ./${elmo_repository} | |||
make | |||
cd .. | |||
fi | |||
#current_directory=${PWD##*/} | |||
#echo " - Current directory: ${current_directory}" | |||
echo | |||
#cd .. | |||
#python3 -m ${current_directory}.run_server | |||
python3 run_server.py |
@@ -0,0 +1,36 @@ | |||
from listeningthread import ListeningThread | |||
from executorthread import ExecutorThread | |||
def do_main_program(projects): | |||
global thread, stop | |||
thread = ListeningThread('localhost', 5000, ExecutorThread, projects=projects) | |||
thread.start() | |||
def program_cleanup(signum, frame): | |||
global thread, stop | |||
thread.stop() | |||
stop = True | |||
thread = None | |||
stop = False | |||
# Information | |||
from project_reader import ProjectReader | |||
reader = ProjectReader() | |||
projects = {sc.get_project_label(): sc for sc in reader.get_project_classes()} | |||
print('Available projects: %s' % list(projects.keys())) | |||
print('') | |||
# Execute | |||
print("Executing...") | |||
do_main_program(projects) | |||
print("Done ! And now, listening...") | |||
import signal | |||
signal.signal(signal.SIGINT, program_cleanup) | |||
signal.signal(signal.SIGTERM, program_cleanup) | |||
# Wait | |||
import time | |||
while not stop: | |||
time.sleep(1) |
@@ -0,0 +1,43 @@ | |||
import threading | |||
from protocol import Protocol, ClosureException | |||
class ServiceThread(threading.Thread): | |||
def run(self): | |||
self.execute() | |||
def execute(self): | |||
# Method where the service runs | |||
pass | |||
class OneShotServiceThread(ServiceThread): | |||
def __init__(self, ip, port, clientsocket): | |||
threading.Thread.__init__(self) | |||
self.ip = ip | |||
self.port = port | |||
self.clientsocket = clientsocket | |||
self.protocol = Protocol(clientsocket) | |||
def run(self): | |||
try: | |||
self.execute() | |||
except ClosureException: | |||
return | |||
def execute(self): | |||
# Method where the service runs | |||
pass | |||
class PermanentServiceThread(ServiceThread): | |||
def __init__(self): | |||
threading.Thread.__init__(self) | |||
self._is_running = True | |||
def is_running(self): | |||
return self._is_running | |||
def stop(self): | |||
self._is_running = False | |||