Skip to content

Commit 35f7147

Browse files
Update kraft for EPT.
Signed-off-by: Sebastian Rauch <s.rauch94@gmail.com>
1 parent 064f674 commit 35f7147

5 files changed

Lines changed: 195 additions & 7 deletions

File tree

kraft/app/app.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@
9191

9292

9393
class Application(Component):
94+
# path of file where the names of functions called via gate are collected
95+
VMEPT_FUNC_LIST_PATH = "/tmp/flexos_vmept_rpc_id_data"
96+
97+
# name and path of auto-generated header file containing the function addresses
98+
VMEPT_ADDR_TABLE_NAME = "vmept_addr_table"
99+
100+
# where to put auto-generated header files (relative to the unikraft build directory)
101+
VMEPT_AUTOGEN_INCLUDE_PATH = "lib/flexos-core/include/flexos/impl"
102+
94103
_type = ComponentType.APP
95104

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

606615
return self.make(extra, verbose)
607616

617+
# generate a header containing an array with the addresses of functions called via EPT-gate
618+
def vmept_gen_address_table_header(self, func_names, header_name, addr_map = {}, write_to_file = True):
619+
include_guard = "%s_H" % header_name.upper()
620+
header_code = "#ifndef %s\n" % include_guard
621+
header_code += "#define %s\n\n" % include_guard
622+
header_code += 'static const void* flexos_vmept_addr_table[] __attribute__((section (".rodata"))) = {\n'
623+
num_entries = len(func_names)
624+
i = 0
625+
for fname in func_names:
626+
i += 1
627+
sep = "," if i < num_entries else " "
628+
addr = addr_map[fname] if fname in addr_map else 0
629+
header_code += "\t(void*) 0x%016x%s /* %s */\n" % (addr, sep, fname)
630+
header_code += "};\n\n"
631+
header_code += "#endif /* %s */" % include_guard
632+
if write_to_file:
633+
addr_table_path = os.path.join(self.unikraft.localdir, self.VMEPT_AUTOGEN_INCLUDE_PATH)
634+
addr_table_path = os.path.join(addr_table_path, self.VMEPT_ADDR_TABLE_NAME + ".h")
635+
addr_table_file = open(addr_table_path, "w")
636+
addr_table_file.write(header_code)
637+
addr_table_file.close()
638+
return header_code
639+
608640
@click.pass_context
609641
def compartmentalize(ctx, self):
610642
self.find_files()
@@ -792,6 +824,12 @@ def simple_replace(template_path, path, marker, shstack_enabled=True):
792824
cmd = ["diff", "-urNp", backup_src, filep]
793825
subprocess.call(cmd, stdout=fulldiff, stderr=subprocess.STDOUT)
794826

827+
is_ept = type(self.compartments[0].mechanism.driver) == VMEPTDriver
828+
if is_ept and not os.path.isfile(self.VMEPT_FUNC_LIST_PATH):
829+
# make sure this file exists
830+
rpc_id_file = open(self.VMEPT_FUNC_LIST_PATH, "w")
831+
rpc_id_file.close()
832+
795833
# now do library-specific rewrites
796834
for lib in self.libraries:
797835
# first add per-library linker scripts
@@ -810,6 +848,13 @@ def simple_replace(template_path, path, marker, shstack_enabled=True):
810848
str(lib.compartment.number))
811849
gr_rule = ""
812850

851+
ept_rpc_id_prefix = "_RPC_ID_" if is_ept else ""
852+
if (is_ept):
853+
rpc_id_gen_template = get_sec_rule("rpc_id_gen.cocci.in")
854+
rpc_id_gen_template = rpc_id_gen_template.replace("{{ filename }}",
855+
"'" + self.VMEPT_FUNC_LIST_PATH + "'")
856+
gr_rule = rpc_id_gen_template + "\n"
857+
813858
def gr_gen_rule(dest_name, dest_comp):
814859
gr_rule = str(gr_rule_template)
815860
name = dest_name
@@ -825,6 +870,9 @@ def gr_gen_rule(dest_name, dest_comp):
825870
if dest_comp == lib.compartment:
826871
# FIXME magic value, put somewhere
827872
gr_gate = "flexos_nop_gate"
873+
gr_rule = gr_rule.replace("{{ ept_id_prefix }}", "")
874+
else:
875+
gr_rule = gr_rule.replace("{{ ept_id_prefix }}", ept_rpc_id_prefix)
828876

829877
gr_rule = gr_rule.replace("{{ gate }}", gr_gate)
830878
gr_rule = gr_rule.replace("{{ gate_r }}", gr_gate + "_r")
@@ -868,6 +916,7 @@ def cb_gen_rule(dest_name, dest_comp):
868916
# with future upstream releases of Coccinelle, talking about it with Julia
869917
whitelisted_libs = ["libvfscore", "libuknetdev", "newlib",
870918
"libuksched", "libuksignal", "libukboot"]
919+
871920
for dest_lib in self.libraries:
872921
if (not dest_lib.compartment.default) and (dest_lib.name != lib.name):
873922
# this library is not in the default compartment, add a specific rule
@@ -920,6 +969,34 @@ def cb_gen_rule(dest_name, dest_comp):
920969

