From dc5a8d109b38a765829e7ea167f5928cde9c6540 Mon Sep 17 00:00:00 2001 From: Christian Dietrich <christian.dietrich@informatik.uni-erlangen.de> Date: Fri, 20 Mar 2015 17:29:45 +0100 Subject: [PATCH] generator: syscall FSM/PLA implementation Implement all system calls as PLA implementations. Change-Id: I1f0bdcdc085727f5ce7e0aa6e6d83db87ae4896a --- generator/coder/syscall_fsm.py | 103 +++++++++++++++++- generator/main.py | 8 +- .../transform/FiniteStateMachineBuilder.py | 2 +- generator/transform/LogicMinimizer.py | 7 +- os/fsm/pla-fsm.h.in | 68 ++++++++++++ 5 files changed, 181 insertions(+), 7 deletions(-) create mode 100644 os/fsm/pla-fsm.h.in diff --git a/generator/coder/syscall_fsm.py b/generator/coder/syscall_fsm.py index ee0cd22..a7f82f2 100644 --- a/generator/coder/syscall_fsm.py +++ b/generator/coder/syscall_fsm.py @@ -10,11 +10,15 @@ import logging class FSMSystemCalls(FullSystemCalls): - def __init__(self): + def __init__(self, use_pla = False): super(FSMSystemCalls, self).__init__() self.alarms = FSMAlarmTemplate - self.fsm_template = SimpleFSMTemplate + if use_pla: + self.fsm_template = PLA_FSMTemplate + else: + self.fsm_template = SimpleFSMTemplate + def generate_system_code(self): self.generator.source_file.include("syscall.h") @@ -178,7 +182,6 @@ class SimpleFSMTemplate(CodeTemplate): def action_rename(action): task_id = action.impl.task_id if task_id == None: - print(action.subtask) task_id = 255 return task_id self.fsm.rename(actions = action_rename) @@ -266,8 +269,100 @@ class SimpleFSMTemplate(CodeTemplate): ret.append(self.expand_snippet(body)) return ret +class PLA_FSMTemplate(CodeTemplate): + def __init__(self, syscall_fsm): + CodeTemplate.__init__(self, syscall_fsm.generator, "os/fsm/pla-fsm.h.in") + self.syscall_fsm = syscall_fsm + self.system_graph = self.generator.system_graph + self.logic = self.system_graph.get_pass("LogicMinimizer") + self.fsm = self.logic.fsm + + def add_transition_table(self): + # Truth table is generated in pla-fsm.h + return + + + def fsm_event(self, syscall, userspace, kernelspace): + event = None + for ev in self.fsm.events: + if self.fsm.event_mapping[ev.name] == syscall: + event = ev + break + if not event: + return # No Dispatch + # kernelspace.add(Statement('kout << "%s" << endl' % syscall.path())) + task = self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.event", + "unsigned", [str(int(event.name, 2))]) + return task + + def fsm_schedule(self, syscall, userspace, kernelspace): + task = self.fsm_event(syscall, userspace, kernelspace) + if not task: + return + if type(task) == int: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.dispatch", + "void", [str(task)]) + else: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.dispatch", + "void", [task.name]) + + def fsm_iret(self, syscall, userspace, kernelspace): + task = self.fsm_event(syscall, userspace, kernelspace) + if not task: + return + + if type(task) == int: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.iret", + "void", [str(task)]) + else: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.iret", + "void", [task.name]) + + ################################################################ + # Used in Template Code + ################################################################ + def truth_table(self, *args): + # Generate the transition table + initializer = [] + for (mask, pattern, output_state, output_action) in self.logic.truth_table: + initializer.append("{{{0}, {1}, {2}, {3}}}".format( + int(mask, 2), + int(pattern, 2), + int(output_state, 2), + int(output_action, 2))) + + return "{" + (", ".join(initializer)) + "}" + + def mask_pattern_len(self, *args): + return str(self.logic.event_len + self.logic.state_len) + + def truth_table_entries(self, *args): + return str(len(self.logic.truth_table)) + + def initial_state(self, *args): + return str(int(self.fsm.initial_state,2)) + + def dispatch_table(self, *args): + mapping = {} + for k, subtask in self.fsm.action_mapping.items(): + mapping[int(k, 2)] = subtask + if not 0 in mapping: + mapping[0] = None + self.NO_DISPATCH = 0 + + initializer = [] + for k,subtask in sorted(mapping.items(), key = lambda x:x[0]): + if not subtask or subtask.conf.is_isr: + initializer.append("0 /* NO_DISPATCH */") + elif subtask == self.system_graph.idle_subtask: + initializer.append("0 /* IDLE */") + self.IDLE = k + else: + initializer.append("&" +subtask.impl.task_descriptor.name) + if not hasattr(self, "IDLE"): + self.IDLE = len(mapping) + 100 + return ", ".join(initializer) class FSMAlarmTemplate(AlarmTemplate): def __init__(self, rules): AlarmTemplate.__init__(self, rules) - diff --git a/generator/main.py b/generator/main.py index e75db21..d91ec7f 100755 --- a/generator/main.py +++ b/generator/main.py @@ -188,7 +188,7 @@ if __name__ == "__main__": else: os_rules = EncodedOS() - assert options.systemcalls in ("full", "specialized", "fsm") + assert options.systemcalls in ("full", "specialized", "fsm", "fsm:pla") if options.systemcalls == "specialized": # Only when we want to specialize the system calls, run the @@ -201,7 +201,13 @@ if __name__ == "__main__": logging.info("Global control flow information is provided by %s", global_abb_information.name()) syscall_rules = SpecializedSystemCalls(global_abb_information) + elif options.systemcalls == "fsm:pla": + assert options.arch == "posix", "FSM Encoding is only supported for arch=posix" + pass_manager.enqueue_analysis("LogicMinimizer") + pass_manager.enqueue_analysis("fsm") + syscall_rules = FSMSystemCalls(use_pla = True) elif options.systemcalls == "fsm": + assert options.arch == "posix", "FSM Encoding is only supported for arch=posix" pass_manager.enqueue_analysis("fsm") syscall_rules = FSMSystemCalls() else: diff --git a/generator/transform/FiniteStateMachineBuilder.py b/generator/transform/FiniteStateMachineBuilder.py index d06e0d4..01d155f 100644 --- a/generator/transform/FiniteStateMachineBuilder.py +++ b/generator/transform/FiniteStateMachineBuilder.py @@ -20,7 +20,7 @@ class Transition: return self._event.name def __repr__(self): - return "<Transition(%s) %d -> %d: %s>" %(self.event, self.source, self.target, self.action) + return "<Transition(%s) %s -> %s: %s>" %(self.event, self.source, self.target, self.action) class Event: diff --git a/generator/transform/LogicMinimizer.py b/generator/transform/LogicMinimizer.py index df5d807..e346b66 100644 --- a/generator/transform/LogicMinimizer.py +++ b/generator/transform/LogicMinimizer.py @@ -15,7 +15,6 @@ class LogicMinimizer(Analysis): def do(self): fsm = self.system_graph.get_pass("fsm").fsm.copy() - self.fsm = self.call_nova(fsm) def call_nova(self, fsm): @@ -74,6 +73,8 @@ class LogicMinimizer(Analysis): fd.write(".e\n") stdout = subprocess.check_output(["nova", nova_input]).decode('ascii', 'ignore') + with open("%s.nova.stdout" % nova_input, "w+") as fd: + fd.write(stdout) event_mapping = {} state_mapping = {} for line in stdout.split("\n"): @@ -134,5 +135,9 @@ class LogicMinimizer(Analysis): got_output_word |= output_word matches[i] += 1 assert got_output_word == desired_output_word + + #for transition in fsm.transitions: + # print(transition, fsm.event_mapping[transition.event], fsm.action_mapping[transition.action]) + logging.info("%d lines in minimzed truth table", len(self.truth_table)) return fsm diff --git a/os/fsm/pla-fsm.h.in b/os/fsm/pla-fsm.h.in new file mode 100644 index 0000000..e416a64 --- /dev/null +++ b/os/fsm/pla-fsm.h.in @@ -0,0 +1,68 @@ +#include "dispatch.h" + +namespace os { +namespace fsm { + +constexpr const os::scheduler::Task * dispatch_table[] = { + {{{!dispatch_table}}} +}; + + +class SchedulerFSM { + public: + struct Row { + unsigned mask : {{{!mask_pattern_len}}}; + unsigned pattern : {{{!mask_pattern_len}}}; + unsigned output_state : {{{!get:logic.state_len}}}; + unsigned output_action : {{{!get:logic.action_len}}}; + } __attribute__((packed)); + + enum { + IDLE = {{{!get:IDLE}}}, + NO_DISPATCH = {{{!get:NO_DISPATCH}}}, + }; + + SchedulerFSM(unsigned state) : internal_state(state) {} + + unsigned event(unsigned event) { + unsigned input_word = event << {{{!get:logic.state_len}}} | internal_state; + unsigned output_state = 0, output_action = 0; + for (unsigned i = 0; i < {{{!truth_table_entries}}}; i++) { + if ((truth_table[i].mask & input_word) == truth_table[i].pattern) { + output_state |= truth_table[i].output_state; + output_action |= truth_table[i].output_action; + } + } + internal_state = output_state; + return output_action; + } + + void dispatch(unsigned task_id) { + if (task_id == IDLE) { + arch::Dispatcher::idle(); + } else if (task_id == NO_DISPATCH) { + return; + } else if (task_id >= sizeof(dispatch_table)/sizeof(*dispatch_table)) { + CALL_HOOK(FaultDetectedHook, LOGIC_ERRORdetected, 0, 0); + } else { + arch::Dispatcher::Dispatch(*dispatch_table[task_id]); + } + } + + void iret(unsigned task_id) { + if (task_id != NO_DISPATCH && task_id != IDLE) { + dispatch(task_id); + } + } + + private: + unsigned internal_state : {{{!get:logic.state_len}}}; + static Row truth_table[{{{!truth_table_entries}}}]; +}; + +SchedulerFSM fsm_engine({{{!initial_state}}}); +SchedulerFSM::Row SchedulerFSM::truth_table[] = {{{!truth_table}}}; + + +} +} -- GitLab