1(*
2 * Copyright 2014, NICTA
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(NICTA_GPL)
9 *)
10
11chapter {* \label{sec:examples}Example Systems *}
12
13(*<*)
14theory Examples_CAMKES
15imports
16  Types_CAMKES
17  Library_CAMKES
18  Wellformed_CAMKES
19begin
20(*>*)
21
22subsection {* \label{subsec:echo}Echo *}
23text {*
24  The following ADL and IDL describe an example system involving two
25  components, client and echo. There is a single connection between them, from
26  a procedure @{text client.s} that client requires to a procedure
27  @{text echo.s} that echo provides. The system is depicted in Figure
28  \ref{fig:echo}.
29
30  \begin{figure}[h]
31  \begin{center}
32  \caption{\label{fig:echo}Echo example}
33  \includegraphics[width=0.6\textwidth]{imgs/echo}
34  \end{center}
35  \end{figure}
36*}
37
38text {*
39  The procedure used in this system is expressed by the following IDL:
40
41\begin{verbatim}
42  procedure Simple {
43    string echo_string(in string s);
44    int echo_int(in int i);
45    void echo_parameter(in int pin, out int pout);
46  };
47\end{verbatim}
48
49  The representation of this in Isabelle is quite similar:\footnote{The
50  procedure parameter type @{text int}
51  is a synonym for
52  @{term integer} and is
53  therefore not modelled in Isabelle.}
54*}
55definition
56  simple :: procedure (* Sourced from Simple.idl4 *)
57where
58  "simple \<equiv> [
59    \<lparr> m_return_type = Some (Primitive (Textual String)), m_name = ''echo_string'',
60      m_parameters = [
61        \<lparr> p_type = Primitive (Textual String),
62          p_direction = InParameter,
63          p_name = ''s'' \<rparr>
64      ] \<rparr>,
65    \<lparr> m_return_type = Some (Primitive (Numerical Integer)), m_name = ''echo_int'',
66      m_parameters = [
67        \<lparr> p_type = Primitive (Numerical Integer),
68          p_direction = InParameter,
69          p_name = ''i'' \<rparr>
70      ] \<rparr>,
71    \<lparr> m_return_type = None, m_name = ''echo_parameter'', m_parameters = [
72        \<lparr> p_type = Primitive (Numerical Integer),
73          p_direction = InParameter,
74          p_name = ''pin'' \<rparr>,
75        \<lparr> p_type = Primitive (Numerical Integer),
76          p_direction = InParameter,
77          p_name = ''pout'' \<rparr>
78      ] \<rparr>
79  ]"
80
81text {*
82  Each component of the system is described by a separate IDL representation:
83
84\begin{verbatim}
85  component Client {
86    control;
87    uses Simple s;
88  }
89\end{verbatim}
90
91\begin{verbatim}
92  component Echo {
93    provides Simple s;
94  }
95\end{verbatim}
96
97  These generate the following formal representations in Isabelle:
98*}
99definition
100  client :: component (* Sourced from Client.camkes *)
101where
102  "client \<equiv> \<lparr>
103    control = True,
104    requires = [(''s'', simple)],
105    provides = [],
106    dataports = [],
107    emits = [],
108    consumes = [],
109    attributes = []
110  \<rparr>"
111
112definition
113  echo :: component (* Sourced from Echo.camkes *)
114where
115  "echo \<equiv> \<lparr>
116    control = False,
117    requires = [],
118    provides = [(''s'', simple)],
119    dataports = [],
120    emits = [],
121    consumes = [],
122    attributes = []
123  \<rparr>"
124
125text {*
126  A @{term composition} block is used to combine these elements into the
127  complete system. There are no attributes in this simple system so the
128  @{term configuration} block of the @{term assembly} can be omitted. The two
129  components are connected via a seL4RPC connection. Note that the underlying
130  implementation mechanism of this seL4RPC connection is abstracted.
131
132\begin{verbatim}
133  assembly {
134    composition {
135      component Echo echo;
136      component Client client;
137      connection seL4RPC simple(from client.s, to echo.s);
138    }
139  }
140\end{verbatim}
141
142  Once again the generated Isabelle formalism looks similar:
143*}
144definition
145  system :: assembly (* Sourced from simple.camkes *)
146where
147  "system \<equiv> \<lparr>
148    composition = \<lparr>
149      components = [(''echo'', echo),(''client'', client)],
150      connections = [(''simple'', \<lparr>
151        conn_type = seL4RPC,
152        conn_from = [(''client'', ''s'')],
153        conn_to = [(''echo'', ''s'')]
154      \<rparr>)]
155    \<rparr>,
156    configuration = None
157  \<rparr>"
158
159text {*
160  Since our wellformedness conditions are executable, we can now prove that
161  this example is a wellformed assembly by evaluation.
162*}
163lemma "wellformed_assembly system" by eval
164
165subsection {* \label{subsec:events}Events *}
166text {*
167  \begin{figure}[h]
168  \begin{center}
169  \caption{\label{fig:event}Event example}
170  \includegraphics[width=0.6\textwidth]{imgs/event}
171  \end{center}
172  \end{figure}
173
174  The following example shows a system using a single event to provide
175  asynchronous communication between two components. The identifier assigned
176  to the event, @{text 1}, is unimportant in this example as there is only
177  one event in use.
178*}
179definition
180  signal :: event
181where
182  "signal \<equiv> 1"
183
184text {*
185  The active component @{text emitter} generates events of the type
186  @{term signal}.
187*}
188definition
189  emitter :: component
190where
191  "emitter \<equiv> \<lparr>
192    control = True,
193    requires = [],
194    provides = [],
195    dataports = [],
196    emits = [(''event'', signal)],
197    consumes = [],
198    attributes = []
199  \<rparr>"
200
201text {*
202  The component @{text consumer} expects to receive these events. When a
203  component is defined to consume an event, a function for registering a
204  callback for this event is made available to the component. The component
205  is initialised at runtime with no callback registered to allow it to do
206  any necessary setup without needing to guard against concurrency. Thus,
207  even when consuming components are conceptually passive they are usually
208  specified as active (@{text "control = True"}) with an entry function that
209  performs some initialisation and then registers an event handler.
210*}
211definition
212  consumer :: component
213where
214  "consumer \<equiv> \<lparr>
215    control = True,
216    requires = [],
217    provides = [],
218    dataports = [],
219    emits = [],
220    consumes = [(''event'', signal)],
221    attributes = []
222  \<rparr>"
223
224text {*
225  The system assembly looks similar to that shown in Section
226  \ref{subsec:echo}, but an asynchronous connector is used between the
227  components.
228*}
229definition
230  event_system :: assembly
231where
232  "event_system \<equiv> \<lparr>
233    composition = \<lparr>
234      components = [(''source'', emitter), (''sink'', consumer)],
235      connections = [(''simpleEvent1'', \<lparr>
236        conn_type = seL4Asynch,
237        conn_from = [(''source'', ''event'')],
238        conn_to = [(''sink'', ''event'')]
239      \<rparr>)]
240    \<rparr>,
241    configuration = None
242  \<rparr>"
243
244text {*
245  Again, wellformedness is proved easily by evaluation.
246*}
247lemma "wellformed_assembly event_system" by eval
248
249subsection {* \label{subsec:dataport}Dataport Usage *}
250text {*
251  \begin{figure}[h]
252  \begin{center}
253  \caption{\label{fig:dataport}Dataport example}
254  \includegraphics[width=0.6\textwidth]{imgs/dataport}
255  \end{center}
256  \end{figure}
257
258  The following example demonstrates the use of a shared memory region, referred
259  to as a dataport in CAmkES. It also uses one of the key aspects of a component
260  platform, component re-use. First the definition of a simple component that
261  uses two dataports:
262*}
263definition
264  data_client :: component
265where
266  "data_client \<equiv> \<lparr>
267    control = True,
268    requires = [],
269    provides = [],
270    dataports = [(''d1'', None), (''d2'', None)],
271    emits = [],
272    consumes = [],
273    attributes = []
274  \<rparr>"
275
276text {*
277  By instantiating this component twice (once as @{text comp1} and once as
278  @{text comp2})
279  the system contains two identical components. The assembly below connects the
280  first dataport of @{text comp1} to the second dataport of
281  @{text comp2} and vice versa.
282  It is possible to specify a system that instantiates @{term data_client} once and
283  connects one of the instance's dataports to the other, but there is nothing to
284  be gained from a component communicating with itself via shared memory.
285*}
286definition
287  data_system :: assembly
288where
289  "data_system \<equiv> \<lparr>
290    composition = \<lparr>
291      components = [(''comp1'', data_client), (''comp2'', data_client)],
292      connections = [(''simple1'', \<lparr>
293        conn_type = seL4SharedData,
294        conn_from = [(''comp1'', ''d1'')],
295        conn_to = [(''comp2'', ''d2'')]
296      \<rparr>), (''simple2'', \<lparr>
297        conn_type = seL4SharedData,
298        conn_from = [(''comp2'', ''d1'')],
299        conn_to = [(''comp1'', ''d2'')]
300      \<rparr>)]
301    \<rparr>,
302    configuration = None
303  \<rparr>"
304
305text {* The data port example is wellformed: *}
306lemma "wellformed_assembly data_system" by eval
307
308subsection {* \label{subsec:terminal}Secure Terminal *}
309text {*
310  This section presents a more realistic component system as a prototype of a
311  secure terminal. Two components are each given a separate region of a text
312  terminal to which they can write character data. They accomplish this by using
313  a connection to a third, trusted component that manages the terminal.
314
315  \begin{figure}[h]
316  \begin{center}
317  \caption{\label{fig:terminal}Terminal example}
318  \includegraphics[width=0.8\textwidth]{imgs/terminal}
319  \end{center}
320  \end{figure}
321
322  The interface for writing to the terminal takes coordinates to write to and a
323  single character to write. The coordinates are relative to the caller's
324  dedicated region. That is, (0, 0) represents the upper left corner of the
325  caller's region, not the terminal as a whole. The method @{text put_char}
326  returns 0 on success and non-zero if the coordinates are out of range.
327*}
328definition
329  display :: procedure
330where
331  "display \<equiv> [
332    \<lparr> m_return_type = Some (Primitive (Numerical uint32_t)), m_name = ''put_char'',
333      m_parameters = [
334        \<lparr> p_type = Primitive (Numerical uint32_t),
335          p_direction = InParameter,
336          p_name = ''x'' \<rparr>,
337        \<lparr> p_type = Primitive (Numerical uint32_t),
338          p_direction = InParameter,
339          p_name = ''y'' \<rparr>,
340        \<lparr> p_type = Primitive (Numerical uint32_t),
341          p_direction = InParameter,
342          p_name = ''data'' \<rparr>
343      ] \<rparr> ]"
344
345text {*
346  The trusted component that manages the terminal is passive and executes only
347  in response to @{text put_char} calls from its clients. The component
348  described below supports exactly two components. This is a case where a more
349  flexible definition would be possible using interface arrays as described in
350  Section \ref{subsubsec:iarrays}.
351*}
352definition
353  manager :: component
354where
355  "manager \<equiv> \<lparr>
356    control = False,
357    requires = [],
358    provides = [(''domain1'', display), (''domain2'', display)],
359    dataports = [],
360    emits = [],
361    consumes = [],
362    attributes = []
363  \<rparr>"
364
365text {*
366  The definition of the client adds an attribute so the execution can branch
367  based on which instance of the component is running, but the instances could
368  equally well execute exactly the same code and have their (identical) output
369  written to the two distinct regions by the manager.
370*}
371definition
372  terminal_client :: component
373where
374  "terminal_client \<equiv> \<lparr>
375    control = True,
376    requires = [(''d'', display)],
377    provides = [],
378    dataports = [],
379    emits = [],
380    consumes = [],
381    attributes = [(''ID'', Primitive (Numerical Integer))]
382  \<rparr>"
383
384text {*
385  Each client is connected to a single interface of the manager.
386*}
387definition
388  channel1 :: connection
389where
390  "channel1 \<equiv> \<lparr>
391    conn_type = seL4RPC,
392    conn_from = [(''client1'', ''d'')],
393    conn_to = [(''manager'', ''domain1'')]
394  \<rparr>"
395definition
396  channel2 :: connection
397where
398  "channel2 \<equiv> \<lparr>
399    conn_type = seL4RPC,
400    conn_from = [(''client2'', ''d'')],
401    conn_to = [(''manager'', ''domain2'')]
402  \<rparr>"
403
404definition
405  comp :: composition
406where
407  "comp \<equiv> \<lparr>
408    components = [(''manager'', manager),
409                  (''client1'', terminal_client),
410                  (''client2'', terminal_client)],
411    connections = [(''channel1'', channel1),
412                   (''channel2'', channel2)]
413  \<rparr>"
414
415text {*
416  Each client is given a unique identifier so it can distinguish itself. As
417  noted above, this is not necessarily required in all systems with multiple
418  instantiations of a single component.
419*}
420definition
421  conf :: configuration
422where
423  "conf \<equiv> [(''client1'', ''ID'', ''1''),
424           (''client2'', ''ID'', ''2'')]"
425
426definition
427  terminal :: assembly
428where
429  "terminal \<equiv> \<lparr>
430    composition = comp,
431    configuration = Some conf
432  \<rparr>"
433
434text {*
435  Wellformedness for this more complex example is easy as well.
436*}
437lemma "wellformed_assembly terminal" by eval
438
439(* An example with an unsatisfied required interface. This should be provable
440 * to be not wellformed.
441 *)
442(*<*)locale FAIL_MissingRequires begin(*>*)
443(*<*)
444(* This example is just here as a sanity check and not
445 * particularly relevant for the docs.
446 *)
447definition
448  x :: component
449where
450  "x \<equiv> \<lparr>
451    control = undefined,
452    requires = [(undefined, undefined)], (* 1 required interface...*)
453    provides = undefined,
454    dataports = undefined,
455    emits = undefined,
456    consumes = undefined,
457    attributes = undefined
458  \<rparr>"
459
460definition
461  broken_assembly :: assembly
462where
463  "broken_assembly \<equiv> \<lparr>composition = \<lparr>
464    components = [(undefined, x)],
465    connections = [] (*... that is unsatisfied. *)
466  \<rparr>, configuration = undefined\<rparr>"
467
468lemma "\<not> wellformed_assembly broken_assembly"
469  apply (unfold wellformed_assembly_def)
470  apply (subst de_Morgan_conj)
471  apply (rule disjI1)
472  apply (unfold wellformed_composition_def broken_assembly_def, simp)
473  apply (unfold refs_valid_composition_def
474                refs_valid_components_def
475                refs_valid_procedures_def
476                x_def ex_one_def)
477  apply fastforce
478 done
479(*>*)
480(*<*)end(*>*)
481
482(*<*)locale FAIL_Empty begin(*>*)
483(*<*)
484(* This example is just here as a sanity check and not
485 * particularly relevant for the docs.
486 *)
487definition
488  broken_assembly :: assembly
489where
490  "broken_assembly \<equiv> \<lparr> composition = \<lparr>
491    components = [],
492    connections = undefined
493  \<rparr>, configuration = undefined \<rparr>"
494
495lemma "\<not>wellformed_assembly broken_assembly"
496  apply (unfold wellformed_assembly_def)
497  apply (case_tac "wellformed_composition (composition broken_assembly)")
498   apply (unfold broken_assembly_def)
499   apply (frule wellformed_composition_is_nonempty)
500   apply simp+
501 done
502(*>*)
503(*<*)end(*>*)
504
505(*<*)
506lemma "\<not>wellformed_assembly \<lparr> composition = \<lparr>
507    components = [(''foo'', undefined), (''foo'', undefined)],
508    connections = undefined
509  \<rparr>, configuration = undefined \<rparr>"
510  by (simp add:wellformed_assembly_def wellformed_composition_def)
511
512lemma "\<not>wellformed_assembly \<lparr> composition = \<lparr>
513    components = undefined,
514    connections = [(''foo'', undefined), (''foo'', undefined)]
515  \<rparr>, configuration = undefined \<rparr>"
516  by (simp add:wellformed_assembly_def wellformed_composition_def)
517
518lemma "\<not>wellformed_assembly \<lparr> composition = \<lparr>
519    components = [(''foo'', undefined)],
520    connections = [(''foo'', undefined)]
521  \<rparr>, configuration = undefined \<rparr>"
522  by (simp add:wellformed_assembly_def wellformed_composition_def)
523
524(* Catch previous issue (\<exists>! x \<in> xs::set \<noteq> \<exists>1 x \<in> xs::list) *)
525lemma "\<not>wellformed_assembly \<lparr> composition = \<lparr>
526    components = [(''foo'', \<lparr>
527      control = undefined,
528      requires = [(''bar'', undefined)],
529      provides = undefined,
530      dataports = undefined,
531      emits = undefined,
532      consumes = undefined,
533      attributes = undefined \<rparr>)],
534    connections = [(''bar'', \<lparr>
535      conn_type = undefined,
536      conn_from = [(''foo'', ''bar'')],
537      conn_to = undefined \<rparr>),
538    (''baz'', \<lparr>
539      conn_type = undefined,
540      conn_from = [(''foo'', ''bar'')],
541      conn_to = undefined \<rparr>)]
542  \<rparr>, configuration = undefined \<rparr>"
543  by (simp add:wellformed_assembly_def wellformed_composition_def refs_valid_components_def
544      refs_valid_composition_def refs_valid_procedures_def ex_one_def)
545
546lemma "\<not>wellformed_procedure []"
547  by (simp add:wellformed_procedure_def)
548(*>*)
549
550(*<*)end(*>*)
551