1# CAmkES Manual 2 3<!-- 4 Copyright 2017, Data61 5 Commonwealth Scientific and Industrial Research Organisation (CSIRO) 6 ABN 41 687 119 230. 7 8 This software may be distributed and modified according to the terms of 9 the BSD 2-Clause license. Note that NO WARRANTY is provided. 10 See "LICENSE_BSD2.txt" for details. 11 12 @TAG(DATA61_BSD) 13 --> 14 15This document describes the structure and functionality of CAmkES, a platform 16for building componentised systems for embedded platforms. The documentation is 17broken into sections for users, template authors and developers. The 18[Usage](#usage) section is for people wanting to develop systems 19using CAmkES as a platform. The [Templating](#templating) section is 20for people wanting to write their own CAmkES templates and use more complex 21functionality. Finally the [Developers](#developers) section is for 22people wanting to modify the internals of CAmkES itself. If you are modifying 23the internals of CAmkES, it is recommended that you read the entirety of this 24documentation. Regardless of which section is most relevant for you, you should 25at least familiarise yourself with the [Terminology](#terminology) section. 26 27CAmkES' primary target platform is the 28[seL4 microkernel](http://sel4.systems/). The seL4 kernel and its functionality 29are not discussed in this document. It is assumed that the reader has read the 30seL4 programming references and is familiar with how this kernel operates and 31the mechanisms it provides. 32 33## Terminology 34 35Throughout this document some domain specific terminology is used that may have 36connotations outside CAmkES/component systems. To avoid confusion the meanings 37of these terms are made explicit below. 38 39**Abstract Syntax Tree (AST)** 40 41> An internal representation of the results of parsing a generalised grammar. 42 More thorough definitions of ASTs are provided 43 [elsewhere](https://en.wikipedia.org/wiki/Abstract_syntax_tree), but this is 44 noted here because the abbreviation 'AST' is used heavily in this 45 documentation. 46 47**Architecture Description Language (ADL)** 48 49> The CAmkES syntax for describing a component system. Most component platforms 50 have their own architecture description language for describing a set of 51 components and how they are wired together, but the term 'ADL' will be used 52 in this documentation to exclusively refer to the CAmkES input specification 53 language. 54 55**Assembly** 56 57> A top-level element that encapsulates a component system description. An 58 assembly can be thought of as a complete description of a full system. 59 A system must contain at least one assembly. A system with more than one 60 assembly is equivalent to a system with one assembly whose composition 61 and configuration sections are the concatenation of the composition and 62 configuration sections of each assembly. 63 64**Attribute** 65 66> Components and connectors can have extra data of an arbitrary type associated 67 with them. These are referred to as attributes. The description of a 68 component/connector must describe the name of the attribute and its type. The 69 value of the attribute itself is unspecified. It is assigned when the entity 70 is instantiated, and this assignment is referred to as a _setting_. Attributes 71 are generally used to specialise or differentiate a component at runtime. 72 The types of attributes can be constructed as a collection or _struct_ of 73 any of the basic CAmkES types: int, unsigned int, char, unsigned char, string. 74 It is possible to give an attribute a default value when it is declared. If 75 there are no settings for an attribute, the default setting will be used. If 76 an attribute is aliased to a different attribute that also has a default, 77 then the different attribute's default will override the original default. 78 79**Component** 80 81> A _type_ of functional entity. It is important to stress this distinction. 82 'Component' is used colloquially to refer to both types and instances, but in 83 a formal sense 'component' refers only to the type. To make this more 84 concrete, the statement `component foo f` describes a component _instance_ f, 85 whose _type_ is foo. 86 87**Composition** 88 89> A container for the component and connector instantiations that form a system. 90 This is essentially a syntactic element for delimiting sections in a 91 specification. It is contained by an assembly block, along with an optional 92 configuration. 93 94**Compound Component** 95 96> A component with a composition section, and optionally a configuration section. 97 98**Configuration** 99 100> A container for describing settings. This is a syntactic element to hold the 101 assignment of attributes for a given system. It is expressed inside an 102 assembly block. 103 104**Connection** 105 106> An instantiation of a connector. Connections connect two _instances_. Because 107 the instantiation of a connector does not really specialise the connector in 108 any particular way, it is easy to conflate the two. However, the sources make 109 important distinctions between connectors and connections. 110 111**Connector** 112 113> A _type_ of link between instances. The distinction between 'connector' and 114 'connection' is the same as that between 'component' and 'instance,' i.e. a 115 connection is an instantiation of a particular connector. 116 117**Consumes** 118 119> Event interfaces that are accepted by a component. If a component consumes a 120 particular event it means that it is expecting to receive and handle that 121 event. 122 123**Dataport** 124 125> Port interfaces that are used by a component. A component's dataports 126 are expected to be available to it at runtime as shared memory regions. 127 128**Direction** 129 130> The flow of a parameter of a procedure method. The only possible directions 131 are 'in' (caller to callee), 'out' (callee to caller), 'inout' 132 (bidirectional) and 'refin' (identical to 'in' except for the C backend where 133 this is optimised to pass-by-reference). 134 135**Emits** 136 137> Event interfaces that are expressed by a component. If a component emits a 138 given event it means that it produces events of this type. 139 140**Event** 141 142> An asynchronous signal interface of a component. Events are defined completely 143 by their identifier, a numerical value. It may be helpful to think of this 144 value as mapping to something like an interrupt number or a signal type, 145 although they do not necessarily represent hardware messages. 146 147**Exported Interface** 148 149> An interface of an internal instance that is presented under the name of an 150 identically typed interface in its containing component. The purpose of 151 exported interfaces is to expose a coherent outward-facing set of interfaces 152 from a component, while potentially implementing those interfaces within 153 nested components. 154 155**Instance** 156 157> An instantiation of a component type. Of course 'instance' can be used to 158 refer to an instantiation of any type, but when you see the term 'instance' in 159 the sources it is generally referring to the instantiation of a component. To 160 give a concrete example, in the statement `component foo f` f is an instance. 161 162**Interface** 163 164> An abstract exposed interaction point of a component. There could be a 165 distinction made here between type and instance of one of these interaction 166 points, but in practice this is not necessary and ambiguity rarely arises. The 167 subcategories of interface are _procedure_, _event_ and _port_. 168 169**Internal Instance** 170 171> A component instance declared inside a compound component's composition section. 172 173**Internal Connection** 174 175> A connection declared inside a compound component which connects two internal 176 instance interfaces. That is, any connection declared inside a compound 177 component. 178 179**Maybe** 180 181> Interfaces of components can be made optional using the `maybe` keyword. Optional 182 interfaces do not need to be connected to any other interfaces. C symbols associated 183 with optional interfaces (functions and dataport pointers) are declared as weak 184 symbols. If nothing is connected to an optional interface, its associated symbols 185 lack definitions. That is, functions and dataport pointers associated with unconnected 186 optional interfaces take the value `NULL` at runtime. 187 188**Method** 189 190> An item of a procedure. When targeting a conventional programming language, 191 methods usually map directly to generated functions. 192 193**Parameter** 194 195> A piece of data referenced by a procedure method. This can be thought of as an 196 argument to a function. 197 198**Port** 199 200> The interface type that represents shared memory semantics. 201 202**Procedure** 203 204> An interface with function call semantics. Procedures consist of a series of 205 methods that can be invoked independently. 206 207**Provides** 208 209> Procedure interfaces implemented by a component. When targeting a conventional 210 programming language this typically means that the component contains 211 functions that are implementations of each method in the procedures provided. 212 213**Setting** 214 215> An assignment of an attribute to a specific value. A setting does not specify 216 the type of the attribute, because this has already been described by the 217 attribute as specified in the component/connector description. 218 219**Struct** 220 221> A collection of named attribute fields that can be used as an attribute type 222 for a component _attribute_. 223 224**Type** 225 226> A procedure method's return type or parameter type. This information does not 227 include the direction of a parameter. An example type is something like 228 'string.' 229 230**Uses** 231 232> Procedure interfaces that are invoked by a component. When targeting a 233 conventional programming language this typically means that the component 234 contains calls to functions that are expected to implement each method in the 235 procedures used. 236 237**Virtual Interface** 238 239> An interface of a compound component that is not implemented by that 240 component, but is an alias for internal instance's interface. 241 242A concrete example: 243 244```camkes 245struct cat { 246 int paws; 247 string name; 248} 249 250procedure thing { 251 int func(in int x); 252} 253 254component foo { 255 control; 256 uses thing t1; 257 emits sig s1; 258 dataport buffer b1; 259 attribute cat kitty; 260} 261 262component bar { 263 provides thing t2; 264 consumes sig s2; 265 dataport buffer b2; 266} 267 268assembly { 269 composition { 270 component foo f; 271 component bar b; 272 273 connection RPC c1(from f.t1, to b.t2); 274 connection Notification c2(from f.s1, to b.s2); 275 connection SharedData c3(from f.b1, to b.b2); 276 } 277 configuration { 278 f.kitty = {"name": "meows", "paws": 4}; 279 } 280} 281``` 282 283* `thing` is a **procedure** 284* `int` is a **type** 285* `func` is a **method** 286* `in` is a **direction** 287* `x` is a **parameter** 288* `sig` is an **event** 289* `buffer` is a **port** 290* `foo` and `bar` are **component**s 291* `t1` is a **uses** 292* `s1` is a **emits** 293* `b1` and `b2` are **dataport**s 294* `t2` is a **provides** 295* `s2` is a **consumes** 296* `assembly { ... }` is an **assembly** 297* `composition { ... }` is a **composition** 298* `f` and `b` are **instance**s 299* `RPC`, `Notification` and `SharedData` are **connector**s 300* `c1`, `c2` and `c3` are **connection**s 301* `cat` is a **struct** 302* `kitty` is an **attribute** 303* `f.kitty` is a **setting** 304 305## Usage 306 307This section is targeted at people building systems on top of the CAmkES 308platform. It assumes a basic knowledge of C programming. 309 310### Dependencies 311 312Please see [the docsite](https://docs.sel4.systems/HostDependencies) for information about dependencies. 313 314To check you have the appropriate dependencies installed: 315 316```bash 317./tools/check_deps.py 318``` 319 320### Tutorial 321 322This section is aimed at getting you up and running with CAmkES applications 323and increase your familiarity with the CAmkES environment. We assume you are 324working in the CAmkES project repository for this. 325 326#### Running a Simple Example 327 328There's an example application under apps/simple that involves two components, 329echo and client, communicating over a single interface. 330 331![Simple system](imgs/echo.png) 332 333To build this example, from the top-level directory run: 334 335```bash 336mkdir build-kzm 337cd build-kzm 338../init-build.sh -DPLATFORM=kzm -DCROSS_COMPILER_PREFIX=arm-none-eabi- -DCAMKES_APP=simple -DSIMULATE=1 339ninja 340``` 341 342This produces an image images/simple-image-arm-imx31. To run this image in 343qemu: 344 345```bash 346./simulate 347``` 348 349You should see debugging output from the system initialisation, followed by: 350 351``` 352echo_int: 42 -> 42 353echo_float: 273421.437500 -> 273421.437500 354echo_double: 273421.427400 -> 273421.427400 355echo_mix: 273421.427400 -> 273421 356echo_string: "hello world" -> "hello world" 357echo_parameter: 123 -> 123 (returned = 123) 358increment_parameter: 100 -> 101 359After the client 360``` 361 362To understand what this example is doing, open the files 363apps/simple/components/Echo/src/echo.c and 364apps/simple/components/Client/src/client.c. The implementations of the echo 365functions are in echo.c and they are called from client.c. The function call 366itself happens over a seL4 endpoint. The connection between the two components 367is described in apps/simple/simple.camkes, and the functional interface that 368echo is providing is described in apps/simple/interfaces/Simple.idl4. 369 370If you want to run this example on IA32, repeat the above procedure with a new build 371directory, replacing the configuration line with the following: 372 373```bash 374../init-build.sh -DPLATFORM=ia32 -DCAMKES_APP=simple -DSIMULATE=1 375``` 376 377#### Creating An Application 378 379Let's create some simple hello world applications using the different interface 380types available in CAmkES. Create a new application directory with two component 381types: 382 383```bash 384mkdir -p apps/helloworld/components/Hello 385mkdir -p apps/helloworld/components/Client 386``` 387 388Functional interfaces, referred to as procedures, are made up of a set of 389methods. Define an interface that the components will communicate over and save 390this under apps/helloworld/interfaces/MyInterface.idl4: 391 392```camkes 393/* apps/helloworld/interfaces/MyInterface.idl4 */ 394 395procedure MyInterface { 396 void print(in string message); 397} 398``` 399 400This interface consists of a single method, print that takes an input parameter 401of type string. Note that, although we are planning to implement this component 402in C, interfaces are defined with abstract types that have equivalents in all 403target languages. In the case of C, string maps to `char*`. Each component 404needs a description of the interfaces it exposes or needs in so-called 405Architecture Description Language. Create these in 406apps/helloworld/components/Hello/Hello.camkes and 407apps/helloworld/components/Client/Client.camkes. 408 409```camkes 410/* apps/helloworld/components/Hello/Hello.camkes */ 411 412import "../../interfaces/MyInterface.idl4"; 413 414component Hello { 415 provides MyInterface inf; 416} 417 418/* apps/helloworld/components/Client/Client.camkes */ 419 420import "../../interfaces/MyInterface.idl4"; 421 422component Client { 423 control; 424 uses MyInterface iface; 425} 426``` 427 428Note that each component description needs to import the interface file we 429created above from apps/helloworld/interfaces. Import statements function 430similar to C's `#include`, in that they can be enclosed in double quotes and 431are relative to the source file, or enclosed in angle brackets and refer to a 432built-in file. The Hello component is to contain an implementation of 433MyInterface and the Client component will expect to be provided with an 434implementation of MyInterface. The `control` keyword indicates that Client is 435what is called an active component. This means it will contain a main function 436(prototyped as `run`) and have an active thread of control. 437 438Create a file to describe the instantiation and structure of the system at 439apps/helloworld/helloworld.camkes. 440 441```camkes 442/* apps/helloworld/helloworld.camkes */ 443 444import <std_connector.camkes>; 445import "components/Hello/Hello.camkes"; 446import "components/Client/Client.camkes"; 447 448assembly { 449 composition { 450 component Hello h; 451 component Client c; 452 connection seL4RPCCall conn(from c.iface, to h.inf); 453 } 454} 455``` 456 457This file begins with several import statements that reference other files. 458Hello.camkes and Client.camkes are the files we created above, while 459std_connector.camkes is a built-in file that defines the standard CAmkES 460connector types. The body of the system description instantiates each component 461once, `h` of type `Hello` and `c` of type `Client`. The components' interfaces 462are connected via a connection, `conn`, of type `seL4RPCCall`. 463 464Now for the implementation of the components. Create a single source file for 465Hello as apps/helloworld/components/Hello/src/hello.c: 466 467```c 468/* apps/helloworld/components/Hello/src/hello.c */ 469 470#include <camkes.h> 471#include <stdio.h> 472 473void inf__init(void) { 474} 475 476void inf_print(const char *message) { 477 printf("Client says: %s\n", message); 478} 479``` 480 481The header camkes.h is generated by the CAmkES build system and contains 482prototypes for functions related to MyInterface that this component needs to 483implement. Note that the actual implementations of interface functions are 484prefixed with the component-local name of the interface (inf from Hello.camkes 485above) and an underscore. The function `inf__init` is for this component to do 486any required initialisation. In the case of this example we have no 487initialisation to perform. 488 489Create a source file for Client as 490apps/helloworld/components/Client/src/client.c that calls these functions as if 491they are directly available to it: 492 493```c 494/* apps/helloworld/components/Client/src/client.c */ 495 496#include <camkes.h> 497 498int run(void) { 499 const char *s = "hello world"; 500 iface_print(s); 501 return 0; 502} 503``` 504 505The entry point of a CAmkES component is `run`. 506 507The final thing is to add some build system boiler plate to be able to build 508the system. 509Copy one of the `CMakeLists.txt` files from another application or create 510`apps/helloworld/CMakeLists.txt` from scratch: 511 512``` 513cmake_minimum_required(VERSION 3.7.2) 514 515project(helloworld C) 516 517DeclareCAmkESComponent(Client SOURCES components/Client/src/client.c) 518DeclareCAmkESComponent(Hello SOURCES components/Hello/src/hello.c) 519 520DeclareCAmkESRootserver(helloworld.camkes) 521``` 522 523You're now ready to compile and run this application, by entering the `CAMKES_APP` value in the cmake configuration GUI: 524 525```bash 526cd build-kzm 527cmake . -DCAMKES_APP=helloworld # set `helloworld` as CAMKES_APP 528ninja 529./simulate 530``` 531 532If all goes well you should see: 533 534``` 535Client says: hello world 536``` 537 538Congratulations, you've just made your first CAmkES application. 539 540#### Under the Hood 541 542We basically just wrote a verbose and roundabout Hello World example, so what 543benefit is CAmkES providing here? Note how the function call between the two 544components looks just like a normal function invocation in C, even though the 545two components are actually in different address spaces. During compilation 546so-called glue code is generated to connect the two components via a seL4 547endpoint and transparently pass the function invocation and return over this 548channel. The communication itself is abstracted in the ADL description in 549apps/helloworld/helloworld.camkes. The connection type we used was seL4RPCCall, but 550it is possible to use another connection type here without modifying the code of 551the components themselves. 552 553CAmkES provides some interface types for other modes of interaction than 554function calls. Events can be used for asynchronous communication and dataports 555for shared memory. 556 557#### An Example of Events 558 559Events are the CAmkES interface type for modelling asynchronous communication 560between components. Like procedures, events connect a single component to 561another single component, but the receiver of an event (called consumer in 562CAmkES parlance) has several ways of receiving the event. The following walks 563through an example demonstrating these. 564 565Create a new application directory with two components: 566 567```bash 568mkdir -p apps/helloevent/components/Emitter 569mkdir -p apps/helloevent/components/Consumer 570``` 571 572Events, unlike procedures, do not need to be defined in a separate IDL file. You 573can simply refer to the event type in your component ADL files and CAmkES will 574infer an event type. Create the following description for Emitter: 575 576```camkes 577/* apps/helloevent/components/Emitter/Emitter.camkes */ 578 579component Emitter { 580 control; 581 emits MyEvent e; 582} 583``` 584 585This description says Emitter is an active component (the control keyword) and 586it emits a single event called e of type MyEvent. Create some basic source code 587for the component that does nothing except emit the event itself: 588 589```c 590/* apps/helloevent/components/Emitter/src/main.c */ 591 592#include <camkes.h> 593 594int run(void) { 595 while (1) { 596 e_emit(); 597 } 598 return 0; 599} 600``` 601 602CAmkES provides an emit function to send the event. 603 604Now let's create a description of the Consumer that will handle this event: 605 606```camkes 607/* apps/helloevent/components/Consumer/Consumer.camkes */ 608 609component Consumer { 610 control; 611 consumes MyEvent s; 612} 613``` 614 615Note that this component consumes (handles) an event of the same type. Let's 616instantiate and connect these components together using another ADL file: 617 618```camkes 619/* apps/helloevent/helloevent.camkes */ 620 621import <std_connector.camkes>; 622import "components/Emitter/Emitter.camkes"; 623import "components/Consumer/Consumer.camkes"; 624 625assembly { 626 composition { 627 component Emitter source; 628 component Consumer sink; 629 connection seL4Notification channel(from source.e, to sink.s); 630 } 631} 632``` 633 634In this file, seL4Notification is a seL4 specific connector for transmitting 635asynchronous signals. The two instantiated components, source and sink are 636connected over the connection channel. 637 638As mentioned above, there are several ways for a component to receive an event. 639The consumer can register a callback function to be invoked when the event is 640received, they can call a blocking function that will return when the event is 641received or they can call a polling function that returns whether an event has 642arrived or not. Let's add some source code that uses all three: 643 644```c 645#include <camkes.h> 646#include <stdio.h> 647 648static void handler(void) { 649 static int fired = 0; 650 printf("Callback fired!\n"); 651 if (!fired) { 652 fired = 1; 653 s_reg_callback(&handler); 654 } 655} 656 657int run(void) { 658 printf("Registering callback...\n"); 659 s_reg_callback(&handler); 660 661 printf("Polling...\n"); 662 if (s_poll()) { 663 printf("We found an event!\n"); 664 } else { 665 printf("We didn't find an event\n"); 666 } 667 668 printf("Waiting...\n"); 669 s_wait(); 670 printf("Unblocked by an event!\n"); 671 672 return 0; 673} 674``` 675 676Note that we re-register the callback during the first execution of the handler. 677Callbacks are deregistered when invoked, so if you want the callback to fire 678again when another event arrives you need to explicitly re-register it. 679 680We now have everything we need to run this system. 681 682Create the appropriate `apps/helloevent/CMakeLists.txt` as for the previous example. Compile the system and 683run it with the simulate script as per the previous example. If all goes well you 684should see something like the following: 685 686``` 687Registering callback... 688Callback fired! 689Polling... 690We didn't find an event 691Waiting... 692Unblocked by an event! 693Callback fired! 694``` 695 696Whether you find an event during polling will be a matter of the schedule that 697seL4 uses to run the components. This covers all the functionality available 698when using events. One final point that may not be obvious from the example is 699that callbacks will always be fired in preference to polling/waiting. That is, 700if a component registers a callback and then waits on an event to arrive, the 701callback will be fired when the first instance of the event arrives and the wait 702will return when/if the second instance of the event arrives. 703 704#### An Example of Dataports 705 706Dataports are CAmkES' abstraction of shared memory. All 707components participating in a connection involving dataports get read/write 708access to the dataport by default. The default dataport type is 709`Buf`, which is implemented as a byte array in C of size `PAGE_SIZE`. 710Alternatively you can specify a user-defined type for the shared memory region. 711This example will demonstrate both. 712 713Create two components that will use a pair of dataports for communication: 714 715```bash 716mkdir -p apps/hellodataport/components/Ping 717mkdir -p apps/hellodataport/components/Pong 718``` 719 720Let's define a struct that will be used as one of the dataports: 721 722```c 723/* apps/hellodataport/include/porttype.h */ 724 725#ifndef _PORTTYPE_H_ 726#define _PORTTYPE_H_ 727 728typedef struct MyData { 729 char data[10]; 730 bool ready; 731} MyData_t; 732 733#endif 734``` 735 736Now let's create an ADL description of the Ping component: 737 738```camkes 739/* apps/hellodataport/components/Ping/Ping.camkes */ 740 741import "Porttype.idl4"; 742 743component Ping { 744 include "porttype.h"; 745 control; 746 dataport Buf d1; 747 dataport MyData_t d2; 748} 749``` 750 751Note that we need to include the C header in the ADL. CAmkES does not actually 752parse this header, but it needs to know to `#include` it whenever it references 753the `MyData_t` type. Add a similar description for Pong: 754 755```camkes 756/* apps/hellodataport/components/Pong/Pong.camkes */ 757 758import "Porttype.idl4"; 759 760component Pong { 761 include "porttype.h"; 762 control; 763 dataport Buf s1; 764 dataport MyData_t s2; 765} 766``` 767 768Now we'll create some basic code for each component to use the dataports: 769 770```c 771/* apps/components/Ping/src/main.c */ 772 773#include <camkes.h> 774#include <porttype.h> 775#include <stdio.h> 776#include <string.h> 777 778// index in d1 to use to signal pong 779#define D1_READY_IDX 20 780 781int run(void) { 782 char *hello = "hello"; 783 784 printf("Ping: sending %s...\n", hello); 785 strncpy((char*)d1, hello, D1_READY_IDX - 1); 786 787 d1_release(); // ensure the assignment below occurs after the strcpy above 788 ((*char)d1)[D1_READY_IDX] = 1; 789 790 /* Wait for Pong to reply. We can assume d2_data is 791 * zeroed on startup by seL4. 792 */ 793 while (!d2->ready) { 794 d2_acquire(); // ensure d2 is read from in each iteration 795 } 796 797 printf("Ping: received %s.\n", d2->data); 798 799 return 0; 800} 801``` 802 803```c 804/* apps/components/Pong/src/main.c */ 805 806#include <camkes.h> 807#include <porttype.h> 808#include <stdio.h> 809#include <string.h> 810 811// index in s1 to use to signal ping 812#define S1_READY_IDX 20 813 814int run(void) { 815 char *world = "world"; 816 817 /* Wait for Ping to message us. We can assume s1_data is 818 * zeroed on startup by seL4. 819 */ 820 while (!((char*)s1)[S1_READY_IDX]) { 821 s1_acquire(); // ensure s1 is read from in each iteration 822 } 823 824 printf("Pong: received %s\n", (char*)s1); 825 826 printf("Pong: sending %s...\n", world); 827 strcpy(s2->data, world); 828 829 s2_release(); // ensure the assignment below occurs after the strcpy above 830 s2->ready = true; 831 832 return 0; 833} 834``` 835 836Note the use of `*_acquire()` and `*_release()` functions. These are used to maintain 837coherency of shared memory between components. Call `*_acquire()` between multiple 838reads from a dataport, where the correct behaviour of the program depends on the 839contents of the dataport possibly changing between reads. Call `*_release()` between 840multiple writes to a dataport, where the correct behaviour of the program depends 841on writes preceding the `*_release()` in the program code being performed strictly 842before the writes following it. 843 844Typically, a real system would have a more complete communication protocol between 845the two components, but for the purposes of this example spinning until a byte 846changes is good enough. We're ready to connect all these sources together with a 847top-level ADL file: 848 849```camkes 850/* apps/hellodataport/hellodataport.camkes */ 851 852import <std_connector.camkes>; 853import "components/Ping/Ping.camkes"; 854import "components/Pong/Pong.camkes"; 855 856assembly { 857 composition { 858 component Ping ping; 859 component Pong pong; 860 861 connection seL4SharedData channel1(from ping.d1, to pong.s1); 862 connection seL4SharedData channel2(from ping.d2, to pong.s2); 863 } 864} 865``` 866 867Add the now familiar `apps/hellodataport/CMakeLists.txt`: 868 869```cmake 870cmake_minimum_required(VERSION 3.7.2) 871 872project(hellodataport C) 873 874# Interface library for our dataport 875add_library(MyData INTERFACE) 876target_include_directories(MyData INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include") 877 878DeclareCAmkESComponent(Ping SOURCES components/Ping/src/main.c LIBS MyData) 879DeclareCAmkESComponent(Pong SOURCES components/Pong/src/main.c LIBS MyData) 880 881DeclareCAmkESRootserver(hellodataport.camkes) 882 883``` 884We added an interface library containing the shared header file. The LIBS field in DeclareCAmkESComponent can be 885used to specify any argument that can be ordinarily given to CMake's `target_link_libraries()`. 886 887If you now compile and run the resulting 888image you should see some output like the following: 889 890``` 891Ping: sending hello... 892Pong: received hello 893Pong: sending world... 894Ping: received world. 895``` 896#### An example of structs and arrays for collections 897 898A struct can be defined with the `struct` keyword. The attributes that make 899up the struct are listed in a `type` `name` format (similar to C). 900 901Arrays are specified by appending the attribute name with a `[]`. The size of 902an array is set at code generation time when the setting for the attribute is 903specified. 904 905This is an example of a valid camkes specification. The corresponding C file 906is shown after. To find a size of an attribute array, the sizeof macro can be 907used as shown in the example. 908 909```camkes 910struct client_config { 911 string name; 912 int age; 913 int height; 914} 915struct cat { 916 int b[]; 917 int c; 918} 919 920component Client { 921 control; 922 attribute client_config config; 923 attribute cat array_in_struct; 924} 925 926assembly { 927 composition { 928 component Client client; 929 } 930 931 configuration { 932 client.config = {"name": "Zed","age": 39, "height": 34+4}; 933 client.array_in_struct = {"b": [3,4,5,6], "c": 4}; 934 } 935} 936 937``` 938 939```c 940#include <camkes.h> 941#include <stdio.h> 942 943int run(void) 944{ 945 printf("struct: %s: height plus age is %d\n", config.name, config.age + config.height); 946 printf("array_in_struct: array length: %d, first element %d\n", sizeof(array_in_struct.b) / sizeof(array_in_struct.b[0]), array_in_struct.b[0]); 947 return 0; 948} 949``` 950 951#### Tutorial Summary 952 953You should now have a reasonably comprehensive understanding of the basic 954connector functionality available in CAmkES. The other apps in the CAmkES 955project repository provide some more diverse system examples. 956 957### Overview 958 959The various parts that comprise CAmkES can be used in several ways, including 960executing a standalone tool as an end user or importing a Python module to 961perform programmatic operations. These two uses are broken up into the sections 962below. [Command Line Arguments](#command-line-arguments) describes how to invoke 963standalone CAmkES functionality, and [Modules](#modules) describes how to import 964and use the various functional units. Importing CAmkES functionality as a module 965is strictly more powerful than running the command line tool, but usage 966is more complicated. Note that these sections only describe external 967interaction with these artefacts. If you are interested in the internals of 968these you will need to refer to the [Developers](#developers) section. 969 970### Command Line Arguments 971 972This section discusses the standalone tool that is part of the CAmkES 973ecosystem. This can be run from the command line with a shell script wrapper 974that checks its dependencies: 975 976```bash 977camkes.sh args... 978``` 979 980The following command line arguments are available. 981 982**--cache**, **-c** 983**--cache-dir** 984 985> In a complicated system, the compilation itself can be quite time intensive. 986 CAmkES implements a template cache that reduces recompilation time within and 987 across builds. The --cache option enables it. 988 989**--cpp** 990**--nocpp** 991 992> Whether or not to run the C pre-processor over the ADL input specification 993 before processing it. The ADL input specification, strictly, is not C source 994 code, but sometimes it can be useful to have the ability to pre-process it as 995 if it was. The CAmkES ADL grammar is sufficiently similar to C that you are 996 unlikely to run into any problems in this respect. 997 998**-D**, **--debug** 999**-q**, **--quiet** 1000**-v**, **--verbose** 1001 1002> Set the level of information and error reporting emitted. The last one of 1003 these options encountered on the command line takes precedence. Note that 1004 there is no option to set the default verbosity (which is more than --quiet, 1005 but less than --verbose). The verbosity setting is applied globally during 1006 execution. For example, applying --debug to inspect a parsing problem in the 1007 runner will also generate debugging output from the lexing phase. 1008 1009**--default-priority** 1010 1011> Threads in a seL4 system are all configured with an initial priority. This 1012 can be tuned via attributes, but otherwise threads inherit a global default. 1013 This parameter allows you to set the global default. 1014 1015**--default-affinity** 1016 1017> Threads and sched-contexts in a seL4 system are all configured with an initial 1018 affinity. This can be tuned via attributes, but otherwise threads inherit a 1019 global default, which is CPU index 0. 1020 1021**--elf**, **-E** 1022 1023> Pass an ELF file that is to contribute to the final CapDL specification of a 1024 system. This parameter allows you to pass in the compiled ELF binary of one of 1025 your component instances. The CAmkES build system should take care of passing 1026 this option. 1027 1028**-f FILE**, **--file FILE** 1029 1030> This argument sets FILE as the input to parse. This argument is required and 1031 only a single input file is supported. 1032 1033**-h**, **--help** 1034 1035> Shows usage information and then exits. 1036 1037**-I PATH**, **--import-path** 1038 1039> CAmkES specifications can contain `import` statements that are either 1040 relative or builtin. Analogously to C pre-processor `#include` directives, 1041 builtin `import` statements use angle brackets, `import <foo.camkes>`. 1042 This option is similar to the C compiler flag, -I, and adds a directory to be 1043 searched for these builtin files. When resolving imports, directories will be 1044 searched in the order in which they are specified on the command line with 1045 the first match taking preference. Note, _unlike_ the C pre-processor this 1046 option _only_ affects searches for builtin imports. Relative imports are 1047 _always_ relative to the location they are included from. 1048 1049**--item**, **-T** 1050 1051> Specify the output you wish the runner to generate. The available options 1052 here are dependent on your input specification and it is best to look at 1053 examples to see what is expected following this option. 1054 1055**--largeframe** 1056 1057> Back large virtual address space regions with large frames when possible. On 1058 ARM and IA32 platforms, multiple frame sizes are supported for mapping 1059 physical memory into address spaces. It is more efficient to use a single 1060 large frame to cover a region than many small frames. This flag controls 1061 whether this promotion to large frames happens automatically. Note that this 1062 does not affect DMA pools, for which mappings are controlled by the 1063 --largeframe-dma option below. 1064 1065**--largeframe-dma** 1066 1067> Back components' DMA pools with large frames when possible. This works 1068 entirely independently to the --largeframe option. The reason for this 1069 separation is that large frame promotion of a DMA pool on ARM can be a 1070 little complicated to achieve. For more information, see 1071 [Efficient DMA](#efficient-dma). 1072 1073**--platform**, **-p** 1074 1075> The target output platform. This determines some aspects of the environment 1076 that the template being rendered is expected to function in. This option is 1077 only relevant to the runner. Valid platforms are "architecture-semantics", 1078 "autocorres", "CIMP", "GraphViz" and "seL4". The "GraphViz" option is for 1079 producing visual representations of a system and the "seL4" option is for 1080 producing binaries. All other platforms are verification frameworks. 1081 1082**--templates**, **-t** 1083 1084> You can use this option to add an extra directory to search for templates 1085 before the built-in location. This can allow you to extend the available 1086 templates or even override the built-in templates. 1087 1088**--version** 1089 1090> Print basic version information and then exit. 1091 1092The following options are all related to runtime optimisations within the 1093templates. Note that most of these are highly seL4 specific and would make no 1094sense in the context of another platform. 1095 1096**--frpc-lock-elision** 1097**--fno-rpc-lock-elision** 1098 1099> Locks are used within the seL4RPC connector templates to prevent threads 1100 interfering with each other's execution. When this option is enabled, CAmkES 1101 will determine when this lock is not required and remove it at compile-time. 1102 1103**--fcall-leave-reply-cap** 1104**--fno-call-leave-reply-cap** 1105 1106> The seL4RPCCall connector needs to save a so-called reply cap on the 1107 receiver's side to prevent accidental deletion in the presence of 1108 interference from other interfaces. In certain circumstances there is 1109 actually no risk of the reply cap being deleted. With this option enabled, 1110 CAmkES will detect these scenarios and operate on the reply cap in place to 1111 avoid extra syscalls. 1112 1113The following options are all related to verification of templates outputs. 1114 1115**--fprovide-tcb-caps** 1116**--fno-provide-tcb-caps** 1117 1118> By default each thread gets a cap to its own TCB. The only purpose of this is 1119 to allow it to suspend itself when it exits. These TCBs can complicate 1120 reasoning about a generated CapDL specification. This option elides these TCB 1121 caps at the cost of threads messily VM faulting when they exit. 1122 1123### Modules 1124 1125Each subset of CAmkES functionality is encapsulated in a Python module that 1126defines exactly what functions and variables are exported. The APIs of these 1127are described below and usage should be reasonably straightforward. To import 1128any of these modules the top-level directory of this distribution should be in 1129your `PYTHONPATH` environment variable. The available modules are: 1130 1131**[camkes.ast](#camkes.ast)** 1132 1133> Definitions of objects that can appear in the result of parsing a CAmkES 1134 specification. If you want to reference the types of objects in a resulting 1135 AST you will need to import this. 1136 1137**camkes.internal** 1138 1139> Functionality used by other CAmkES modules. You should not import this 1140 module. 1141 1142**[camkes.parser](#camkes.parser)** 1143 1144> To parse an input specification in memory or to do post-processing 1145 manipulations on a specification-derived AST you will need to import this 1146 module. The [runner](#runner) imports this module to perform its job. 1147 1148**camkes.runner** 1149 1150> This module is available, but does not export any symbols. You should never 1151 need to import it. 1152 1153**[camkes.templates](#camkes.templates)** 1154 1155> If you need to lookup builtin templates you will need to import this module. 1156 Note that this module does not contain any template _instantiation_ logic. 1157 1158#### camkes.ast 1159 1160The result of parsing a CAmkES specification is an Abstract Syntax Tree (AST), 1161representing the input as a set of interconnected nodes. When using the default 1162parser, the object returned is of type, `LiftedAST`, which is defined in this 1163module. `LiftedAST` and its children all inherit from a base type, `ASTObject`, 1164that provides common functionality like traversal and comparison. 1165 1166One of the AST objects is a class, `Reference`. Objects of this class are used 1167in the AST to represent symbols that refer to entities that are defined 1168elsewhere. During parsing, references are removed from the AST as they are 1169resolved to the entities to which they refer. In particular, if you are using 1170the default parser, the returned AST will never contain any `Reference` 1171objects. 1172 1173In the code and in this document there is some discussion of 'collapsing' AST 1174references. This is meant to refer to replacing the `Reference` object in the 1175AST by the entity to which it refers. Note that this needs to be done by 1176reference so that you still only end up with a single copy of the entity, but 1177multiple pointers to it. 1178 1179If you are not using the default CAmkES parser, but are assembling your own 1180from the [parser module](#camkes.parser), it is important to note that objects 1181of the classes in the AST module are only created in the stage 3 parser. If you 1182are inspecting the output of any low-level parser prior to stage 3, you will 1183not see objects from camkes.ast. 1184 1185#### camkes.parser 1186 1187If you need to manipulate the AST, rather than just simply printing it 1188out, you will want to import the parser as a module into your own code. After 1189importing this module, you can interact with the parser through the following 1190high-level API. 1191 1192**`parse_file(filename, options=None)`** 1193 1194> Parse a file into a `LiftedAST`. The `options` arguments is expected to be a 1195 namespace as constructed by the runner. If you have non-standard parsing 1196 requirements, you may find this function is insufficiently flexible for your 1197 needs. In this case, you will need to compose the low-level parsers. You can 1198 see a rough guide of how to do this in camkes/parser/parser.py. 1199 1200**`parse_string(string, options=None)`** 1201 1202> Parse a string into a `LiftedAST`. This function works identically to the 1203 previous in all respects, except obviously you will not have accurate 1204 filename information. 1205 1206#### camkes.templates 1207 1208This module contains functionality for looking up builtin templates. The 1209templates themselves are actually stored in this directory (camkes/templates) 1210as well to reduce confusion. The description below only describes the externally 1211facing behaviour of this module. If you need to understand how template lookups 1212actually work you will need to read the source code and comments. 1213 1214The API only contains a single class through which all access is intended to 1215flow. 1216 1217`Templates.`**`__init__(self, platform)`** 1218 1219> Create a new template store in which templates can later be looked up. The 1220 category of templates that are available from this store is specialised via 1221 **`platform`**. At time of writing the valid values of **`platform`** are 1222 'seL4', 'CIMP' and 'GraphViz'. 1223 1224`Templates.`**`add_root(self, root)`** 1225 1226> Add a directory to be searched for templates when performing lookups. This 1227 directory is added _before_ existing directories, which allows you to 1228 overwrite builtin templates if you wish. 1229 1230`Templates.`**`get_roots(self)`** 1231 1232> Return the list of directories that are searched for templates. Note that if 1233 you are the only client operating on this `Templates` object you will know 1234 the contents of this list anyway, but this function is provided for 1235 convenience. 1236 1237`Templates.`**`add(self, connector_name, path, template)`** 1238 1239> Add a template to the lookup dictionary, such that it can later be returned 1240 in a template lookup. Only connector templates can be added currently (i.e. 1241 component templates and top-level templates cannot be added). The caller 1242 provides the **`connector_name`** this template applies to (e.g. 1243 'seL4MyConnector'), a partial lookup **`path`** to the template (e.g. 1244 'from.source') and a roots-relative path to the **`template`** itself. Again, 1245 this function is sufficiently complicated that it may be easier to comprehend 1246 its usage from reading `camkes/runner/__main__.py`. 1247 1248`Templates.`**`lookup(self, path, entity=None)`** 1249 1250> Locate and return a template. The **`path`** provided should be a full lookup 1251 path from the second-level of the lookup dictionary (i.e. not including the 1252 platform prefix). For example, a valid **`path`** might be 1253 'seL4RPCCall.from.source'. If you provide an **`entity`** this is used as a guard 1254 on the lookup. The guards come into play when looking up connector templates. 1255 In this situation the connector type of the connection you pass in as 1256 **`entity`** will be used to determine if a given template matches your 1257 lookup. This function returns `None` if a matching template can't be found. 1258 1259### Runtime API 1260 1261This section describes the environment in which you, as a user, will find 1262yourself writing code. Standard C library functionality is available, but as a 1263CAmkES application, there is also extra functionality provided by generated 1264code and supporting libraries. This extra functionality is what is documented 1265in this section. 1266 1267Parts of the functionality discussed below are provided by the library, 1268libsel4camkes. In a typical seL4 project the user would need to specify that 1269they want to link against this library. This is not required in CAmkES as it is 1270assumed you always want to link against this library. For more information from 1271a CAmkES developer's point of view, see [Core Libraries](#core-libraries). The 1272API is bidirectional in a sense, in that some of the functions below are called 1273by CAmkES code and expected to be provided by the user. This is noted in their 1274descriptions. 1275 1276The following types are available at runtime from the C context of a component: 1277 1278**`Buf`** (`#include <camkes/dataport.h>`) 1279 1280> The underlying type of a dataport. A user is never expected to instantiate 1281 one of these manually, but they are free to do so if they wish. 1282 1283**`camkes_error_handler_t`** (`#include <camkes/error.h>`) 1284> The type of an error handler for dealing with errors originating in glue 1285 code. For more information about this see 1286 [Error Handling](#error-handling). 1287 1288**`camkes_tls_t`** (`#include <camkes/tls.h>`) 1289 1290> Thread-local storage metadata. This captures some necessary information for 1291 constructing a thread context inside templates. A user is never expected to 1292 instantiate or deal with one of these, but they are free to do so if they 1293 wish. 1294 1295**`dataport_ptr_t`** (`#include <camkes/dataport.h>`) 1296 1297> A component-independent representation of a pointer into a dataport. This is 1298 intended to be an opaque type to the user that is only ever used via the 1299 `dataport_wrap_ptr` and `dataport_unwrap_ptr` functions. 1300 1301The following variables are available: 1302 1303**_`dataport`_** (`#include <camkes.h>`) 1304 1305> If a component has a dataport they will be provided with a symbol of the 1306 dataport's name that is a pointer of the type they specified in their CAmkES 1307 specification. As mentioned previously, the default type is `Buf`. 1308 1309The following functions are available at runtime: 1310 1311**`camkes_error_handler_t camkes_register_error_handler(camkes_error_handler_t handler)`** (`#include <camkes/error.h>`) 1312**`camkes_error_handler_t ` _`interface`_`_register_error_handler(camkes_error_handler_t handler)`** (`#include <camkes/error.h>`) 1313 1314> Register a component-wide or interface-specific error handler, respectively. 1315 These functions return the previous error handler or `NULL` if there was no 1316 previously installed error handler. For more information see 1317 [Error Handling](#error-handling). 1318 1319**`dataport_ptr_t dataport_wrap_ptr(void *ptr)`** (`#include <camkes/dataport.h>`) 1320**`void *dataport_unwrap_ptr(dataport_ptr_t ptr)`** (`#include <camkes/dataport.h>`) 1321 1322> Utility functions for creating and destroying a component-independent 1323 representation of a pointer into a dataport. This `dataport_ptr_t` can be 1324 passed over a procedure interface to be unwrapped by the receiving component. 1325 Unwrapping will fail if the underlying pointer is not into a dataport that is 1326 shared with the receiver. `dataport_unwrap_ptr` returns `NULL` on failure. 1327 1328**`void` _`dataport`_`_acquire(void)`** 1329 1330> An acquire memory fence. Any read from the dataport preceding this fence in 1331 program order will take place before any read or write following this fence in 1332 program order. In uniprocessor environments, this is always a compiler memory 1333 fence. In multiprocessor environments, memory barrier instructions will be 1334 emitted if necessary, depending on the affinities of component instances 1335 connected by the dataport. 1336 1337**`void` _`dataport`_`_release(void)`** 1338 1339> A release memory fence. Any write to the dataport following this fence in 1340 program order will take place after any read or write preceding this fence in 1341 program order. In uniprocessor environments, this is always a compiler memory 1342 fence. In multiprocessor environments, memory barrier instructions will be 1343 emitted if necessary, depending on the affinities of component instances 1344 connected by the dataport. 1345 1346**`void *camkes_dma_alloc(size_t size, int align)`** (`#include <camkes/dma.h>`) 1347**`void camkes_dma_free(void *ptr, size_t size)`** (`#include <camkes/dma.h>`) 1348 1349> Allocator for DMA device operations. These are closely linked with the DMA 1350 pool functionality, as the allocation is backed by this pool. 1351 1352**`uintptr_t camkes_dma_get_paddr(void *ptr)`** (`#include <camkes/dma.h>`) 1353 1354> Translate a pointer into a DMA region into a physical address. This function 1355 assumes that the pointer you are passing in is to a byte within a region 1356 allocated to you by `camkes_dma_alloc_page`. The reason for needing to obtain 1357 the physical address of a pointer is typically to pass to a device that is 1358 going to access this region outside of the scope of the MMU. For more 1359 information, see the [DMA](#direct-memory-access) section below. 1360 1361**`void *camkes_io_map(void *cookie, uintptr_t paddr, size_t size, int cached, ps_mem_flags_t flags)`** (`#include <camkes/io.h>`) 1362 1363> Lookup the translation to virtual address from the physical address of a 1364 memory-mapped IO device. This function is primarily to ease interaction with 1365 libplatsupport infrastructure, so refer to its documentation where 1366 appropriate. 1367 1368**`int camkes_io_mapper(ps_io_mapper_t *mapper)`** (`#include <camkes/io.h>`) 1369 1370> Construct an IO mapping structure to pass to libplatsupport. See source 1371 comments for more information about how to use this. 1372 1373**`int camkes_io_ops(ps_io_ops_t *ops)`** (`#include <camkes/io.h>`) 1374 1375> Construct an IO operations structure to pass to libplatsupport. See source 1376 comments for more information about how to use this. 1377 1378**`int camkes_io_port_in(void *cookie, uint32_t port, int io_size, uint32_t *result)`** (`#include <camkes/io.h>`) 1379**`int camkes_io_port_out(void *cookie, uint32_t port, int io_size, uint32_t val)`** (`#include <camkes/io.h>`) 1380 1381> Read from or write to a hardware IO port. This function is primarily to ease 1382 interaction with libplatsupport infrastructure, so refer to its documentation 1383 where appropriate. 1384 1385**`int camkes_io_port_ops(ps_io_port_ops_t *ops)`** (`#include <camkes/io.h>`) 1386 1387> Construct an IO port access structure to pass to libplatsupport. See source 1388 comments for more information about how to use this. 1389 1390**`const char *get_instance_name(void)`** (`#include <camkes.h>`) 1391 1392> Returns the name of this component instance. This can be helpful if you want 1393 to write component functionality that has different behaviour depending on 1394 which instance it is. 1395 1396**`int` _`instance`_`_main(int thread_id)`** 1397 1398> A component instance's entry point. This is generated by the platform and 1399 invokes the user's `run` function when complete. 1400 1401**`int main(int thread_id)`** (in libsel4camkes.a) 1402 1403> This function — the C entry point to a component — is provided by 1404 the platform. Components should not provide their own `main`. 1405 1406**`int run(void)`** 1407 1408> This function is expected to be provided by the user in a control component. 1409 It is invoked by `main` after component initialisation is complete. 1410 1411**`NORETURN _start(int thread_id)`** (in libsel4camkes.a) 1412 1413> This function provides the assembly entry point of a component and consists 1414 of a brief trampoline to `main`. The user can override this if they wish, but 1415 it is unwise to do this unless you have a deep understanding of the runtime 1416 environment. 1417 1418**`void pre_init(void)`** 1419 1420> This function can be optionally provided by the user. If it is present, it 1421 will be invoked _before_ the component's interfaces' init functions have 1422 executed. Be aware that you will not have full runtime support in this 1423 function. For example, interfaces cannot be expected to be accessible. 1424 1425**`void` _`interface`_`__init(void)`** 1426 1427> For each incoming or outgoing interface a user can optionally provide this 1428 function. If it is present it will be invoked _after_ the component's 1429 pre-init function, but _before_ its post-init function. The same caveats about 1430 the runtime environment from above are applicable here. 1431 1432**`void post_init(void)`** 1433 1434> This function can be optionally provided by the user. If it is present, it 1435 will be invoked _after_ the component's pre-init function and after all 1436 interfaces' init functions, but _before_ any interface enters its run 1437 function. 1438 1439**`int` _`interface`_`__run(void)`** 1440 1441> This function can be provided for any incoming or outgoing interface. If it 1442 is present, it will be invoked after all pre- and post-init functions have 1443 run. 1444 1445**_`return`_ _`procedure`_`_`_`method`_`(`_`args...`_`)`** (`#include <camkes.h>`) 1446 1447> In a component that provides a procedure interface, things are somewhat 1448 reversed and the implementation calls functions that you are expected to 1449 provide. For each method in the procedure you are expected to provide a 1450 matching implementation. In a component that uses a procedure interface, 1451 functions of this form are available for you to call. 1452 1453**`void` _`event`_`_emit(void)`** (`#include <camkes.h>`) 1454 1455> In a component that emits an event a function prefixed with the event's name 1456 is available that causes the event to be sent. 1457 1458**`void` _`event`_`_poll(void)`** (`#include <camkes.h>`) 1459 1460> In a component that consumes an event a function prefixed with the event's 1461 name is available that returns whether there is a pending event. Note, this 1462 function never blocks. 1463 1464**`int` _`event`_`_reg_callback(void (*callback)(void*), void *arg)`** (`#include <camkes.h>`) 1465 1466> In a component that consumes an event a function prefixed with the event's 1467 name is available for registering a callback for this event. When the event 1468 is received, the provided function will be invoked with the argument provided 1469 when registering the callback. Note that registered 1470 callbacks take precedence over threads blocked on calls to _`event`_`_wait`. 1471 _`event`_`_reg_callback` returns 0 on success and non-zero if the callback 1472 could not be registered. 1473 1474**`void` _`event`_`_wait(void)`** (`#include <camkes.h>`) 1475 1476> In a component that consumes an event a function prefixed with the event's 1477 name is available that blocks until the event is received. 1478 1479### Synchronization Primitives 1480 1481CAmkES provides three primitives for intra-component mutual exclusion and synchronization. 1482Mutexes, semaphores, and binary semaphores are declared similarly to properties of a component definition: 1483 1484```camkes 1485component Foo { 1486 has mutex m; 1487 has semaphore s; 1488 has binary_semaphore b; 1489} 1490``` 1491 1492By default semaphores have a count (initial value) of 1, and binary semaphores have an initial value 1493of 0. This can be adjusted using an attribute: 1494 1495```camkes 1496assembly { 1497 composition { 1498 component Foo f; 1499 ... 1500 } 1501 configuration { 1502 f.s_value = 4; 1503 f.b_value = 1; // must be either 0 or 1 1504 ... 1505 } 1506} 1507``` 1508 1509An application can lock or unlock a declared mutex and call post or wait on a 1510declared semaphore or binary semaphore. For example, for the above declarations, the following 1511functions are available at runtime: 1512 1513```c 1514/* Lock mutex m */ 1515int m_lock(void); 1516 1517/* Unlock mutex m */ 1518int m_unlock(void); 1519 1520/* Wait on semaphore s */ 1521int s_wait(void); 1522 1523/* Try to wait on semaphore s */ 1524int s_trywait(void); 1525 1526/* Post to semaphore s */ 1527int s_post(void); 1528 1529/* Wait on a binary semaphore b */ 1530int b_wait(void); 1531 1532/* Post to a binary semaphore b */ 1533int b_post(void); 1534``` 1535 1536The CAmkES mutexes and semaphores have the behaviour you would expect from an 1537seL4 or pthreads implementation. 1538 1539There is no native support for inter-component locks. However, it is possible 1540to construct these on top of the CAmkES platform. An example of how you would 1541do this is shown in the lockserver example application in the CAmkES project 1542repository. 1543 1544### Direct Memory Access 1545 1546Direct Memory Access (DMA) is a hardware feature that allows devices to read 1547and write memory without going via the CPU. It is intended to give a fast I/O 1548path to devices, for which memory access is usually the bottleneck. 1549 1550This only has specific relevance in the context of CAmkES because on platforms 1551without an [IOMMU](https://en.wikipedia.org/wiki/IOMMU) devices perform DMA 1552accesses on physical memory, rather than virtual memory. The implications of 1553this are that, when a device is being directed to perform I/O by a driver, it 1554needs to know the physical address(es) of the memory it is about to access. On 1555seL4 reversing a virtual memory mapping requires specific capability operations 1556and thus CAmkES needs to be aware of any memory region which you intend to use 1557for DMA transfers. 1558 1559To allocate some memory for DMA within a specific component instance you 1560describe a DMA pool with a size in bytes. For example, 1561 1562```camkes 1563assembly { 1564 composition { 1565 component Foo f; 1566 ... 1567 } 1568 configuration { 1569 f.dma_pool = 8192; 1570 } 1571} 1572``` 1573 1574This declares an 8KB pool of memory that is available for DMA operations. 1575Within the component you must allocate and release pointers into this region 1576with the `camkes_dma_alloc` and `camkes_dma_free` functions described above. 1577The allocation function accepts a size and alignment constraint, but be aware 1578that allocation may not be efficient or guaranteed when requesting more than 15794Kb. Note that if you declare a DMA pool that is not page-aligned (4K on the 1580platforms we support) it will automatically be rounded up. 1581 1582#### Efficient DMA 1583 1584For components that need to perform large DMA operations, you will need to 1585allocate a large DMA pool. Backing the virtual address space mappings for such 1586a pool with 4KB frames can lead to performance issues. For this reason, you may 1587wish to use the command line option --largeframe-dma to back DMA pools with 1588large frames. 1589 1590This is relatively straightforward on IA32, but on an ARM platform you may run 1591into a limitation of the GNU Assembler that prevents the large alignments 1592required by the DMA pool. Support for working around this is provided by the 1593CAmkES build system, but is a little complicated, so the precise steps for 1594achieving this in a CAmkES project are documented below. 1595 1596Enable large frame promotion for the DMA pool in your build configuration: 1597 1598```bash 1599cmake . -DCAmkESDMALargeFramePromotion=ON 1600``` 1601 1602On older versions of binutils, if you were using a large enough DMA pool 1603to get promoted to large frames with an alignment constraint that was rejected 1604by the GNU Assembler, you should see output like the following: 1605 1606``` 1607/tmp/ccfGhK5Z.s: Assembler messages: 1608/tmp/ccfGhK5Z.s:1483: Error: alignment too large: 15 assumed 1609``` 1610Updating binutils should fix this issue. 1611 1612### Error Handling 1613 1614Some runtime conditions can lead to an error in the glue code. For example, if 1615an interface accepts a string parameter and the caller passes a string that is 1616too large to fit in the IPC buffer. Errors can also arise in glue code if your 1617user code is not well-behaved and attempts to operate directly on capabilities. 1618The glue code attempts to handle all errors occurring from user mistakes and 1619malicious user code, to the best of its abilities. It also attempts to handle 1620errors that occur as a result of unexpected runtime conditions. For example, 1621accesses to a device that unexpectedly is not found at runtime. 1622 1623The mode of error handling can be configured at compile-time, but the default 1624mode is generally the only relevant one you will need. It allows for runtime 1625handling of errors. By default, all errors cause a diagnostic message and a 1626system halt on a debug kernel. To alter this behaviour, user code can call the 1627function `camkes_register_error_handler` (described in 1628[Runtime API](#runtime-api)) and provide their own error handling function. 1629The user's error handling will thenceforth be invoked by glue code whenever an 1630error is detected. The error handling function should return one of the 1631following values, documented further in `camkes/error.h`, that indicate to the 1632glue code how it should proceed: 1633 1634* `CEA_DISCARD` ��� Ignore whatever message or request was currently being 1635 handled and return to the original calling function of the user or an event 1636 loop as appropriate. This is typically the failure mode you want for servers 1637 that are intended to be robust against denial-of-service attacks from 1638 malicious clients. 1639 1640* `CEA_IGNORE` ��� Pretend the error was not detected and continue executing. 1641 This is almost never the response you want to take, but it can be useful for 1642 debugging or masking spurious errors. 1643 1644* `CEA_ABORT` ��� Terminate the current thread with failure status. This is a 1645 fail-stop response, though note it will not halt the rest of the system. If 1646 the glue code is currently handling a request on behalf of a client, the 1647 client will likely end up stuck blocked waiting for a response. 1648 1649* `CEA_HALT` ��� Halt the entire system. This is only possible on a debug 1650 kernel. On a release kernel it will act identically to `CEA_ABORT`. 1651 1652To conditionally determine which response to return, the error handler is 1653passed a structure that describes the error that was detected. For details on 1654this structure, refer to `camkes/error.h`. 1655 1656The mechanism just described allows for handling errors at a component-wide 1657level. In a more complicated component, there are often notional subsystems 1658that want to be able to handle their own errors independently. For this there 1659are interface-specific error handlers. Each interface has its own error handler 1660registration function as _`interface`_`_register_error_handler`. Any interface that 1661does not have a registered interface-specific error handler will default to the 1662component-wide error handler. 1663 1664### Custom Attributes 1665 1666CAmkES allows the programmer to define arbitrary attributes of components. 1667 1668```camkes 1669component Foo { 1670 attribute string a; 1671 attribute int b; 1672} 1673``` 1674 1675These attributes are set in the configuration section of the assembly: 1676 1677```camkes 1678assembly { 1679 composition { 1680 component Foo f; 1681 ... 1682 } 1683 configuration { 1684 f.a = "Hello, World!"; 1685 f.b = 42; 1686 ... 1687 } 1688} 1689``` 1690 1691This results in the specified values being available as global variables 1692in the glue code with the same name as the attribute. 1693 1694```c 1695const char * a = "Hello, World!"; 1696const int b = 42; 1697``` 1698 1699#### Attribute's conversion to literal 1700 1701Unfortunately, the `C` language (in contrast to C++) does not support using 1702`lvalues` as literals (e.g. when declaring an array), even if declared as const, 1703so we need to introduce a "mechanism" for converting CAmkES attributes to 1704literals. 1705 1706The `CAMKES_CONST_ATTR` macro has been introduced for that purpose. 1707 1708Actually, the macro does not really convert arbitrary variables, but rather 1709CAmkES declares a const variable and also adds a respective macro to the code, 1710which is then used for that purpose. 1711 1712Usage example is presented below: 1713 1714```C 1715/* main.camkes */ 1716assembly { 1717 composition { 1718 component FOO foo; 1719 } 1720 configuration { 1721 foo.lenData = 16; 1722 } 1723} 1724 1725/* Foo.c */ 1726const int foo[CAMKES_CONST_ATTR(lenData)] = { 0 }; 1727 1728int run() 1729{ 1730#if CAMKES_CONST_ATTR(lenData) < 0xF0 1731 return 0; 1732#else 1733 return 1; 1734#endif 1735} 1736``` 1737 1738### Hardware Components 1739 1740A hardware component represents an interface to hardware in the form of a component. 1741Declaring a component with the `hardware` keyword creates a hardware component. 1742 1743```camkes 1744component Device { 1745 hardware; 1746 1747 provides IOPort io_port; 1748 emits Interrupt irq; 1749 dataport Buf mem; 1750} 1751``` 1752 1753When an interface of a device component instance is connected to a regular 1754component, that component gets access to that device via some 1755hardware interface (interface here refers to a means of interacting with 1756hardware - not a CAmkES interface). 1757The type of hardware interface depends on the type of CAmkES interface, 1758and the connector used. Available connectors for hardware, and their 1759corresponding hardware interfaces are listed below. 1760 1761**Interface:** procedure \ 1762**Keyword:** `provides` \ 1763**Connector:** `seL4HardwareIOPort` \ 1764**Description:** 1765When using `IOPort` as the interface type, this provides access to IO ports. The connected 1766component gets access to the methods in the `IOPort` interface, which allow sending and receiving 1767data over IO ports. This is specific to the IA32 architecture. 1768 1769**Interface:** event \ 1770**Keyword:** `emits` \ 1771**Connector:** `seL4HardwareInterrupt` \ 1772**Description:** 1773An event is emitted when an interrupt occurs. 1774 1775**Interface:** port \ 1776**Keyword:** `dataport` \ 1777**Connector:** `seL4HardwareMMIO` \ 1778**Description:** 1779Memory mapped registers can be accessed via the shared memory. 1780 1781The following shows an example of connecting a hardware component to a driver 1782component. Note the order of arguments to the connection. `seL4HardwareInterrupt` requires 1783the hardware interface on the `from` side of the connection, whereas the other connectors 1784require the hardware interface on the `to` side. 1785 1786```camkes 1787component Driver { 1788 uses IOPort io_port; 1789 consumes Interrupt irq; 1790 dataport Buf mem; 1791} 1792 1793assembly { 1794 composition { 1795 component Device dev; 1796 component Driver drv; 1797 ... 1798 connection seL4HardwareIOPort ioport_c(from drv.io_port, to dev.io_port); 1799 connection seL4HardwareInterrupt irq_c(from dev.irq, to drv.irq); 1800 connection seL4HardwareMMIO mmio_c(from drv.mem, to dev.mem); 1801 } 1802} 1803``` 1804 1805#### Configuration 1806 1807Each type of hardware component interface has some configuration required for it 1808to work. This is done by setting attributes of instances of device components. 1809 1810##### MMIO 1811 1812The physical address of the memory, and size (in bytes) to make available 1813to a connected component must be specified. The example below specifies that 1814the port named `mem` of the component instance `d` is a 0x1000 byte region 1815starting at physical address 0xE0000000. 1816 1817```camkes 1818component Device { 1819 hardware; 1820 1821 dataport Buf mem; 1822 ... 1823} 1824 1825assembly { 1826 composition { 1827 component Device d; 1828 ... 1829 } 1830 configuration { 1831 d.mem_paddr = 0xE0000000; 1832 d.mem_size = 0x1000; 1833 ... 1834 } 1835} 1836``` 1837 1838##### Interrupts 1839 1840Depending on the platform different information needs to specified to 1841connect a hardware interrupt source with a components interrupt handler. 1842 1843On ARM and if you are using the legacy x86 PIC controller then simply an 1844interrupt number must be specified. The example below specifies that 1845the event will be emitted when interrupt number 2 is received. 1846 1847```camkes 1848component Device { 1849 hardware; 1850 1851 emits Interrupt irq; 1852 ... 1853} 1854 1855assembly { 1856 composition { 1857 component Device d; 1858 ... 1859 } 1860 configuration { 1861 d.irq_irq_number = 2; 1862 ... 1863 } 1864} 1865``` 1866 1867If using the newer I/O APIC controller on x86 then you need to describe 1868the I/O APIC source and provide a destination vector. An I/O APIC source 1869is described in terms of 1870 1871* Physical I/O APIC controller indexed starting at 0. Typically a system 1872 only has one of these 1873* Pin, ranging from 0 to 23, on the I/O APIC controller that the interrupt 1874 will come in on 1875* The trigger mode and polarity of the interrupt 1876 1877The destination vector is a number in the range of 0 to 107 and must be unique 1878across all destination vectors defined in an assembly. 1879 1880Selecting between edge and level trigger modes is done by setting the 1881`*_irq_ioapic_level` attribute where a value of `1` means level triggered and 1882`0` means edge triggered. Similarly the active polarity is configured by 1883the `*_irq_ioapic_polarity` attribute where a value of `1` means active 1884low and `0` means active high. 1885 1886To change the previous example to connect an interrupt on I/O APIC 0, pin 2 1887that is edge triggered with active high polarity you would change 1888 1889```camkes 1890d.irq_irq_number = 2; 1891``` 1892 1893To become 1894 1895```camkes 1896d.irq_irq_type = "ioapic"; 1897d.irq_irq_ioapic = 0; 1898d.irq_irq_ioapic_pin = 2; 1899d.irq_irq_ioapic_polarity = 0; 1900d.irq_irq_ioapic_level = 0; 1901d.irq_irq_vector = 42; 1902``` 1903 1904With the `vector` being arbitrarily chosen as `42` 1905 1906An interrupt that is edge triggered and active high can be more concisely 1907declared as an ISA interrupt by 1908 1909```camkes 1910d.irq_irq_type = "isa"; 1911d.irq_irq_ioapic = 0; 1912d.irq_irq_ioapic_pin = 2; 1913d.irq_irq_vector = 42; 1914``` 1915 1916Similarly if this interrupt were to be level triggered and active low it 1917could be declared as a PCI interrupt by 1918 1919```camkes 1920d.irq_irq_type = "pci"; 1921d.irq_irq_ioapic = 0; 1922d.irq_irq_ioapic_pin = 2; 1923d.irq_irq_vector = 42; 1924``` 1925 1926##### IO Ports 1927 1928The allowable range of IO Ports must be specified. 1929The example below specifies that the hardware component instance 1930`d` may access IO ports greater than or equal to 0x60, and less 1931than 0x64. 1932 1933```camkes 1934component Device { 1935 hardware; 1936 1937 provides IOPort io_port; 1938 ... 1939} 1940 1941assembly { 1942 composition { 1943 component Device d; 1944 ... 1945 } 1946 configuration { 1947 d.io_port_attributes = "0x60:0x64"; 1948 ... 1949 } 1950} 1951``` 1952 1953### Port Privileges 1954 1955CAmkES allows the programmer to specify access rights that instances have over 1956the ports connecting them to other instances. This is done by setting the 1957`*_access` attribute of the port. The value of the attribute must be a string 1958containing the letters "R", "W" and "X", giving the port read, write and execute 1959privileges, respectively. If left unspecified, full access will be given. 1960 1961In the example below, instance `f` has read-only access to `port_a`, and 1962instance `b` has read/write access to `port_a`. Instance `b` has read-only 1963access to `port_b`. Instance `a` has read/write/execute access to `port_b` even 1964though it's not explicitly stated, as this is the default. 1965 1966```camkes 1967component Foo { 1968 dataport Buf data_a; 1969 dataport Buf data_b; 1970} 1971 1972component Bar { 1973 dataport Buf data_a; 1974 dataport Buf data_b; 1975} 1976 1977assembly { 1978 composition { 1979 component Foo f; 1980 component Bar b; 1981 ... 1982 connection seL4SharedData port_a(from f.data_a, to b.data_a); 1983 connection seL4SharedData port_b(from f.data_b, to b.data_b); 1984 ... 1985 } 1986 configuration { 1987 f.data_a_access = "R"; 1988 b.data_a_access = "RW; 1989 f.data_b_access = "R"; 1990 ... 1991 } 1992} 1993``` 1994 1995### Thread Model 1996 1997CAmkES components are typically multithreaded and, to prevent race conditions, 1998it is often necessary to understand what threads exist in your system. 1999 2000Firstly there is a single active thread. This is the thread of control that 2001calls the component's entry point for components declared `control`. This 2002thread is present even in non-control components in order to perform 2003initialisation actions. 2004 2005Each interface your component interacts with, either as an incoming or outgoing 2006interface, induces another thread within the component. Initial synchronisation 2007of these threads and their various setup activities is all handled by generated 2008code. Note that this per-interface thread is present even for interfaces that 2009you may think of as passive. For example, dataports. This is merely an 2010implementation artefact and may change in future. 2011 2012One thing that may not be intuitive for users is that you have no guarantee as 2013to which thread will invoke an event callback. If you have registered a 2014callback for an event you are receiving, you should not assume that any 2015thread-local state persists between invocations. This is because the thread 2016which invokes a callback may not be the same thread as was used last time the 2017callback was invoked. 2018 2019### Thread Priorities 2020 2021Each thread in a CAmkES system has a priority that determines how it is 2022scheduled by seL4. These priorities default to a value given by the 2023`--default-priority` command-line argument to the runner. In a given system, it 2024it possible to adjust the priority of a specific thread with an attribute that 2025has specific semantics. To adjust the priority of the control thread (the 2026thread that calls `run`), use the `_priority` attribute: 2027 2028```camkes 2029assembly { 2030 composition { 2031 component Foo f; 2032 ... 2033 } 2034 configuration { 2035 f._priority = 100; 2036 } 2037} 2038``` 2039 2040To adjust the priority of an interface thread, use an attribute named with the 2041name of the interface and the suffix ``_priority'': 2042 2043```camkes 2044component Foo { 2045 uses MyInterface i; 2046} 2047 2048assembly { 2049 composition { 2050 component Foo f; 2051 ... 2052 } 2053 configuration { 2054 f.i_priority = 100; 2055 } 2056} 2057``` 2058 2059If you want to adjust the priority of every thread within a given component 2060instance, you can use a general component attribute: 2061 2062```camkes 2063configuration { 2064 f.priority = 100; 2065} 2066``` 2067 2068For more information about the specifics of the seL4 scheduler, please refer to 2069the seL4 documentation. 2070 2071### Thread CPU affinity 2072 2073Each thread in a CAmkES system also has a processor affinity. This affinity will 2074by default bind all threads to CPU index 0, bootstrap-processor. In a system 2075where seL4 is built without multicore, setting this value above 0 is illegal. 2076 2077```camkes 2078component Mycomponent { 2079 /* ... */ 2080 uses Myinterface i; 2081} 2082 2083assembly { 2084 composition { 2085 component Mycomponent c; 2086 } 2087 configuration { 2088 /* Run all threads in "c" on CPU 1 */ 2089 c.affinity = 1; 2090 } 2091} 2092``` 2093 2094Alternatively: 2095 2096```camkes 2097configuration { 2098 /* Run only the control thread on CPU 1, but run the rest of the threads 2099 * in this component on the "default" CPU (index 0). 2100 */ 2101 c._affinity = 1; 2102} 2103``` 2104 2105Or perhaps: 2106 2107```camkes 2108configuration { 2109 /* Run only the interface thread for "i" on CPU 1, but run the rest of the 2110 * threads in this component on the "default" CPU (index 0). 2111 */ 2112 c.i_affinity = 1; 2113} 2114``` 2115 2116### Thread Stacks 2117 2118Each CAmkES thread has a stack provided for it for use at runtime, as is 2119typical. Stack size defaults to 4K, but this default can be adjusted through 2120the relevant build system configuration option. Additionally the stacks of 2121individual threads within a component can be set with attributes: 2122 2123```camkes 2124configuration { 2125 2126 // Assign foo's control thread an 8K stack 2127 foo._stack_size = 8192; 2128 2129 // Assign the interface thread for inf in foo a 16K stack 2130 foo.inf_stack_size = 16384; 2131 2132} 2133``` 2134 2135Note that stacks must have a size that is 4K aligned, so if you assign a thread 2136a stack size that is not 4K aligned it will be rounded up. Stacks have a 4K 2137unmapped "guard page" either side of them. This is a debugging aid to force a 2138virtual memory fault when threads underrun or overrun their stacks. 2139 2140### Scheduling Domains 2141 2142In CAmkES, it is possible to specify the domain each thread belongs to, by setting attributes. 2143Each interface of each component instance will have an associated thread, and 2144there will be an additional thread per-component to perform initialisation and 2145optionally act as the control thread. For interface threads, their domain can be 2146specified by setting the attribute `<interface>_domain` of the instance. For 2147control threads, the attribute `_domain` of the instance can be set. 2148 2149```camkes 2150component Foo { 2151 control; 2152 uses iface i; 2153} 2154 2155component Bar { 2156 provides iface o; 2157} 2158 2159assembly { 2160 composition { 2161 component Foo f; 2162 component Bar b; 2163 connection seL4RPCCall c(from f.i, to b.o); 2164 ... 2165 } 2166 configuration { 2167 f._domain = 0; // domain of control thread of f 2168 b.o_domain = 1; // domain of o interface of b 2169 ... 2170 } 2171} 2172``` 2173 2174### Userspace RPC Transfer Buffers 2175 2176By default, the majority of RPC connectors exchange data through a 2177kernel-managed IPC buffer. RPC communication involving longer messages can be 2178optimised by exchanging data through userspace buffers instead of the IPC 2179buffer. To achieve this, set up an `seL4SharedData` connection and assign a 2180custom attribute: 2181 2182```camkes 2183component Foo { 2184 uses iface i; 2185 dataport Buf d; 2186} 2187 2188component Bar { 2189 provides iface j; 2190 dataport Buf e; 2191} 2192 2193assembly { 2194 composition { 2195 component Foo foo; 2196 component Bar bar; 2197 2198 connection seL4RPCCall conn(from foo.i, to bar.j); 2199 connection seL4SharedData ubuf(from foo.d, to bar.e); 2200 } 2201 configuration { 2202 conn.buffer = "ubuf"; 2203 } 2204} 2205``` 2206 2207There are a few limitations to be aware of when using this technique. The only 2208RPC connector that supports this style of userspace communication at time of 2209writing is `seL4RPCCall`. The RPC connection must be 1-to-1 and the 2210`seL4SharedData` connection must connect the same two component instances. The 2211size of the buffer (determined by the dataports' type) is flexible, but if you 2212use a buffer that is too small to accommodate RPC data you will trigger runtime 2213errors during parameter marshalling. 2214 2215### Multi-Assembly Applications 2216 2217CAmkES allows programmers to define an arbitrary number of assemblies for their application. 2218Different assemblies may appear in different files, provided that they are appropriately 2219included in the main ADL file. At compile time, the bodies of each 2220assembly are merged together, with all declared names remaining the same. 2221Thus, naming conflicts can occur on items declared in different assemblies. 2222 2223```camkes 2224assembly { 2225 composition { 2226 component Foo f; 2227 } 2228} 2229 2230assembly { 2231 composition { 2232 component Bar b; 2233 connection seL4RPCCall c(from f.a, to b.a); 2234 } 2235 configuration { 2236 f.some_attribute = 0; 2237 } 2238} 2239``` 2240 2241The example above is equivalent to: 2242 2243```camkes 2244assembly { 2245 composition { 2246 component Foo f; 2247 component Bar b; 2248 connection seL4RPCCall c(from f.a, to b.a); 2249 } 2250 configuration { 2251 f.some_attribute = 0; 2252 } 2253} 2254``` 2255 2256### Hierarchical Components 2257 2258#### Syntax 2259 2260A component definition may include a composition and configuration section. 2261The composition and configuration sections must be the last items in the component definition. 2262The composition and configuration sections may appear in any order. A composition section 2263can be included without a configuration, however a configuration section is only allowed 2264if there is a composition. 2265 2266```camkes 2267component Foo_Impl { 2268 provides iface_a a_impl; 2269 attribute string str; 2270} 2271 2272component Foo { 2273 provides iface_a a; 2274 2275 composition { 2276 component Foo_Impl fi; 2277 export fi.a_impl -> a; 2278 } 2279 configuration { 2280 fi.str = "Hello, World!"; 2281 } 2282} 2283 2284component Bar { 2285 control; 2286 uses iface_a a; 2287} 2288 2289assembly { 2290 composition { 2291 component Foo f; 2292 component Bar b; 2293 connection seL4RPCCall c(from b.a, to f.a); 2294 } 2295} 2296``` 2297 2298In the example above, the component `Foo` exposes a virtual interface `a`, 2299which is exported from the interface `a_impl` of the component instance `fi` of type `Foo_Impl`. 2300 2301#### Hierarchy Resolution 2302 2303Prior to compilation, the AST representing the system is transformed to remove all 2304hierarchical components. For each instance of a compound component, any internal instances 2305and internal connections declared 2306inside the component are copied into the top-level assembly with the compound component instance's 2307name prepended to their own. 2308Each appearance of a virtual interface of some compound component instance 2309in a connection in the top-level assembly, is replaced 2310with the exported interface of the internal instance copied into the top-level assembly 2311while resolving that compound component instance. 2312Then, for each compound component, all virtual interfaces are removed. 2313If this results in any components with no interfaces, these components, and all instances 2314of such components, are removed from the specification. 2315 2316The example above would be converted into the following: 2317 2318```camkes 2319component Foo_Impl { 2320 provides iface_a a_impl; 2321 attribute string str; 2322} 2323 2324component Bar { 2325 control; 2326 uses iface_a a; 2327} 2328assembly { 2329 composition { 2330 component Bar b; 2331 component Foo_Impl f.fi; 2332 connection seL4RPCCall c(from b.a, to f.fi.a_impl); 2333 } 2334 configuration { 2335 f.fi.str = "Hello, World!"; 2336 } 2337} 2338``` 2339 2340#### Examples 2341 2342##### Connecting multiple compound components 2343 2344It's possible for both sides of a connection to be virtual interfaces: 2345 2346```camkes 2347component Foo_Impl { 2348 provides iface_a a_impl; 2349} 2350 2351component Bar_Impl { 2352 uses iface_a a_usage; 2353} 2354 2355component Foo { 2356 provides iface_a a; 2357 2358 composition { 2359 component Foo_Impl fi; 2360 export fi.a_impl -> a; 2361 } 2362} 2363 2364component Bar { 2365 uses iface_a a; 2366 2367 composition { 2368 component Bar_Impl bi; 2369 export bi.a_usage -> a; 2370 } 2371} 2372 2373assembly { 2374 composition { 2375 component Foo f; 2376 component Bar b; 2377 connection seL4RPCCall c(from b.a, to f.a); 2378 } 2379} 2380``` 2381 2382This example compiles to: 2383 2384```camkes 2385component Foo_Impl { 2386 provides iface_a a_impl; 2387} 2388 2389component Bar_Impl { 2390 uses iface_a a_usage; 2391} 2392 2393assembly { 2394 composition { 2395 component Foo_Impl f.fi; 2396 component Bar_Impl b.bi; 2397 connection seL4RPCCall c(from b.bi.a_usage, to f.fi.a_impl); 2398 } 2399} 2400``` 2401 2402##### Compound component with non-virtual interfaces 2403 2404A component can have both virtual and implemented interfaces: 2405 2406```camkes 2407component Foo_Impl { 2408 provides iface_a a_impl; 2409} 2410 2411component Foo { 2412 provides iface_a a; 2413 provides iface_b b; 2414 2415 composition { 2416 component Foo_Impl fi; 2417 export fi.a_impl -> a; 2418 } 2419} 2420 2421component Bar { 2422 uses iface_a a; 2423 uses iface_b b; 2424} 2425 2426assembly { 2427 composition { 2428 component Foo f; 2429 component Bar b; 2430 connection seL4RPCCall c(from b.a, to f.a); 2431 connection seL4RPCCall c(from b.b, to f.b); 2432 } 2433} 2434``` 2435 2436This example compiles to: 2437 2438```camkes 2439component Foo_Impl { 2440 provides iface_a a_impl; 2441} 2442 2443component Foo { 2444 provides iface_b b; 2445} 2446 2447component Bar { 2448 uses iface_a a; 2449 uses iface_b b; 2450} 2451 2452assembly { 2453 composition { 2454 component Foo f; 2455 component Bar b; 2456 component Foo_Impl f.fi; 2457 connection seL4RPCCall c(from b.a, to f.fi.a_impl); 2458 connection seL4RPCCall c(from b.b, to f.b); 2459 } 2460} 2461``` 2462 2463##### Deeper Hierarchy 2464 2465So far, each example has had a compound component containing only non-compound component instances. 2466It's possible to have a hierarchy of components of an arbitrary depth. 2467 2468```camkes 2469component A_Piece1 { 2470 provides a_piece ap; 2471} 2472 2473component A_Piece2 { 2474 uses a_piece ap; 2475 provides iface_a a_impl; 2476} 2477 2478component Foo_Impl { 2479 provides iface_a a_impl; 2480 2481 composition { 2482 component A_Piece1 a1; 2483 component A_Piece2 a2; 2484 connection seL4RPCCall c(from a1.ap, to a2.ap); 2485 export a2.a_impl -> a_impl; 2486 } 2487} 2488 2489component Foo { 2490 provides iface_a a; 2491 2492 composition { 2493 component Foo_Impl fi; 2494 export fi.a_impl -> a; 2495 } 2496} 2497 2498component Bar { 2499 uses iface_a a; 2500} 2501 2502assembly { 2503 composition { 2504 component Foo f; 2505 component Bar b; 2506 connection seL4RPCCall c(from b.a, to f.a); 2507 } 2508} 2509``` 2510 2511This example compiles to: 2512 2513```camkes 2514component A_Piece1 { 2515 provides a_piece ap; 2516} 2517 2518component A_Piece2 { 2519 uses a_piece ap; 2520 provides iface_a a_impl; 2521} 2522 2523component Bar { 2524 uses iface_a a; 2525} 2526 2527assembly { 2528 composition { 2529 component Bar b; 2530 2531 component A_Piece1 f.fi.a1; 2532 component A_Piece2 f.fi.a2; 2533 2534 connection seL4RPCCall f.fi.c(from f.fi.a1.ap, to f.fi.a2.ap); 2535 connection seL4RPCCall c(from b.a, to f.fi.a2.a_impl); 2536 } 2537} 2538``` 2539 2540### Hierarchical Attributes 2541 2542Attributes of internal instances and internal connections declared in the composition section 2543of a compound component may be set to refer to attributes of that compound component. During 2544hierarchy resolution, values of referring attributes are set to copies of the values of 2545their corresponding referent attributes. 2546 2547#### Syntax 2548 2549The `<-` operator is used to set an attribute to refer to another. Lines of the following form 2550may appear in the configuration section of a compound component: 2551 2552```camkes 2553entity_name.attribute_name <- local_attribute_name; 2554``` 2555 2556Here, `entity_name` is the name of a component instance or connection declared in the component's 2557composition section, `attribute_name` is the name of an attribute of the entity, and 2558`local_attribute_name` is the name of an attribute of the composition component. 2559 2560#### Example 2561 2562```camkes 2563component B { 2564 ... 2565 attribute string b_str; 2566} 2567 2568component A { 2569 ... 2570 attribute string a_str; 2571 2572 composition { 2573 ... 2574 component B b; 2575 } 2576 configuration { 2577 ... 2578 b.b_str <- a_str; 2579 } 2580} 2581 2582assembly { 2583 composition { 2584 ... 2585 component A a; 2586 } 2587 configuration { 2588 ... 2589 a.a_str = "Hello, World!"; 2590 } 2591} 2592``` 2593 2594This example is resolved to the following: 2595 2596```camkes 2597component B { 2598 ... 2599 attribute string b_str; 2600} 2601 2602component A { 2603 ... 2604 attribute string a_str; 2605} 2606 2607assembly { 2608 composition { 2609 ... 2610 component A a; 2611 component B a_b; 2612 } 2613 configuration { 2614 ... 2615 a.a_str = "Hello, World!"; 2616 a_b.b_str = "Hello, World!"; 2617 } 2618} 2619``` 2620 2621### Custom Data Types 2622 2623CAmkES allows the definition of custom data types for procedure method arguments and ports. 2624Data types can be defined in C header files by typedefing a struct, enum or built-in type. 2625Sections of the application that refer to custom types must include the header file. 2626 2627#### Procedures 2628 2629Assume a data type `Vector` is defined in the file vector.h in the top level include directory of the application: 2630 2631```c 2632#ifndef _VECTOR_H_ 2633#define _VECTOR_H_ 2634 2635typedef struct { 2636 double x; 2637 double y; 2638} Vector; 2639 2640#endif 2641``` 2642 2643A procedural interface could then be defined to use the type: 2644 2645```camkes 2646procedure algebra_iface { 2647 include <vector.h>; 2648 Vector add(Vector a, Vector b); 2649} 2650``` 2651 2652C source files that need access to this data type can include the file with: 2653 2654```c 2655#include <vector.h> 2656``` 2657 2658To make the build system aware of the header file, for each component that uses it, the following must be added 2659to the application's `CMakeLists.txt` (replacing the name `Component` with the name of the component): 2660 2661``` 2662DeclareCAmkESComponent(Component INCLUDES include/vector.h) 2663``` 2664 2665#### Ports 2666 2667Assume a data type `IntArray` is defined in int_array.h in the top level include directory of the application: 2668 2669```c 2670#ifndef _INT_ARRAY_H_ 2671#define _INT_ARRAY_H_ 2672 2673typedef struct { 2674 int data[1024]; 2675} IntArray; 2676 2677#endif 2678``` 2679 2680A component could declare a port of this type: 2681 2682```camkes 2683component A { 2684 control; 2685 2686 include "int_array.h"; 2687 dataport IntArray int_arr; 2688} 2689``` 2690 2691This would give the implementation access to a global pointer, which points to 2692an appropriately large region of memory for the data type: 2693 2694```c 2695extern volatile IntArray * int_arr; 2696``` 2697 2698### Single Address Space Components (Groups) 2699 2700By default, each component instance in an application is given its own address 2701space. This is ideal for isolation, but this separation does not come for free 2702and inter-address space communication is necessarily more expensive than local 2703communication. To colocate two component instances in a single address space, 2704they can be grouped together: 2705 2706```camkes 2707assembly { 2708 composition { 2709 group my_group { 2710 component Foo foo; 2711 component Bar bar; 2712 } 2713 } 2714} 2715``` 2716 2717Any references to such instances now need to be qualified by their group name. 2718For example, to connect the above two instances: 2719 2720```camkes 2721... 2722connection seL4RPCCall conn(from my_group.foo.inf1, 2723 to my_group.bar.inf2); 2724... 2725``` 2726 2727When component instances are colocated, another connector becomes available. 2728The `seL4DirectCall` connector collapses RPC communication into a direct 2729function call. Its usage is identical to other connectors: 2730 2731```camkes 2732... 2733connection seL4DirectCall conn(from my_group.foo.inf1, 2734 to my_group.bar.inf2); 2735... 2736``` 2737 2738Using this connector between two components that are not colocated is incorrect 2739and will trigger an error. 2740 2741#### Caveats 2742 2743When colocating component instances in a single address space, the intent is 2744for the environment of the instances to be as close to indistinguishable as 2745possible (with the exception of performance characteristics) from full 2746separation. This abstraction is not perfect and there are some mechanisms that 2747have slightly different semantics when used in a single address space scenario 2748and in an isolated scenario. 2749 2750Parameters of direction `out` of certain types are typically heap-located in an 2751isolated component instance. This is still true in a colocated environment, but 2752when using the `seL4DirectCall` connector, these are located in the _callee's_ 2753heap, not the caller's as may be otherwise expected. Freeing one of these 2754pointers to the incorrect heap will result in heap corruption and should be 2755avoided. Conversely, _not_ freeing this pointer will leak memory and should also 2756be avoided. The recommended technique to work around this is to introduce a back 2757channel to the callee when necessary: 2758 2759```camkes 2760procedure my_proc { 2761 /* The following procedure will return a parameter, `x`, 2762 * that is a pointer into the callee's heap. It cannot 2763 * be directly freed by the caller and needs to be 2764 * passed back to the callee. 2765 */ 2766 void foo(out string x); 2767 2768 /* We provide a back channel for this. */ 2769 include <stdint.h>; 2770 void remote_free(uintptr_t p); 2771} 2772 2773component Caller { 2774 control; 2775 uses my_proc f; 2776} 2777 2778component Callee { 2779 provides my_proc g; 2780} 2781 2782assembly { 2783 composition { 2784 component Caller caller; 2785 component Callee callee; 2786 2787 connection seL4DirectCall conn(from caller.f, to callee.g); 2788 } 2789} 2790``` 2791 2792It is then possible to implement both components' code in such a way that 2793memory is always freed to the correct heap: 2794 2795```c 2796/* Caller.c */ 2797 2798int run(void) { 2799 char *x; 2800 f_foo(&x); 2801 printf("received %s\n", x); 2802 f_remote_free((uintptr_t)x); 2803 return 0; 2804} 2805``` 2806 2807```c 2808/* Callee.c */ 2809 2810void g_foo(char **x) { 2811 *x = strdup("hello world"); 2812} 2813 2814void g_remote_free(uintptr_t p) { 2815 free((void*)p); 2816} 2817``` 2818 2819This is cumbersome, but at least allows one to write safe code. In a 2820continually evolving project, it may not be known in advance whether 2821`seL4DirectCall` will be used. In these situations, it is recommended to use a 2822free wrapper that detects where a pointer is hosted. In the case of a simple 2823static heap region (the default), a wrapper can be constructed as follows: 2824 2825```c 2826/* Caller.c */ 2827 2828static void safe_free(void *p) { 2829 /* These symbols are defined by generated code and 2830 * specify the bounds of the heap. 2831 */ 2832 extern char *morecore_area; 2833 extern size_t morecore_size; 2834 2835 if ((uintptr_t)p >= (uintptr_t)morecore_area && 2836 (uintptr_t)p < (uintptr_t)morecore_area + morecore_size) { 2837 /* The pointer is in our heap. */ 2838 free(p); 2839 } else { 2840 /* The pointer is in the callee's heap. */ 2841 f_remote_free((uintptr_t)p); 2842 } 2843} 2844 2845int run(void) { 2846 char *x; 2847 f_foo(&x); 2848 printf("received %s\n", x); 2849 safe_free(x); 2850 return 0; 2851} 2852``` 2853 2854The preceding discussion dealt with `out` parameters, but note that the same 2855issue exists on _both_ sides of an `seL4DirectCall` connection using `inout` 2856parameters. That is, the argument to the callee and the final value to the 2857caller are both pointers that would normally point into a local heap, but now 2858potentially point into a remote heap. 2859 2860As a result of toolchain limitations, 2861[link-time optimisations](https://gcc.gnu.org/wiki/LinkTimeOptimization) cannot 2862be applied to a component group. If you have LTO enabled in your build settings 2863it will be ignored for component groups. 2864 2865### Global Include Directories 2866 2867CAmkES allows users to define a list of directories that will be searched 2868when resolving imports of .camkes files (components and interfaces). 2869`CAmkESAddImportPath(interfaces)` will append a directory to this search path. 2870There is an additional path for templates which can be modified by calling 2871`CAmkESAddTemplatesPath(templates)`. The repository global-components repository 2872is an example of these mechanisms being used to import components, interfaces 2873and templates into a project. The target project simply needs to include 2874`global-components.cmake` to enable these modules to be referred to from within 2875the project's camkes files. Below is an example of importing global-components: 2876```cmake 2877find_file(GLOBAL_COMPONENTS_PATH global-components.cmake PATHS ${CMAKE_SOURCE_DIR}/projects/global-components/ CMAKE_FIND_ROOT_PATH_BOTH) 2878mark_as_advanced(FORCE GLOBAL_COMPONENTS_PATH) 2879if("${GLOBAL_COMPONENTS_PATH}" STREQUAL "GLOBAL_COMPONENTS_PATH-NOTFOUND") 2880 message(FATAL_ERROR "Failed to find global-components.cmake. Consider cmake -DGLOBAL_COMPONENTS_PATH=/path/to/global-components.cmake") 2881endif() 2882include(${GLOBAL_COMPONENTS_PATH}) 2883 2884``` 2885 2886This allows one to place common components and interfaces in a central location 2887rather than duplicating them inside the application directory of each 2888application that uses them. Components and interfaces defined in global include 2889directories are known as **Global Components** and **Global Interfaces**. 2890When the distinction is necessary, non-global components and interfaces are 2891known as **Local Components** and **Local Interfaces**. 2892 2893#### Recommended Practices 2894 2895Generally, a component should be created as a global component unless there's 2896some good reason not to. Applications should consist of a (usually) small number 2897of control components, and possibly some application specific utility components. 2898When possible, utility components should be generalised and placed in a global 2899component repository. 2900 2901All procedural interfaces used or provided by global components should be 2902global interfaces. Applications containing multiple local components which 2903communicate over procedural interfaces should define these interfaces locally, 2904unless it would make sense for these interfaces to generalise to other components 2905in the future, in which case they should be global interfaces. 2906 2907Regarding header files defining custom data types, if the data type is specific to 2908a particular component or procedural interface, the header file should be placed 2909in the directory of that component or interface. Otherwise, header files should 2910be placed in a well known top-level subdirectory of the component repository so 2911they may be reused between components and interfaces. 2912 2913It is possible that between global components, there is some shared functionality 2914such as commonly used algorithms and data structures. Rather than duplicating this 2915code across multiple global components, it should be placed in source/header files 2916in a well known top-level subdirectory of the component repository. 2917 2918### Cached Hardware Dataports 2919 2920By default, memory backing hardware dataports (`seL4HardwareMMIO`) is mapped uncached. 2921Typically such a dataport will be backed by a device's memory mapped registers rather 2922than main memory. In such cases it's generally desired that after writing to a register 2923the effect of the write is felt immediately, and changes to device registers are observable 2924as soon as they occur, so mapping this memory uncached makes sense. There are however, 2925cases where it is preferable to map this memory cached instead. 2926 2927For example, consider a system that updates a large memory mapped frame buffer for 2928a display, by writing to it one word at a time. If this buffer was mapped uncached, 2929each word written to the buffer would incur the full time taken to write to memory. 2930If instead, the buffer was mapped cached, each word would be written to the cache, 2931incurring a much shorter write time. Cache lines would then be written back to memory 2932at a later point. This optimization works on the assumption that the throughput of 2933the cache being written back to memory is higher than that of the CPU writing 2934directly to memory a word at a time. After all the data has been written to the buffer, 2935the cache must be flushed to ensure the data is actually in the buffer. 2936 2937CAmkES provides a mechanism for flushing the cache, but currently it is a no-op 2938on all architectures other than ARM. On x86, the DMA engine is cache-coherent, 2939so there's no reason to explicitly flush the cache after writing to a cached 2940hardware dataport. 2941 2942#### Marking a hardware dataport as cached 2943 2944To map a hardware dataport cached, set the `<instance>.<interface>_hardware_cached` attribute to `true`: 2945 2946 component DisplayDevice { 2947 hardware; 2948 dataport FrameBuffer framebuffer; 2949 } 2950 2951 component DisplayDriver { 2952 ... 2953 dataport FrameBuffer framebuffer; 2954 } 2955 2956 assembly { 2957 composition { 2958 component DisplayDevice display_device; 2959 component DisplayDriver display_driver; 2960 ... 2961 2962 connection seL4HardwareMMIO fbconn( 2963 from display_driver.framebuffer, 2964 to display_device.framebuffer 2965 ); 2966 } 2967 configuration { 2968 ... 2969 display_device.framebuffer_hardware_cached = true; /* <-- set this attribute 2970 * to mark dataport 2971 * as cached 2972 */ 2973 } 2974 } 2975 2976#### Manipulating the cache 2977 2978After writing to a cached hardware dataport, or potentially prior to reading from it, 2979it is necessary to manipulate the cache to ensure a consistent view of the memory 2980between the CPU and any devices. CAmkES provides a function for each hardware dataport 2981for doing cache operations on the range of addresses inside the dataport. 2982 2983For a dataport interface named `framebuffer`, the function that operates on the cache 2984will be 2985 2986```c 2987int framebuffer_cache_op(size_t start_offset, size_t size, dma_cache_op_t cache_op) 2988``` 2989 2990`start_offset` and `size` are the offset in bytes into the dataport to start flushing, 2991and the number of bytes to flush respectively. `cache_op` is one of the three defined 2992cache operations: `DMA_CACHE_OP_CLEAN`, `DMA_CACHE_OP_INVALIDATE`, `DMA_CACHE_OP_CLEAN_INVALIDATE`. 2993The function returns 0 on success and non-zero on error 2994 2995## Templating 2996 2997CAmkES glue code, code automatically introduced into your component system at 2998compile time, is driven by a set of templates. These templates are instantiated 2999with values determined from your input ADL specification. CAmkES templates are 3000written as C code with Python snippets embedded in comments. This is all driven 3001by the [Jinja2](http://jinja.pocoo.org/docs/) templating engine. You can see 3002examples of existing templates in camkes/templates/. 3003 3004The remainder of this section gives advice for people intending to implement 3005their own templates or modify existing templates. If you are attempting to 3006modify the template environment itself, you should instead refer to the 3007[Template Environment](#template-environment) section. 3008 3009### Template Writing 3010 3011Inside a template you write C code as you would normally, but use the following 3012special comments to run Python code: 3013 3014* `/*- execute code -*/` (equivalent of Python's `exec`) 3015* `/*? execute code and replace with result -*/` (equivalent of Python's `eval`) 3016* `/*# a comment to be removed at instantiation #*/` 3017 3018In general, when writing code in a template, refer to the Jinja documentation 3019syntax and functionality. Note that the default Jinja delimiters have been modified 3020to `/*` and `*/` to let syntax highlighting in C work more naturally. 3021 3022Within a given template you have a variable `me` that functions like native 3023Python's `self`. It refers to the object of relevance to the current template. 3024So, for example, during instantiation of the component source file, it refers 3025to the component instance being instantiated. In certain general "top-level" 3026templates, there is no particular "subject." In these templates, for example 3027`camkes-gen.cmake`, `me` will be `None`. 3028 3029The template environment is a limited subset of Python. It is relatively easy 3030to extend, and if you intend to do this you can see how in the 3031[Template Environment](#template-environment) section. Some statements in 3032Python could not be cleanly exposed and so have instead become functions. In 3033particular, be aware of quirks in assertions, lambdas and exceptions. `assert` 3034is available as a function. So instead of writing `assert foo == 1` you would 3035write `assert(foo == 1)`. 3036 3037Lambdas are perhaps more confusing. Instead of writing 3038`lambda x: x.startswith('hello')` you would write 3039`lambda('x: x.startswith(\'hello\')'`. Note that you lose some type safety and 3040expressivity here, but there did not seem to be a nicer way to expose this. 3041Exceptions are now also raised by function. So instead of writing 3042`raise Exception('foo')` you would write `raise(Exception('foo'))`. 3043 3044For the specific functionality available in the template context, it may be 3045helpful to refer to the file camkes/runner/Context.py. Note that in the 3046template context you also have access to the command line options via `options` 3047as well. 3048 3049### Idioms 3050 3051There are certain common operations you may wish to perform inside a template 3052context, for which idioms have developed. This section documents some of these 3053snippets of code that may look unusual when you first encounter them. 3054 3055#### Passing Information Between Templates 3056 3057You often wish to do this with two related templates. For example, in the 3058templates that form each side of a connection you often wish to talk about the 3059same object on both sides. None of the templates currently call the low-level 3060helper functions that enable this directly, but if you do want to invoke them, 3061they are `stash` and `pop`. `stash` lets you save a Python object under a given 3062key name and `pop` retrieves a previously saved Python object by key. Note that 3063these are only usable for passing objects between templates that share related 3064`me` references. 3065 3066#### Generating Symbol Names 3067 3068Within a C template you sometimes need a temporary variable in a context in 3069which user-provided variables may be in scope. That is, you need a named symbol 3070but you need to ensure it doesn't collide with any existing user symbols. To do 3071this you can call the function `c_symbol`. This generates a pseudo-unique name 3072that you can use from then on. For example, 3073 3074```c 3075/*- set my_var = c_symbol() -*/ 3076int /*? my_var ?*/ = 42; 3077... 3078``` 3079 3080`c_symbol` takes an optional string argument that will make that string part of 3081the resulting symbol name. This is helpful for debugging purposes if you want 3082to give someone looking at the instantiated template a visual clue as to the 3083purpose of a temporary variable. 3084 3085#### Subverting Scoping 3086 3087Jinja has some unusual and often counter-intuitive variable scoping rules. 3088Occasionally templates wish to conditionally assign to a variable within the 3089context of a loop or other Jinja block. In these circumstances it can be tricky 3090to get the write to propagate outside the loop. You may see a temporary array 3091and a `do` construct used in these situations: 3092 3093```c 3094/*- set temp = [None] -*/ 3095/*- for .... -*/ 3096 ... 3097 /*- if ... -*/ 3098 /*- do temp.__setitem__(0, True) -*/ 3099 /*- else -*/ 3100 /*- do temp.__setitem__(0, False) -*/ 3101 /*- endif -*/ 3102 ... 3103/*- endfor -*/ 3104/*- set variable_we_want_to_set = temp[0] -*/ 3105``` 3106 3107### Reply Capabilities 3108 3109The seL4 system call, `seL4_Call`, generates transient capabilities called 3110reply capabilities (see the seL4 documentation for more specific details). Care 3111must be taken when writing template code in order to avoid interfering with the 3112functionality of another piece of template code that may have created reply 3113capabilities. If you are not using reply capabilities yourself, there is a 3114simple rule to remember: 3115 3116* always call `camkes_protect_reply_cap()` before performing an operation that 3117 would cause a wait on a synchronous endpoint. 3118 3119This call is idempotent (you can call it multiple times in sequence with no ill 3120effects), though be aware it may modify the contents of your IPC buffer. You 3121do not need to perform this operation when sending on a synchronous endpoint or 3122waiting on a notification, however it _is_ necessary when performing 3123batched system calls like `seL4_ReplyRecv` or `seL4_Call` on a synchronous 3124endpoint. 3125 3126If you are _receiving_ reply capabilities in your own template and calling 3127external functionality before using them, you need to be aware that they can be 3128overwritten when execution is outside your template. To safe guard yourself 3129against this, there is a complementary rule: 3130 3131* always call `camkes_declare_reply_cap(...)` when you have just received a 3132 reply capability. 3133 3134Note that you need to pass this function an empty capability slot into which to 3135save the reply capability if it is about to be overwritten. In order to support 3136saving of this reply capability on demand, CAmkES needs a capability to the 3137current thread's CNode. This needs to be setup by your template code. Some 3138variant of the following code needs to be executed for each thread that could 3139receive a reply capability: 3140 3141```c 3142/*# Allocate a cap to our own CNode. #*/ 3143/*- set cnode = alloc_cap('cnode', my_cnode) -*/ 3144/* Configure a TLS pointer to our own CNode cap. */ 3145camkes_get_tls()->cnode_cap = /*? cnode ?*/; 3146``` 3147 3148When you need to use a reply capability you have protected, you should check 3149the `reply_cap_in_tcb` member of the CAmkES TLS structure and, if the capability 3150is no longer in your TCB, call `camkes_unprotect_reply_cap()` and deal with any 3151possible error that may have occurred. The functional API for dealing with 3152reply capabilities is provided below. Though this is technically part of the 3153[runtime API](#runtime-api), it is included here because user code is never 3154expected to call these functions. 3155 3156**`int camkes_declare_reply_cap(seL4_CPtr shadow_slot)`** (`#include <camkes/tls.h>`) 3157 3158> Identify to the CAmkES library that you are in possession of a reply 3159 capability in your TCB. CAmkES only handles a single reply capability 3160 currently and, as such, you should not call this function when you have 3161 previously declared a pending reply capability you have not yet discarded. 3162 This essentially says to CAmkES, "I have a reply cap in my TCB; please save 3163 it to `shadow_slot` if it is in risk of being deleted." 3164 3165**`void camkes_protect_reply_cap(void)`** (`#include <camkes/tls.h>`) 3166 3167> Guard any potential pending reply capability against deletion by saving it 3168 now. Note that this function accepts no arguments and returns nothing. It is 3169 designed to be called unconditionally from generated code that believes it 3170 may be about to overwrite a reply capability. There is no point providing a 3171 result to the caller because the caller is not the conceptual "owner" of 3172 the capability and does not know how to deal with a failure to protect it. 3173 You should always call this code in your template if you believe a reply 3174 capability could be present and the operation you are about to perform has a 3175 chance of deleting it. 3176 3177**`seL4_Error camkes_unprotect_reply_cap(void)`** (`#include <camkes/tls.h>`) 3178 3179> Discard any information relating to a current pending reply capability. This 3180 is designed to be called by the original declarer of a reply capability when 3181 it is about to use (or discard) that capability. Note that this returns a 3182 potential error that was encountered when some intermediate code tried to 3183 protect the capability and it failed. The return value is essentially a 3184 result from `seL4_CNode_SaveCaller`. This should _only_ be called when you 3185 know the reply cap you need is no longer in your TCB. That is, you should 3186 check the `reply_cap_in_tcb` member of the CAmkES TLS structure to determine 3187 if calling this function is necessary. 3188 3189To get a more concrete idea of how these functions are used, you can refer to 3190the seL4RPCCall connector that uses this mechanism. 3191 3192One final thing to note is that this functionality assumes cooperative 3193templates. There is nothing to prevent a malicious template omitting a call to 3194`camkes_protect_reply_cap()` and wilfully destroying pending reply 3195capabilities. 3196 3197### Template Debugging 3198 3199If you are writing complicated template logic and need to debug during 3200instantiation, you can insert breakpoints into your template. These can be 3201inserted as either `/*- breakpoint() -*/` or `/*? breakpoint() ?*/`. When 3202encountered during instantiation they will drop you into the Python 3203interpreter, from where you can explore `me` and other local variables. 3204 3205When prototyping or debugging more complicated problems it can be helpful to 3206have the ability to run arbitrary Python in the template context. There is some 3207limited support for this, with the functions `exec` and `eval`. These operate 3208like the native Python `exec` and `eval`, but may be a little more fragile. 3209Note that `exec` is a function in this context, not a statement. So where you 3210would normally write `exec 'print \'hello\''` you would write 3211`exec('print \'hello\'')`. 3212 3213Although never advisable in a proper implementation, it is possible to pass 3214arbitrary information between unrelated templates. Similar to the `stash` and 3215`pop` functions described above, there are lower level versions, `_stash` and 3216`_pop` that let you write to and read from a context that propagates across all 3217templates. Note that you can only use this to pass information "forwards" to 3218templates that are instantiated after the one you are calling `_stash` from. 3219 3220## Developers 3221 3222This section is targeted at those intending to modify the CAmkES implementation 3223itself. The information below assumes you are familiar with the features and 3224functionality of CAmkES. 3225 3226If you are modifying the actual sources of any of the CAmkES modules I've 3227attempted 3228to leave helpful comments. I've occasionally used tags in the comments that 3229may help you when grepping and whatnot. They mean: 3230 3231**FIXME** 3232 3233> This is a stop gap piece of functionality that should be replaced 3234 with something more feature complete when time permits. This could also refer 3235 to an existing bug that cannot currently be easily remedied. 3236 3237**HACK** 3238 3239> This code is a bit dubious, but is intentionally written this way to 3240 work around limitations in some other tool outside our control. 3241 3242**MOVE** 3243 3244> This is the wrong place for this piece of functionality. It should 3245 be refactored somewhere else. 3246 3247**PERF** 3248 3249> This code is structured in a counter-intuitive or non-obvious way for 3250 performance reasons. Refactor if you wish, but be aware it may have a 3251 significant impact on runtime. 3252 3253**SLOW** 3254 3255> This code is known to be inefficient, but was deliberately written 3256 this way for simplicity. If you are hitting performance problems and looking 3257 for optimisation opportunities try grepping for this. 3258 3259**TODO** 3260 3261> Some part of the functionality in this section has not yet been 3262 implemented or the code could be improved in some way. 3263 3264**XXX** 3265 3266> There is something out of the ordinary about this piece of code that 3267 should probably be fixed. This is often in cases where I didn't have time to 3268 write a proper **FIXME** or **TODO** comment. 3269 3270### Parser Internals 3271 3272* camkes/parser/* 3273 3274The previous section, [camkes.parser](#camkes.parser), describes the high-level 3275interface to the CAmkES parser. This parser is assembled from a pipeline of 3276lower-level parsers. These are each described as a "stage" in parsing. To 3277understand them, it is necessary to understand a few variants of Abstract 3278Syntax Tree representations that are referred to in the source code. The 3279following representations are described in order from least to most abstract: 3280 3281* **Augmented input** This is not an AST, as such, but rather a tuple of source 3282 data and a set of read files. 3283* **Raw AST** This is a tree of `plyplus.stree`s. 3284* **Augmented AST** This is a list of `plyplus.stree`s with attached 3285 information about their original source data and the file they came from. 3286* **Lifted AST** This is the most abstract programmatic representation of an 3287 input specification and the form developers will come to be most familiar 3288 with. It is a tree of objects from [camkes.ast](#camkes.ast). 3289 3290The various low-level parsers are each responsible for a specific AST 3291transformation, with the high-level parser stringing them all together for ease 3292of use. The low-level parsers are: 3293 3294* **Stage 0** Reads an input file and optionally runs the C pre-processor over 3295 it. This "parser" is really just a more full featured version of the `open` 3296 call. 3297* **Stage 1** Parses input using `plyplus`. Note that this is where the CAmkES 3298 grammer (camkes/parser/camkes.g) comes into play. 3299* **Stage 2** Resolves `import` statements. This parser repeatedly calls back 3300 into the stage 1 parser to parse further sources. Note that from here on, 3301 `import` statements do not appear in the AST. 3302* **Stage 3** Lifts the `plyplus` AST into the objects of 3303 [camkes.ast](#camkes.ast). This is generally the most intensive parse phase 3304 and inherently the most fragile as it encodes much of the semantics of the 3305 CAmkES input language. 3306* **Stage 4** Resolves semantic references. From here on, no 3307 `camkes.ast.Reference`s remain in the AST. 3308* **Stage 5** Collapses `group`s. The `group` keyword is used to colocate 3309 component instances into a single address space. This stage removes groups 3310 from the AST, assigning the same address space to their contained instances. 3311* **Stage 6** Combines multiple assemblies. It is possible for more than one 3312 `assembly` block to be specified in a CAmkES input specification, in which 3313 case the intended assembly is the concatentaion of all of them. This stage 3314 performs that concatenation. 3315* **Stage 7** Flattens component hierarchies. Component instances that are 3316 nested inside other components are hoisted to the top-level assembly by this 3317 stage. 3318* **Stage 8** Resolves attribute references. Settings can be given a value that 3319 references another attribute (using the `<-` operator). This stage resolves 3320 these references to concrete values. 3321* **Stage 9** Freezes the AST. This stage transforms various AST internal data 3322 structures into optimised forms and makes AST modification from this point on 3323 impossible. 3324 3325With this information, looking back at the high-level parser, one can see that 3326it simply chains these stages together. It is possible to programmatically 3327construct a differing or partial parser by composing the low-level parsers in a 3328different manner. 3329 3330#### Pre-Compiled Templates 3331 3332 * camkes/runner/Renderer.py 3333 3334The Jinja templating engine works by compiling template code to native Python 3335code, which it then runs to produce the generated output. This compilation to 3336Python code is normally performed in each execution. To speed up this process, 3337when caching is enabled, the templates are compiled to the cache directory. In 3338future executions, template rendering optimistically fetches pre-compiled 3339templates from this cache. On a cache miss, it falls back to the original 3340template sources. 3341 3342### Template Context 3343 3344The code that renders the templates themselves is all contained under the 3345runner directory in the CAmkES module. While the rendering itself is driven 3346from Renderer.py, the more relevant file is actually Context.py. The 3347`new_context` function returns a dictionary that defines the template 3348environment, that is, what local variables are present in the template at 3349instantiation time. 3350 3351There is some fairly complex functionality here aimed at providing nice 3352abstractions to template authors. In particular, `alloc_obj`, `alloc_cap`, 3353`stash`, `pop` and `guard` are intended to provide an abstraction for the 3354template author to pass variables between templates. Refer to the comments in 3355this file to understand more about the template context. 3356 3357Extending the context can be done by adding more items to this dictionary and 3358there aren't many gotchas here. If you're doing something more complicated than 3359exposing an existing built-in and having difficulty you may find the 3360implementations of `breakpoint` or `exec` informative as examples. 3361 3362### Core Libraries 3363 3364CAmkES has a notion of "core libraries" as the set of seL4 libraries that may 3365be relied on to be available from within the template context. These are 3366defined within the camkes-gen.cmake template. This set of libraries has been extended on demand to cover all 3367base seL4 infrastructure. This can be freely expanded to cover more libraries 3368with no expected surprises. 3369 3370Be aware that these libraries will be unconditionally depended upon and linked 3371into all CAmkES components. That is, the user's lists of libraries defined in 3372their application CMakeLists.txt will all be silently extended to include the core 3373libraries. 3374 3375### Testing 3376 3377CAmkES has a set of unit tests and a set of integration tests. The unit tests 3378are structured per-module, with each module's tests in a subdirectory of its 3379source: 3380 3381 * camkes/ast/tests 3382 * camkes/internal/tests 3383 * camkes/parser/tests 3384 * camkes/runner/tests 3385 * camkes/templates/tests 3386 3387The unit tests use Python's 3388[unittest](https://docs.python.org/2/library/unittest.html) framework. The 3389simplest way to execute them is from the top-level wrapper script: 3390 3391```bash 3392./alltests.py 3393``` 3394 3395Alternatively, any finer granularity of test cases may be selected: 3396 3397```bash 3398# Run all AST unit tests 3399./camkes/ast/tests/runall.py 3400 3401# Run only AST hashing assumption tests 3402./camkes/ast/tests/runall.py TestHashingAssumptions 3403 3404# Run only the specific test for hashing None 3405./camkes/ast/tests/runall.py TestHashingAssumptions.test_none 3406``` 3407 3408The integration tests are contained in the CAmkES project repository under the 3409directory tests/. Again, the simplest way to execute these is with a wrapper 3410script: 3411 3412```bash 3413./tests/run-all.py 3414``` 3415 3416Alternatively, you can run individual integration tests: 3417 3418```bash 3419# Test simple RPC 3420./tests/arm-simple.tcl 3421``` 3422