Skip to content

Commit

Permalink
Update kraft for EPT.
Browse files Browse the repository at this point in the history
Signed-off-by: Sebastian Rauch <[email protected]>
  • Loading branch information
UniformlyR4ndom committed Dec 13, 2021
1 parent 064f674 commit 35f7147
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 7 deletions.
77 changes: 77 additions & 0 deletions kraft/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@


class Application(Component):
# path of file where the names of functions called via gate are collected
VMEPT_FUNC_LIST_PATH = "/tmp/flexos_vmept_rpc_id_data"

# name and path of auto-generated header file containing the function addresses
VMEPT_ADDR_TABLE_NAME = "vmept_addr_table"

# where to put auto-generated header files (relative to the unikraft build directory)
VMEPT_AUTOGEN_INCLUDE_PATH = "lib/flexos-core/include/flexos/impl"

_type = ComponentType.APP

_config = None
Expand Down Expand Up @@ -605,6 +614,29 @@ def fetch(ctx, self, verbose=False):

return self.make(extra, verbose)

# generate a header containing an array with the addresses of functions called via EPT-gate
def vmept_gen_address_table_header(self, func_names, header_name, addr_map = {}, write_to_file = True):
include_guard = "%s_H" % header_name.upper()
header_code = "#ifndef %s\n" % include_guard
header_code += "#define %s\n\n" % include_guard
header_code += 'static const void* flexos_vmept_addr_table[] __attribute__((section (".rodata"))) = {\n'
num_entries = len(func_names)
i = 0
for fname in func_names:
i += 1
sep = "," if i < num_entries else " "
addr = addr_map[fname] if fname in addr_map else 0
header_code += "\t(void*) 0x%016x%s /* %s */\n" % (addr, sep, fname)
header_code += "};\n\n"
header_code += "#endif /* %s */" % include_guard
if write_to_file:
addr_table_path = os.path.join(self.unikraft.localdir, self.VMEPT_AUTOGEN_INCLUDE_PATH)
addr_table_path = os.path.join(addr_table_path, self.VMEPT_ADDR_TABLE_NAME + ".h")
addr_table_file = open(addr_table_path, "w")
addr_table_file.write(header_code)
addr_table_file.close()
return header_code

@click.pass_context
def compartmentalize(ctx, self):
self.find_files()
Expand Down Expand Up @@ -792,6 +824,12 @@ def simple_replace(template_path, path, marker, shstack_enabled=True):
cmd = ["diff", "-urNp", backup_src, filep]
subprocess.call(cmd, stdout=fulldiff, stderr=subprocess.STDOUT)

is_ept = type(self.compartments[0].mechanism.driver) == VMEPTDriver
if is_ept and not os.path.isfile(self.VMEPT_FUNC_LIST_PATH):
# make sure this file exists
rpc_id_file = open(self.VMEPT_FUNC_LIST_PATH, "w")
rpc_id_file.close()

# now do library-specific rewrites
for lib in self.libraries:
# first add per-library linker scripts
Expand All @@ -810,6 +848,13 @@ def simple_replace(template_path, path, marker, shstack_enabled=True):
str(lib.compartment.number))
gr_rule = ""

ept_rpc_id_prefix = "_RPC_ID_" if is_ept else ""
if (is_ept):
rpc_id_gen_template = get_sec_rule("rpc_id_gen.cocci.in")
rpc_id_gen_template = rpc_id_gen_template.replace("{{ filename }}",
"'" + self.VMEPT_FUNC_LIST_PATH + "'")
gr_rule = rpc_id_gen_template + "\n"

def gr_gen_rule(dest_name, dest_comp):
gr_rule = str(gr_rule_template)
name = dest_name
Expand All @@ -825,6 +870,9 @@ def gr_gen_rule(dest_name, dest_comp):
if dest_comp == lib.compartment:
# FIXME magic value, put somewhere
gr_gate = "flexos_nop_gate"
gr_rule = gr_rule.replace("{{ ept_id_prefix }}", "")
else:
gr_rule = gr_rule.replace("{{ ept_id_prefix }}", ept_rpc_id_prefix)

gr_rule = gr_rule.replace("{{ gate }}", gr_gate)
gr_rule = gr_rule.replace("{{ gate_r }}", gr_gate + "_r")
Expand Down Expand Up @@ -868,6 +916,7 @@ def cb_gen_rule(dest_name, dest_comp):
# with future upstream releases of Coccinelle, talking about it with Julia
whitelisted_libs = ["libvfscore", "libuknetdev", "newlib",
"libuksched", "libuksignal", "libukboot"]