921970
coccinelle_rewrite(lib, rule_file, fulldiff)
922971

972+
# generate a header with macros defining IDs for all
973+
# functions given by function_names
974+
def vmept_gen_rpc_id_macro_header(function_names, header_name):
975+
include_guard = "%s_H" % header_name.upper()
976+
header_code = "#ifndef %s\n" % include_guard
977+
header_code += "#define %s\n\n" % include_guard
978+
rpc_id = 0
979+
for fname in function_names:
980+
header_code += "#define %s%s %d\n" % (ept_rpc_id_prefix, fname, rpc_id)
981+
rpc_id += 1
982+
header_code += "\n#define FLEXOS_VMEPT_RPCID_CNT %d\n\n" % rpc_id
983+
header_code += "#endif /* %s */" % include_guard
984+
return header_code
985+
986+
if (is_ept):
987+
rpc_id_file = open(self.VMEPT_FUNC_LIST_PATH, "r")
988+
fnames = list(map(str.strip, rpc_id_file.readlines()))
989+
rpc_id_file.close()
990+
id_header_name = "vmept_rpc_id"
991+
addr_table_name = "flexos_%s" % self.VMEPT_ADDR_TABLE_NAME
992+
id_header_code = vmept_gen_rpc_id_macro_header(fnames, id_header_name)
993+
addr_table_code = self.vmept_gen_address_table_header(fnames, addr_table_name, write_to_file = True)
994+
id_header_path = os.path.join(self.unikraft.localdir, self.VMEPT_AUTOGEN_INCLUDE_PATH)
995+
id_header_path = os.path.join(id_header_path, id_header_name + ".h")
996+
id_header_file = open(id_header_path, "w")
997+
id_header_file.write(id_header_code)
998+
id_header_file.close()
999+
9231000
logger.info("Full diff of rewritings: %s" % fulldifff)
9241001
fulldiff.close()
9251002

kraft/cmd/build.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,25 @@ def simple_replace(template_path, marker):
8484
if lib.name.startswith("app"):
8585
appcomp = lib.compartment
8686

87+
# get VMEPT config options
88+
max_threads_shift = 8 # max hreads is (1 << max_threads_shift)
89+
with open(os.path.join(app.localdir, ".config")) as conf:
90+
conf_data = conf.read()
91+
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_256=y' in conf_data:
92+
max_threads_shift = 8
93+
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_128=y' in conf_data:
94+
max_threads_shift = 7
95+
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_64=y' in conf_data:
96+
max_threads_shift = 6
97+
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_32=y' in conf_data:
98+
max_threads_shift = 5
99+
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_16=y' in conf_data:
100+
max_threads_shift = 4
101+
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_8=y' in conf_data:
102+
max_threads_shift = 3
103+
if 'CONFIG_LIBFLEXOS_VMEPT_MAX_THREADS_4=y' in conf_data:
104+
max_threads_shift = 2
105+
87106
i = 0
88107
logger.info("Building with VM/EPT: " + str(no_ept) + " images to build.")
89108
for comp in app.compartments:
@@ -92,7 +111,8 @@ def simple_replace(template_path, marker):
92111
# edit build args
93112
extra_args = ["CFLAGS_EXTRA=-DFLEXOS_VMEPT_COMP_ID=" + str(i)
94113
+ " -DFLEXOS_VMEPT_COMP_COUNT=" + str(no_ept)
95-
+ " -DFLEXOS_VMEPT_APPCOMP=" + str(appcomp.number)]
114+
+ " -DFLEXOS_VMEPT_APPCOMP=" + str(appcomp.number)
115+
+ " -DFLEXOS_VMEPT_MAX_THREADS_SHIFT=" + str(max_threads_shift)]
96116
if fast:
97117
extra_args.insert(0, "-j")
98118

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

134+
for target in app.binaries:
135+
# insert correct addresses
136+
funcname_file = open(Application.VMEPT_FUNC_LIST_PATH, "r")
137+
fnames = list(map(str.strip, funcname_file.readlines()))
138+
funcname_file.close()
139+
140+
addr_map = {}
141+
for fname in fnames:
142+
addr_map[fname] = 0
143+
144+
readelf = subprocess.Popen(['readelf', '-sW', target.binary_debug], stdout = subprocess.PIPE)
145+
output = subprocess.check_output(['awk', '{if ($4 == "FUNC") { print $2,$8 } }'], stdin = readelf.stdout).decode()
146+
readelf.wait()
147+
148+
raw_lines = output.splitlines()
149+
150+
entries = []
151+
for line in raw_lines:
152+
fields = line.split()
153+
address = int(fields[0], 16)
154+
name = fields[1]
155+
if name in addr_map:
156+
addr_map[name] = address
157+
158+
patched_code = app.vmept_gen_address_table_header(fnames,
159+
Application.VMEPT_ADDR_TABLE_NAME, addr_map, write_to_file = True)
160+
161+
# build again
162+
return_code = make_progressbar(app.make_raw(verbose=verbose,
163+
extra=extra_args))
164+
165+
if (return_code > 0):
166+
# there was probably an error
167+
logger.error("Aborting build due to probable error during execution "
168+
"of the make command (code " + str(return_code) + ")")
169+
return
170+
114171
# secure image (so that it doesn't get overwritten)
115172
for target in app.binaries:
116173
os.rename(target.binary, target.binary + ".comp" + str(i))

