blob: 3bd1055829c1d75ac19f68e7197c128cc3359b7c [file] [log] [blame]
Mate Toth-Palf2861772024-08-01 13:18:30 +02001.. SPDX-License-Identifier: BSD-3-Clause
2.. SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
3
4###############
5EL0 apps in RMM
6###############
7
8****
9Goal
10****
11
12The goal of introducing EL0 app support in TF-RMM is to improve security by
13minimizing the amount of code running in privileged mode. This is achieved by
14deprivileging parts of RMM to run at EL0 using the Virtualization Host
15Extensions (VHE). This approach is especially desirable for code pulled in from
16external projects (like Mbed TLS), as such components are often complex and
17sensitive. RMM apps now run at EL0 using the EL2&0 translation regime, with the
18CPU configured such that an eret instruction in EL2 transitions directly to EL0,
19and the target EL of an SVC instruction is EL2. Additionally, each EL0 app has
20its own isolated address space, which not only improves fault isolation but also
21helps mitigate speculation-based side channels, allowing secrets within apps to
22be better protected from speculative execution. This isolation mechanism also
23lays the groundwork for future side-channel mitigations and facilitates their
24deployment. Overall, this scheme is especially useful for sand-boxing complex
25and sensitive code at EL0 and increasing the robustness of RMM.
26
27|RMM app EL0|
28
29This design document covers the various aspects of the implementation of the EL0
30app support in RMM.
31
32
33*********************
34Building app binaries
35*********************
36
37The RMM app's code is in the ``app`` directory, and they may link to
38libraries from the ``lib`` directory. RMM apps use a common linker script that
39contains a few predefined section. The RMM app cmake file first compiles and
40links the RMM app elf binary. Then the python script ``app/gen_app_bin.py``
41is called that extracts the section contents along with address and size
42information. Then this information is used to generate a bin file. The bin file
43is a concatenation of the following:
44
45+----------------+-------------------------------------+
46| 1 page size of | 8 bytes padding (explained later) |
47| header +-------------------------------------+
48| | magic |
49| +-------------------------------------+
50| | header version |
51| +-------------------------------------+
52| | app_name |
53| +-------------------------------------+
54| | app id |
55| +-------------------------------------+
56| | app_len |
57| +-------------------------------------+
58| | section 1 offset |
59| +-------------------------------------+
60| | section 1 size |
61| +-------------------------------------+
62| | ... |
63| +-------------------------------------+
64| | section n offset |
65| +-------------------------------------+
66| | section n size |
67| +-------------------------------------+
68| | magic |
69| +-------------------------------------+
70| | Padding |
71+----------------+-------------------------------------+
72| content of section 1 |
73+------------------------------------------------------+
74| ... |
75+------------------------------------------------------+
76| content of section n |
77+------------------------------------------------------+
78
79The number and order of sections in an RMM app elf/binary is hardcoded in the
80linker script, the python script that does the extraction of section content,
81and in the header definition.
82
83The RMM app bin size is padded to be a multiple of page size.
84
85************************
86Building final RMM image
87************************
88
89The RMM core code is built and linked using its own linker script. Then objcopy
90is called on the resulting elf to extract the sections to an img file. Then the
91bin files for the RMM apps are built as described above. The final RMM image
92is created concatenating the following elements by the python script
93``app/bundle_app_rmm.py``:
94
95* The first RMM app bin. The first 8 byte padding of the header is updated to a
96 ``BL`` (branch with link) instruction, followed by 4 bytes of padding. This
97 allows the offset of the first meaningful field - the section offsets in the
98 app header - to remain consistent with its position in the original app
99 binary. The ``BL`` instruction branches to the start of the text section in
100 the RMM core img. The ``BL`` instruction uses ``PC`` relative offset to encode
101 the branch target, so the instruction can be calculated when the bundled image
102 is assembled. The return value that is saved in the Link Register by the
103 ``BL`` instruction is used by RMM core to determine the memory address of the
104 header of the first app in the bundle.
105* The rest of the RMM app bins (if any) unmodified.
106* The RMM core img file aligned to 64KB offset to meet ELF loader requirements.
107
108The packaged RMM binary must be loaded at a 64KB-aligned physical address to
109ensure that the RMM core itself is also 64KB-aligned. This alignment requirement
110stems from the use of a 1:1 virtual-to-physical address mapping for the RMM
111core. In contrast, EL0 apps run at virtual addresses determined at compile time,
112which are already 64KB-aligned. As a result, the physical address alignment of
113app binaries is not significant.
114
115The number of RMM apps expected by RMM core is hardcoded in RMM core.
116The RMM app headers are parsed by the RMM core during the coldboot phase. The
117RMM app headers contain a magic value, so if less than the expected number of
118RMM apps is added to the final bin that can be detected, then boot fails in that
119case. If more than the hardcoded number of RMM apps is present, RMM boot fails
120as well.
121
122|RMM bin generation|
123
124****************
125RMM App Instance
126****************
127
128In this document app instance refers to an execution context, along with the
129necessary memory that is allocated for it. In operating system terms, a thread
130is analogous to an EL0 App instance.
131
132To manage and run an RMM app instance, RMM core needs memory for the following
133purposes:
134
1351. RMM app context: A single page of memory for use by the context switch logic
136 to back up registers. This memory page acts as app's CPU context storage when
137 it is not scheduled. This page is mapped in the APP VA space as well, with
138 permissions that it is only accessible by privileged execution (i.e. EL2).
139 The mapping is necessary because, on exit from an RMM app to the RMM core,
140 the RMM app's virtual address (VA) space is still active and set up in the
141 High VA region, while the RMM core's VA space is not yet available. To switch
142 back to RMM Core High VA space, the general purpose registers need to be
143 backed up beforehand. To enable this, the app context page is mapped at the
144 beginning of the apps VA space (without UNPRIV access). This fixed mapping
145 allows the context switch code to use a hardcoded address for the register
146 backup. Consequently, the EL0 apps accessible address space begins at a 4KB
147 offset from the start of the High VA region
148
1492. A memory page that is used to exchange RMM app specific data between the
150 RMM app and the RMM app caller mapped both in EL2 and in EL0. (Also
151 referenced as shared page by this document.)
152
1533. Metadata for the RMM app (``struct app_data_cfg``). This includes
154
155 * xlat library structures including the pointer to the pagetable for the RMM
156 app.
157 * entry point
158 * PA of the app_reg_ctx
159 * PA of the shared page
160
1614. Page containing the pagetable for the EL0 memory mappings (currently the RMM
162 app has a limited 2MB VA space)
163
1645. Stack for RMM app.
165
1666. Heap for RMM app.
167
168In the current implementation there are 3 possible locations where the above
169mentioned data is stored:
170
171a. In statically allocated per-cpu buffers.
172b. In the rec structure for a REC and in the rec aux pages
173c. In the pdev structure for a PDEV object in the pdev aux pages
174
175In case of *b.* and *c.* the memory pages are delegated by the host.
176
177Note that this introduces a limitation on the stack/heap of the RMM apps, as the
178max count of aux pages is limited, and RMM core is already using some of them.
179
180****************
181RMM App VA space
182****************
183
184The RMM app va space (as it is configured in the xlat library) contains the
185following regions:
186
187 * Single page for the RMM app context (Transient)
188 * RMM app text
189 * RMM app RO data
190 * RMM app data
191 * RMM app BSS
192 * RMM app Shared (Transient)
193 * RMM app heap (Transient)
194 * RMM app stack (Transient)
195
196The pages that are mapped in the transient region are private to the RMM app
197instance. As all the other regions are common, it is possible to initialise the
198xlat_ctx_cfg used by apps during RMM boot.
199
200**************************
201Initialising RMM app pages
202**************************
203
204The pages that are instance specific (`RMM App Instance`_) needs to be initialised
205on creating an RMM app instance.
206
207As it is possible that the pages are delegated by the host, and the pages need
208to be mapped dynamically using slot-buffer framework, a new slot is added to the
209slot buffer. When initialising such pages, the page under initialisation is
210mapped into this new slot, and unmapped after initialising.
211
212The ``app_init_data`` function receives an array of physical addresses of
213the pages to be used for the RMM app. In case of initialisation the code checks
214whether the PA is in the range of the RMM core's rw PA range. If so, it can
215write to it directly. If not, the slot buffer mechanism is used as described
216above.
217
218Mappings when using AUX pages for RMM app RW memory:
219
220|RMM app memory aux|
221
222Mappings when using statically allocated pages for RMM app RW memory:
223
224|RMM app memory static|
225
226*********************
227RMM App Service Calls
228*********************
229
230Since the apps are running at EL0, it cannot perform some privileged operations
231like communicate with EL3 or copy data from NS host buffer etc. RMM provides
232some services for RMM apps (like printing). The services are required to have
233the signature
234
235
236 .. code-block:: bash
237
238 typedef uint64_t (*app_service_func)(struct app_data_cfg *app_data,
239 unsigned long arg0,
240 unsigned long arg1,
241 unsigned long arg2,
242 unsigned long arg3);
243
244Services are expected to be thread safe.
245
246Some services can call other apps to perform its functionality (like PRNG). But
247this kind of nesting is limited to one other app to avoid interdependencies
248between apps.
249
250Services are stored in a function pointer array. There is a single array in the
251system.
252
253The RMM app that calls a service must do an SVC with a predefined immediate
254value. The index of the service to be executed is selected by the value of the
255X0 register.
256
257The el0_app framework calls app_enter in a loop. It exits the loop
258if the SVC immediate value reports function return or yield (in future).
259
260********************
261Debugging RMM on FVP
262********************
263
264The RMM core text section offset is changed due to the app binaries being
265prepended before the RMM core img. The ``bundle_app_rmm.py`` script prints the
266text section offset in the binary which should be added to the RMM load address
267when loading the elf in the debugger for symbols. The script output is in the
268file ``<build_dir>/<build_type>/bundle_app_out.txt``. The offset is also printed
269out during the build process.
270
271The RMM apps are linked to the VA address that they are going to be loaded by
272RMM core, so the RMM app symbols needs to be loaded in the debugger with offset
273``0x0``
274
275*******************
276RMM Fake Host Build
277*******************
278
279In case of the fake host build, the applications are compiled as a standalone
280elf file. The RMM core is compiled to the elf file ``rmm_core.elf``. The path
281to the RMM app elf files are passed to ``rmm_core.elf`` as a command line
282parameter, along with the ID of the RMM apps. The first time the main RMM
283process calls ``app_init_data`` the process is forked, the image of the
284requested RMM app is loaded in the new process, and a named-pipe connection is
285established between the two processes. When the RMM app process is created, for
286each ``app_init_data`` (including the first call) a new thread is created. The
287main thread in the RMM app process is responsible for dispatching the RMM app
288calls and returns between the main RMM process and the RMM app thread.
289
290There is no shared memory between the main and the RMM app processes, memory
291sharing is emulated by sending over the content of the main process's "shared
292page" to the RMM app thread on an ``app_run`` call, and sending back the content
293of the RMM app thread's "shared page" on RMM app function return.
294
295|RMM app host|
296
297The help of the main process:
298
299 .. code-block::
300
301 $ rmm_core.elf --help
302 Run RMM on the host
303
304 Usage: rmm_core.elf [-h|--help] [app_id app_elf [...]]
305
306 Arguments:
307 -h, --help print this message and exit.
308 app_id Integer value of app id of the app.
309 app_elf path to the app's elf file.
310
311
312An example call:
313
314 .. code-block:: bash
315
316 $ Debug/rmm_core.elf \
317 103 Debug/rmm_app_random.elf \
318 211 Debug/rmm_app_attestation.elf
319
320*************************
321RMM Apps currently in RMM
322*************************
323
324Currently there are 2 RMM apps in RMM:
325
326 - attestation: Used for doing attestation related tasks, like attestation
327 token generation and hash calculation
328 - random: A small application with a pseudo random number generator, either
329 seeded with a true random sequence, or with input from an already initialised
330 random RMM app.
331
332Currently both apps have their own build of Mbed TLS linked to them.
333
334There is an instance of random number RMM app initialised for each of the CPUs.
335There is also an attestation app initialised for each CPU for doing RIM
336extension, and there is an RMM app instance initialised for each REC, to do
337measurement extend and attestation token generation.
338
339The attestation RMM app uses the random RMM app via a service. The attestation
340RMM app reaches the EL3 interface (for requesting realm attestation key
341and platform token) via an RMM app service.
342
343The layout of the RMM apps can be seen on the image below:
344
345|RMM app layout|
346
347Note: To be continued with DA related RMM apps
348
349************************
350Directory layout of apps
351************************
352
353 .. code-block:: bash
354
355 .
356 └── app
357 ├── attestation
358 ├── el0_app
359 ├── mbedtls_attest # Library (EL0)
360 ├── qcbor # Library (EL0)
361 ├── src # Implementation of the attestation RMM app (EL0)
362 └── t_cose # Library (EL0)
363 └── rmm_stub # Helper function for using the Attestation RMM app (EL2)
364 ├── common
365 ├── el0_app # Common code that is used by multiple apps (EL0)
366 ├── framework # Framework for calling an app and provide app services (EL2)
367 ├── include
368 └── rmm_svc # Implementation of RMM services provided to apps (EL2)
369 └── random
370 ├── el0_app
371 ├── mbedtls_random # Library (EL0)
372 └── src # Implementation of the Random RMM app (EL0)
373 └── rmm_stub # Helper function for using the Random RMM app (EL2)
374
375**********************************************
376Proposed Enhancements to the RMM App Framework
377**********************************************
378
379#. Shared Memory for ``fake_host``
380
381 Implement support for shared memory to enable communication between processes
382 within the ``fake_host`` environment.
383
384#. Configurable App ID
385
386 Currently, the App ID is hardcoded. There is a suggestion to derive it from a
387 header generated as part of the configuration. This approach can be explored
388 further.
389
390#. App BSS Allocation
391
392 Consider whether the App BSS should be allocated dynamically. Alternatively,
393 RMM could reserve a dedicated section for app BSS and allocate memory from
394 there.
395
396#. Common Binary Generation Logic
397
398 The logic for generating app bin files can be consolidated or reused.
399
400#. Avoid Unnecessary Remapping of Shared Buffers
401
402 When shared buffers are located in auxiliary granules, remapping may not be
403 needed if the granules are already mapped.
404
405#. Unify VBAR Usage
406
407 Currently, separate VBARs are set up for the app and RMM. Evaluate whether a
408 single VBAR could be used to simplify the design.
409
410#. Lightweight App Threading in ``fake_host``
411
412 Replace full PThreads with a lighter-weight threading model for running apps
413 in the ``fake_host`` test environment.
414
415#. Enable FEAT_PAN/PAN3 for EL0
416
417 Ensure that the appropriate Privileged Access Never (PAN) features (including
418 PAN3) are correctly set when executing code at EL0.
419
420#. Hardening ``app_services``
421
422 The ``app_services`` interface should be hardened. This includes:
423
424 - Clear documentation of function arguments and return codes
425 - Proper validation of input parameters
426
427#. Harden ``rmm_stub`` and Define Conventions
428
429 The ``rmm_stub`` must validate all return values from EL0 apps. Also, define
430 a consistent convention for parameter passing between the EL0 app and the
431 stub to support future extensibility.
432
433#. Optional TLBI on EL0 Entry
434
435 In certain cases, Translation Lookaside Buffer Invalidate (TLBI) may not be
436 needed when entering an EL0 app. This optimization is already noted in the
437 code and should be validated and documented.
438
439#. Post-Build App Repackaging
440
441 Explore the possibility of repackaging EL0 apps after the main RMM binary is
442 built.
443
444#. Unmap heap pages allocated to app from RMM high VA space.
445
446 When heap is allocated from REC aux granules, the aux granules are always
447 mapped when the REC is in use and the app is not running. Even if app is
448 running stack and pages table page not needed to be mapped, and unless some
449 data is being shared between core and app via heap, heap pages are not needed
450 to be mapped
451
452.. |RMM app EL0| image:: ./diagrams/rmm_app_EL0.drawio.png
453.. |RMM bin generation| image:: ./diagrams/rmm_bin_generation.drawio.png
454.. |RMM app memory aux| image:: ./diagrams/rmm_app_memory_aux.drawio.png
455.. |RMM app memory static| image:: ./diagrams/rmm_app_memory_static.drawio.png
456.. |RMM app host| image:: ./diagrams/rmm_app_on_host.drawio.png
457.. |RMM app layout| image:: ./diagrams/rmm_app_layout.drawio.png