for dest_lib in self.libraries:
if (not dest_lib.compartment.default) and (dest_lib.name != lib.name):
# this library is not in the default compartment, add a specific rule
Expand Down Expand Up @@ -920,6 +969,34 @@ def cb_gen_rule(dest_name, dest_comp):

coccinelle_rewrite(lib, rule_file, fulldiff)

# generate a header with macros defining IDs for all
# functions given by function_names
def vmept_gen_rpc_id_macro_header(function_names, header_name):
include_guard = "%s_H" % header_name.upper()
header_code = "#ifndef %s\n" % include_guard
header_code += "#define %s\n\n" % include_guard
rpc_id = 0
for fname in function_names:
header_code += "#define %s%s %d\n" % (ept_rpc_id_prefix, fname, rpc_id)
rpc_id += 1
header_code += "\n#define FLEXOS_VMEPT_RPCID_CNT %d\n\n" % rpc_id
header_code += "#endif /* %s */" % include_guard
return header_code

if (is_ept):
rpc_id_file = open(self.VMEPT_FUNC_LIST_PATH, "r")
fnames = list(map(str.strip, rpc_id_file.readlines()))
rpc_id_file.close()
id_header_name = "vmept_rpc_id"
addr_table_name = "flexos_%s" % self.VMEPT_ADDR_TABLE_NAME
id_header_code = vmept_gen_rpc_id_macro_header(fnames, id_header_name)
addr_table_code = self.vmept_gen_address_table_header(fnames, addr_table_name, write_to_file = True)
id_header_path = os.path.join(self.unikraft.localdir, self.VMEPT_AUTOGEN_INCLUDE_PATH)
id_header_path = os.path.join(id_header_path, id_header_name + ".h")
id_header_file = open(id_header_path, "w")
id_header_file.write(id_header_code)
id_header_file.close()

logger.info("Full diff of rewritings: %s" % fulldifff)
fulldiff.close()

Expand Down
59 changes: 58 additions & 1 deletion kraft/cmd/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,25 @@ def simple_replace(template_path, marker):
if lib.name.startswith("app"):
appcomp = lib.compartment

# get VMEPT config options
max_threads_shift = 8 # max hreads is (1 << max_threads_shift)
with open(os.path.join(app.localdir, ".config")) as conf:
conf_data = conf.read()
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_256=y' in conf_data:
max_threads_shift = 8
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_128=y' in conf_data:
max_threads_shift = 7
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_64=y' in conf_data:
max_threads_shift = 6
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_32=y' in conf_data:
max_threads_shift = 5
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_16=y' in conf_data:
max_threads_shift = 4
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_8=y' in conf_data:
max_threads_shift = 3
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_4=y' in conf_data:
max_threads_shift = 2

i = 0
logger.info("Building with VM/EPT: " + str(no_ept) + " images to build.")
for comp in app.compartments:
Expand All @@ -92,7 +111,8 @@ def simple_replace(template_path, marker):
# edit build args
extra_args = ["CFLAGS_EXTRA=-DFLEXOS_VMEPT_COMP_ID=" + str(i)
+ " -DFLEXOS_VMEPT_COMP_COUNT=" + str(no_ept)
+ " -DFLEXOS_VMEPT_APPCOMP=" + str(appcomp.number)]
+ " -DFLEXOS_VMEPT_APPCOMP=" + str(appcomp.number)
+ " -DFLEXOS_VMEPT_MAX_THREADS_SHIFT=" + str(max_threads_shift)]
if fast:
extra_args.insert(0, "-j")

Expand All @@ -111,6 +131,43 @@ def simple_replace(template_path, marker):
"of the make command (code " + str(return_code) + ")")
return

for target in app.binaries:
# insert correct addresses
funcname_file = open(Application.VMEPT_FUNC_LIST_PATH, "r")
fnames = list(map(str.strip, funcname_file.readlines()))
funcname_file.close()

addr_map = {}
for fname in fnames:
addr_map[fname] = 0

readelf = subprocess.Popen(['readelf', '-sW', target.binary_debug], stdout = subprocess.PIPE)
output = subprocess.check_output(['awk', '{if ($4 == "FUNC") { print $2,$8 } }'], stdin = readelf.stdout).decode()
readelf.wait()

raw_lines = output.splitlines()