kraft/sec/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ def coccinelle_rewrite(lib, rule_file, fulldiff):
150150

151151
with open(log, 'wb') as logf:
152152
try:
153-
cmd1 = ["spatch", "-j", "6", "-in_place", "-sp_file", rule_file, file]
153+
# we can't use parallel jobs when building for EPT since this leads to
154+
# @finalize scripts being called too early
155+
cmd1 = ["spatch", "-in_place", "-sp_file", rule_file, file]
154156
cmd2 = ["diff", "-urNp", backup_src, file]
155157
logf.write(bytes("$ " + " ".join(cmd1) + "\n", 'utf-8'))
156158
logf.flush()

kraft/sec/replacements/ukboot_init_sections.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
(void *) __uk_image_symbol(_ecomp{{ comp_nr }}));
33
PROTECT_SECTION("bss_comp{{ comp_nr }}", {{ comp_nr }}, (void *) __uk_image_symbol(_bss_comp{{ comp_nr }}),
44
(void *) __uk_image_symbol(_ebss_comp{{ comp_nr }}));
5-
ASSIGN_HEAP("comp{{ comp_nr }}", {{ comp_nr }} /* key */, 1000 /* size */, flexos_comp{{ comp_nr }}_alloc);
5+
ASSIGN_HEAP("comp{{ comp_nr }}", {{ comp_nr }} /* key */, CONFIG_LIBFLEXOS_COMP_HEAP_SIZE /* size */, flexos_comp{{ comp_nr }}_alloc);
Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,65 @@
1+
@gatereplacer_return0_{{ rule_nr }}@
2+
identifier func;
3+
expression ret, lname;
4+
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
5+
@@
6+
- flexos_gate_r({{ lib_dest_name }}, ret, func);
7+
+ {{ gate_r }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, ret, func_id);
8+
9+
@script:python@
10+
func_name << gatereplacer_return0_{{ rule_nr }}.func;
11+
@@
12+
fname = str(func_name)
13+
if fname not in entries:
14+
entries[fname] = entry_cnt
15+
entry_cnt += 1
16+
117
@gatereplacer_return{{ rule_nr }}@
18+
identifier func;
219
expression list EL;
320
expression ret, lname;
21+
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
22+
@@
23+
- flexos_gate_r({{ lib_dest_name }}, ret, func, EL);
24+
+ {{ gate_r }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, ret, func_id, EL);
25+
26+
@script:python@
27+
func_name << gatereplacer_return{{ rule_nr }}.func;
428
@@
5-
- flexos_gate_r({{ lib_dest_name }}, ret, EL);
6-
+ {{ gate_r }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, ret, EL);
29+
fname = str(func_name)
30+
if fname not in entries:
31+
entries[fname] = entry_cnt
32+
entry_cnt += 1
33+
34+
@gatereplacer_noreturn0_{{ rule_nr }}@
35+
identifier func;
36+
expression lname;
37+
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
38+
@@
39+
- flexos_gate({{ lib_dest_name }}, func);
40+
+ {{ gate }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, func_id);
41+
42+
@script:python@
43+
func_name << gatereplacer_noreturn0_{{ rule_nr }}.func;
44+
@@
45+
fname = str(func_name)
46+
if fname not in entries:
47+
entries[fname] = entry_cnt
48+
entry_cnt += 1
749

850
@gatereplacer_noreturn{{ rule_nr }}@
51+
identifier func;
952
expression list EL;
1053
expression lname;
54+
fresh identifier func_id = "{{ ept_id_prefix }}" ## func;
55+
@@
56+
- flexos_gate({{ lib_dest_name }}, func, EL);
57+
+ {{ gate }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, func_id, EL);
58+
59+
@script:python@
60+
func_name << gatereplacer_noreturn{{ rule_nr }}.func;
1161
@@
12-
- flexos_gate({{ lib_dest_name }}, EL);
13-
+ {{ gate }}({{ comp_cur_nb }}, {{ comp_dest_nb }}, EL);
62+
fname = str(func_name)
63+
if fname not in entries:
64+
entries[fname] = entry_cnt
65+
entry_cnt += 1

0 commit comments

Comments
 (0)