From 32f2a71876e406885f34b077513a895dbefdcefe Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Fri, 1 Apr 2022 16:28:07 +0000 Subject: [PATCH] Add copyregion support for mapping a frame into the VSpace. Add a "copyregion" object that supports a named page-aligned memory region where page frames can be mapped. A copyregion has a name used to construct the C symbol name and an optional size that specifies how large a window to create (default is one "small page"). Any specified size must be a multiple of the base page size (4096 on RISCV). Multiple regions can be created per component by using different names. Note there is no synchronization copyregion accesses (e.g. if used by multiple threads). A copy region is setup before any pre_init method is called; any attempt to use it before then is undefined. A copy region is implemented "under the covers" by creating a C array named who's pages are unmapped at startup to create a hole in the VSpace. Change-Id: I78c99441869860c55a80f8c1d93e3a31107af8d1 GitOrigin-RevId: 0dbaa9886d988ff622e8d96188023c0ec8440589 --- camkes/ast/__init__.py | 2 +- camkes/ast/objects.py | 21 ++++++++++++++---- camkes/parser/camkes.g | 5 ++++- camkes/parser/stage3.py | 19 ++++++++++++++++- camkes/templates/component.common.c | 33 +++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/camkes/ast/__init__.py b/camkes/ast/__init__.py index 4ab48ee6..4153f57b 100644 --- a/camkes/ast/__init__.py +++ b/camkes/ast/__init__.py @@ -21,7 +21,7 @@ from .location import SourceLocation from .objects import Assembly, Attribute, AttributeReference, Component, \ Composition, Configuration, Connection, ConnectionEnd, Connector, \ - Consumes, Dataport, DictLookup, Emits, Export, Group, Include, Instance, Interface, \ + Consumes, CopyRegion, Dataport, DictLookup, Emits, Export, Group, Include, Instance, Interface, \ Method, Mutex, Parameter, Procedure, Provides, Reference, Semaphore, \ BinarySemaphore, Setting, Uses, Struct, QueryObject from .traversal import SimpleTraversalContext, TraversalAction, \ diff --git a/camkes/ast/objects.py b/camkes/ast/objects.py index ea2f574f..47912086 100644 --- a/camkes/ast/objects.py +++ b/camkes/ast/objects.py @@ -609,17 +609,19 @@ def freeze(self): all(isinstance_fallback(x, "Semaphore") for x in s)) @ast_property("binary_semaphores", lambda b: isinstance(b, (list, tuple)) and all(isinstance_fallback(x, "BinarySemaphore") for x in b)) +@ast_property("copyregions", lambda c: isinstance(c, (list, tuple)) and + all(isinstance_fallback(x, "CopyRegion") for x in c)) @ast_property("composition", Composition) @ast_property("configuration", Configuration) class Component(MapLike): child_fields = ('attributes', 'includes', 'provides', 'uses', 'emits', - 'consumes', 'dataports', 'mutexes', 'semaphores', 'binary_semaphores', 'composition', - 'configuration') + 'consumes', 'dataports', 'mutexes', 'semaphores', 'binary_semaphores', 'copyregions', + 'composition', 'configuration') def __init__(self, name=None, includes=None, control=False, hardware=False, provides=None, uses=None, emits=None, consumes=None, dataports=None, - attributes=None, mutexes=None, semaphores=None, binary_semaphores=None, composition=None, - configuration=None, location=None): + attributes=None, mutexes=None, semaphores=None, binary_semaphores=None, copyregions=None, + composition=None, configuration=None, location=None): super(Component, self).__init__(location) self.name = name self.includes = list(includes or []) @@ -634,6 +636,7 @@ def __init__(self, name=None, includes=None, control=False, hardware=False, self.mutexes = list(mutexes or []) self.semaphores = list(semaphores or []) self.binary_semaphores = list(binary_semaphores or []) + self.copyregions = list(copyregions or []) if composition is not None: self.composition = composition else: @@ -655,6 +658,7 @@ def claim_children(self): [self.adopt(m) for m in self.mutexes] [self.adopt(s) for s in self.semaphores] [self.adopt(b) for b in self.binary_semaphores] + [self.adopt(b) for b in self.copyregions] if self.composition is not None: self.adopt(self.composition) if self.configuration is not None: @@ -777,6 +781,15 @@ def __init__(self, name, location=None): self.name = name +@ast_property("name", six.string_types) +@ast_property("size", lambda x: isinstance(x, six.integer_types) and x >= 0) +class CopyRegion(ASTObject): + def __init__(self, name, size, location=None): + super(CopyRegion, self).__init__(location) + self.name = name + self.size = size + + @ast_property("name", lambda x: x is None or isinstance(x, six.string_types)) @ast_property("from_type", lambda x: isinstance(x, six.string_types) and x in ('Dataport', 'Event', 'Procedure')) diff --git a/camkes/parser/camkes.g b/camkes/parser/camkes.g index e51b838c..f6074bcb 100644 --- a/camkes/parser/camkes.g +++ b/camkes/parser/camkes.g @@ -66,6 +66,7 @@ ID: '[a-zA-Z_]\w*' REFIN: 'refin'; SEMAPHORE: 'semaphore'; BINARY_SEMAPHORE: 'binary_semaphore'; + COPYREGION: 'copyregion'; SIGNED: 'signed'; STRUCT: 'struct'; STRING: 'string'; @@ -98,7 +99,7 @@ attribute_decl: attribute_parameter ('=' item)? ; component_decl: COMPONENT id? component_defn; component_defn: '\{' (attribute | consumes | control | dataport | emits | hardware | include | mutex | provides | semaphore | binary_semaphore | - uses)* + copyregion | uses)* ((composition_sing configuration_sing?) | configuration_sing composition_sing)? '\}'; component_ref: reference | component_defn; @@ -116,6 +117,8 @@ mutex: HAS MUTEX id ';'; provides: PROVIDES reference id ';'; semaphore: HAS SEMAPHORE id ';'; binary_semaphore: HAS BINARY_SEMAPHORE id ';'; +copyregion_size: '\(' numeric_expr '\)'; +copyregion: HAS COPYREGION id copyregion_size? ';'; uses: maybe? USES reference id ';'; maybe: MAYBE; diff --git a/camkes/parser/stage3.py b/camkes/parser/stage3.py index 35df4560..59177dae 100644 --- a/camkes/parser/stage3.py +++ b/camkes/parser/stage3.py @@ -27,7 +27,7 @@ from camkes.ast import Assembly, Attribute, AttributeReference, Component, \ Composition, Configuration, Connection, ConnectionEnd, Connector, \ - Consumes, Dataport, DictLookup, Emits, Export, Group, Include, Instance, Interface, \ + Consumes, CopyRegion, Dataport, DictLookup, Emits, Export, Group, Include, Instance, Interface, \ LiftedAST, Method, Mutex, normalise_type, Parameter, Procedure, Provides, \ Reference, Semaphore, BinarySemaphore, QueryObject, Setting, SourceLocation, Uses, Struct from .base import Parser @@ -240,6 +240,7 @@ def _lift_component_decl(location, *args): attributes=component_defn.attributes, mutexes=component_defn.mutexes, semaphores=component_defn.semaphores, binary_semaphores=component_defn.binary_semaphores, + copyregions=component_defn.copyregions, composition=component_defn.composition, configuration=component_defn.configuration, location=location) @@ -263,6 +264,7 @@ def _lift_component_defn(location, *args): mutexes=[x for x in args if isinstance(x, Mutex)], semaphores=[x for x in args if isinstance(x, Semaphore)], binary_semaphores=[x for x in args if isinstance(x, BinarySemaphore)], + copyregions=[x for x in args if isinstance(x, CopyRegion)], composition=composition, configuration=configuration, location=location) @@ -688,6 +690,19 @@ def _lift_binary_semaphore(location, id): return BinarySemaphore(id, location) +def _lift_copyregion(location, *args): + if len(args) == 2: + name, size = args + return CopyRegion(name, size, location) + else: + # XXX use pagesize? + return CopyRegion(args[0], 4096, location) + + +def _lift_copyregion_size(location, arg): + return arg + + def _lift_setting(location, id, id2, item): item = strip_quotes(item) return Setting(id, id2, item, location) @@ -838,6 +853,8 @@ def _collapse(location, content): 'reference': _lift_reference, 'semaphore': _lift_semaphore, 'binary_semaphore': _lift_binary_semaphore, + 'copyregion': _lift_copyregion, + 'copyregion_size': _lift_copyregion_size, 'setting': _lift_setting, 'signed_char': _lift_signed_char, 'signed_int': _lift_signed_int, diff --git a/camkes/templates/component.common.c b/camkes/templates/component.common.c index e104e211..515cc99b 100644 --- a/camkes/templates/component.common.c +++ b/camkes/templates/component.common.c @@ -80,6 +80,26 @@ const char *get_instance_name(void) { return name; } +/*- set copy_region_caps = [] -*/ +/*- for c in me.type.copyregions -*/ + /*# Setup any per-component copy regions. The pre_init (or similar) routine + * is expected to unmap the pages using copy_region_caps. This leaves each + * COPY_REGION as a "hole" in the component's VSpace where it can map page + * frames. Users are required to implement any necessary synchronization. #*/ + /*- set copy_region_size = c.size -*/ + /*- set page_size = macros.get_page_size(copy_region_size, options.architecture) -*/ + /*- if page_size == 0 -*/ + /*? raise(TemplateError('Invalid %s copy_region size %d: must be a multiple of %d' % (c.name, copy_region_size, 4096))) ?*/ + /*- endif -*/ + /*- set page_size_bits = int(math.log(page_size, 2)) -*/ + /*# set copy_region_symbol = '%s_COPY_REGION' % c.name #*/ + /*- set copy_region_symbol = c.name -*/ + char /*? copy_region_symbol ?*/[ROUND_UP_UNSAFE(/*? copy_region_size ?*/, /*? page_size ?*/)] + ALIGN(/*? page_size ?*/) + SECTION("align_/*? page_size_bits ?*/bit"); + /*? register_shared_variable('%s_copy_region_%s' % (me.name, c.name), copy_region_symbol, copy_region_size, frame_size=page_size, perm='RW', with_mapping_caps=copy_region_caps) ?*/ +/*- endfor -*/ + /*- set cnode_size = configuration[me.address_space].get('cnode_size_bits') -*/ /*- if cnode_size -*/ /*- if isinstance(cnode_size, six.string_types) -*/ @@ -791,6 +811,19 @@ static int post_main(int thread_id) { ZF_LOGF_IF(tls_regions[i] == NULL, "Failed to create tls"); } } + /*- for cap in copy_region_caps -*/ + /*# Would otherwise put this in pre_init... #*/ + ret = seL4_ARCH_Page_Unmap(/*? cap ?*/); + ERR_IF(ret != 0, camkes_error, ((camkes_error_t){ + .type = CE_SYSCALL_FAILED, + .instance = "/*? me.name ?*/", + .description = "failed to unmap copy_region frame /*? cap ?*/", + .syscall = 0, /* XXX no ARCHPageUnmap */ + .error = ret, + }), ({ + return -1; + })); + /*- endfor -*/ ret = component_control_main(); sync_sem_bare_wait(/*? interface_init_ep ?*/, &interface_init_lock); return ret;