entries = []
for line in raw_lines:
fields = line.split()
address = int(fields[0], 16)
name = fields[1]
if name in addr_map:
addr_map[name] = address

patched_code = app.vmept_gen_address_table_header(fnames,
Application.VMEPT_ADDR_TABLE_NAME, addr_map, write_to_file = True)

# build again
return_code = make_progressbar(app.make_raw(verbose=verbose,
extra=extra_args))

if (return_code > 0):
# there was probably an error
logger.error("Aborting build due to probable error during execution "
"of the make command (code " + str(return_code) + ")")
return

# secure image (so that it doesn't get overwritten)
for target in app.binaries:
os.rename(target.binary, target.binary + ".comp" + str(i))
Expand Down
4 changes: 3 additions & 1 deletion kraft/sec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ def coccinelle_rewrite(lib, rule_file, fulldiff):

with open(log, 'wb') as logf:
try:
cmd1 = ["spatch", "-j", "6", "-in_place", "-sp_file", rule_file, file]
# we can't use parallel jobs when building for EPT since this leads to
# @finalize scripts being called too early
cmd1 = ["spatch", "-in_place", "-sp_file", rule_file, file]
cmd2 = ["diff", "-urNp", backup_src, file]
logf.write(bytes("$ " + " ".join(cmd1) + "\n", 'utf-8'))
logf.flush()
Expand Down
2 changes: 1 addition & 1 deletion kraft/sec/replacements/ukboot_init_sections.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
(void *) __uk_image_symbol(_ecomp{{ comp_nr }}));
PROTECT_SECTION("bss_comp{{ comp_nr }}", {{ comp_nr }}, (void *) __uk_image_symbol(_bss_comp{{ comp_nr }}),
(void *) __uk_image_symbol(_ebss_comp{{ comp_nr }}));
ASSIGN_HEAP("comp{{ comp_nr }}", {{ comp_nr }} /* key */, 1000 /* size */, flexos_comp{{ comp_nr }}_alloc);
ASSIGN_HEAP("comp{{ comp_nr }}", {{ comp_nr }} /* key */, CONFIG_LIBFLEXOS_COMP_HEAP_SIZE /* size */, flexos_comp{{ comp_nr }}_alloc);
60 changes: 56 additions & 4 deletions kraft/sec/rules/gatereplacer.cocci.in
Original file line number Diff line number Diff line change
@@ -1,13 +1,65 @@
@gatereplacer_return0_{{ rule_nr }}@
identifier func;
expression ret, lname;
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
@@
- flexos_gate_r({{ lib_dest_name }}, ret, func);
+ {{ gate_r }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, ret, func_id);

@script:python@
func_name << gatereplacer_return0_{{ rule_nr }}.func;
@@
fname = str(func_name)
if fname not in entries:
entries[fname] = entry_cnt
entry_cnt += 1

@gatereplacer_return{{ rule_nr }}@
identifier func;
expression list EL;
expression ret, lname;
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
@@
- flexos_gate_r({{ lib_dest_name }}, ret, func, EL);
+ {{ gate_r }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, ret, func_id, EL);

@script:python@
func_name << gatereplacer_return{{ rule_nr }}.func;
@@
- flexos_gate_r({{ lib_dest_name }}, ret, EL);
+ {{ gate_r }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, ret, EL);
fname = str(func_name)
if fname not in entries:
entries[fname] = entry_cnt
entry_cnt += 1

@gatereplacer_noreturn0_{{ rule_nr }}@
identifier func;
expression lname;
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
@@
- flexos_gate({{ lib_dest_name }}, func);
+ {{ gate }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, func_id);

@script:python@
func_name << gatereplacer_noreturn0_{{ rule_nr }}.func;
@@
fname = str(func_name)
if fname not in entries:
entries[fname] = entry_cnt
entry_cnt += 1

@gatereplacer_noreturn{{ rule_nr }}@
identifier func;
expression list EL;
expression lname;
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
@@
- flexos_gate({{ lib_dest_name }}, func, EL);
+ {{ gate }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, func_id, EL);

@script:python@
func_name << gatereplacer_noreturn{{ rule_nr }}.func;
@@
- flexos_gate({{ lib_dest_name }}, EL);
+ {{ gate }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, EL);
fname = str(func_name)
if fname not in entries:
entries[fname] = entry_cnt
entry_cnt += 1

0 comments on commit 35f7147

Please sign in to comment.