summaryrefslogtreecommitdiff
path: root/docs/porting-guide.md
blob: 6eded66d8df383bde21ca613aaa906de9b0746a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
EL3 Firmware Test framework Porting Guide
=========================================

Contents
--------

1.  Introduction
2.  Platform requirements
3.  Mandatory modifications
4.  Optional modifications
5.  Storage abstraction layer
6.  Build flags

- - - - - - - - - - - - - - - - - -

1.  Introduction
----------------

Porting the EL3 Firmware Test Framework to a new platform involves making some
mandatory and optional modifications for both the cold and warm boot paths.
Modifications consist of:

*   Implementing a platform-specific function or variable,
*   Setting up the execution context in a certain way, or
*   Defining certain constants (for example #defines).

The platform-specific functions and variables are all declared in
[include/plat/common/platform.h]. The framework provides a default
implementation of variables and functions to fulfill the optional requirements.
These implementations are all weakly defined; they are provided to ease the
porting effort. Each platform port can override them with its own implementation
if the default implementation is inadequate.


2.  Platform requirements
-------------------------

The Test Framework relies on the following features to be present on the
platform and accessible from Normal World.

*   Watchdog
*   Non-Volatile Memory
*   System Timer

This also means that a platform port of the Test Framework must include software
drivers for those features.


3.  Mandatory modifications
---------------------------

### File : platform_def.h [mandatory]

Each platform must ensure that a header file of this name is in the system
include path with the following constants defined. This may require updating the
list of `PLAT_INCLUDES` in the `platform.mk` file. In the ARM FVP port, this
file is found in [plat/fvp/include/platform_def.h].

*   **#define : PLATFORM_LINKER_FORMAT**

    Defines the linker format used by the platform, for example
    `elf64-littleaarch64` used by the FVP.

*   **#define : PLATFORM_LINKER_ARCH**

    Defines the processor architecture for the linker by the platform, for
    example `aarch64` used by the FVP.

*   **#define : PLATFORM_STACK_SIZE**

    Defines the stack memory available to each CPU. This constant is used by
    [plat/common/aarch64/platform_mp_stack.S].

*   **#define : PLATFORM_CLUSTER_COUNT**

    Defines the total number of clusters implemented by the platform in the
    system.

*   **#define : PLATFORM_CORE_COUNT**

    Defines the total number of CPUs implemented by the platform across all
    clusters in the system.

*   **#define : PLATFORM_MAX_CPUS_PER_CLUSTER**

    Defines the maximum number of CPUs that can be implemented within a cluster
    on the platform.

*   **#define : PLATFORM_NUM_AFFS**

    Defines the total number of nodes in the affinity hierarchy at all affinity
    levels used by the platform.

*   **#define : PLATFORM_MAX_AFFLVL**

    Defines the maximum number of affinity levels in the system that the
    platform implements.  ARMv8-A has support for 4 affinity levels. It is
    likely that hardware will implement fewer affinity levels. For example,
    the Base AEM FVP implements two clusters with a configurable number of CPUs.
    It reports the maximum affinity level as 1.

*   **#define : PLAT_MAX_SPI_OFFSET_ID**

    Defines the offset of the last Shared Peripheral Interrupt supported by the
    TFTF on this platform. SPI numbers are mapped onto GIC interrupt IDs,
    starting from interrupt ID 32. In other words, this offset ID corresponds to
    the last SPI number, to which 32 must be added to get the corresponding last
    GIC IRQ ID.
    E.g. `PLAT_MAX_SPI_OFFSET_ID` = 10 means that IRQ #42 is the last SPI.

*   **#define : PLAT_LOCAL_PSTATE_WIDTH**

    Defines the bit-field width of the local state in State-ID field of
    the power-state parameter. This macro will be used by the TFTF framework
    to compose the State-ID field given the local power state at different
    affinity levels.

*   **#define : PLAT_MAX_PWR_STATES_PER_LVL**

    Defines the maximum number of power states at a power domain level for
    the platform. This macro will be used by the `PSCI_STAT_COUNT/RESIDENCY`
    tests to determine the size of the array to allocate for storing the
    statistics.

*   **#define : TFTF_BASE**

    Defines the base address of the TFTF binary in DRAM. Used by the linker
    script to link the image at the right address. Must be aligned on a
    page-size boundary.

*   **#define : IRQ_PCPU_NS_TIMER**

    Defines the IRQ ID of Per CPU Non-Secure timer of the platform.

*   **#define : IRQ_CNTPSIRQ1**

    Defines the IRQ ID of System timer of the platform.

If the platform port uses the ARM Watchdog Module (SP805) peripheral, the following constant
needs to be defined:

*   **#define : SP805_WDOG_BASE**
    Defines the base address of the SP805 watchdog peripheral.

If the platform port uses the IO storage framework, the following constants
must also be defined:

*   **#define : MAX_IO_DEVICES**

    Defines the maximum number of registered IO devices. Attempting to register
    more devices than this value using `io_register_device()` will fail with
    `IO_RESOURCES_EXHAUSTED`.

*   **#define : MAX_IO_HANDLES**

    Defines the maximum number of open IO handles. Attempting to open more IO
    entities than this value using `io_open()` will fail with
    `IO_RESOURCES_EXHAUSTED`.

*   **#define : NOR_FLASH_BLOCK_SIZE**

    It needs to be defined if you are using the Intel StrataFlash P30 embedded
    driver provided by us. It defines the largest block size as seen by the
    software while writing to NOR flash.

*  **#define : TFTF_NVM_OFFSET**

    The TFTF needs some Non-Volatile Memory to store persistent data. This
    defines the offset from the beginning of this memory that the TFTF can use.

*   **#define : TFTF_NVM_SIZE**

    Defines the size of the Non-Volatile Memory allocated for TFTF usage.

### Function : tftf_plat_arch_setup() [mandatory]

    Argument : void
    Return   : void

This function performs any platform-specific and architectural setup that the
platform requires.

In both the ARM FVP and Juno ports, this function configures and enables the
MMU.

### Function : tftf_early_platform_setup() [mandatory]

    Argument : void
    Return   : void

This function executes with the MMU and data caches disabled. It is only called
by the primary CPU. It is used to perform platform-specific actions very early
in the boot.

In both the ARM FVP and Juno ports, this function configures the console.

### Function : tftf_platform_setup() [mandatory]

    Argument : void
    Return   : void

This function executes with the MMU and data caches enabled. It is responsible
for performing any remaining platform-specific setup that can occur after the
MMU and data cache have been enabled.

This function is also responsible for initializing the storage abstraction layer
used to access non-volatile memory for permanent storage of test results. It
also initialises the GIC and detects the platform topology using
platform-specific means.

### Function : plat_get_nvm_handle()  [mandatory]

    Argument : uintptr_t *
    Return   : void

It is needed if the platform port uses IO storage framework. This function is
responsible for getting the pointer to the initialised non-volatile memory
entity.

### Function : tftf_plat_get_pwr_domain_tree_desc()  [mandatory]

    Argument : void
    Return   : char *

This function returns the platform topology description array in a suitable
format as expected by TFTF. The size of the array is expected to be
PLATFORM_NUM_AFFS - PLATFORM_CORE_COUNT + 1. The format used to describe this
array is :

1.  The first entry in the array specifies the number of power domains at the
    highest power level implemented in the platform. This caters for platforms
    where the power domain tree does not have a single root node e.g. the FVP
    which has two cluster power domains at the highest level (1).

2.  Each subsequent entry corresponds to a power domain and contains the number
    of power domains that are its direct children.

The array format is the same as the one used by ARM Trusted Firmware and more
details of its description can be found in the ARM Trusted Firmware
documentation [docs/psci-pd-tree.md].

### Function : tftf_plat_get_mpidr()  [mandatory]

    Argument : unsigned int
    Return   : uint64_t

This function converts a given 'core_pos' into a valid MPIDR if the CPU is
present in the platform. The 'core_pos' is a unique number less than the
PLATFORM_CORE_COUNT returned by platform_get_core_pos() for a given CPU. This
API is used by the topology framework in TFTF to query the presence of a CPU
and ,if present, returns the corresponding MPIDR for it. If the CPU referred
to by the 'core_pos' is absent, then this function returns INVALID_MPID.

### Function : plat_get_state_prop() [mandatory]

    Argument : unsigned int
    Return   : const plat_state_prop_t *

This functions returns the `plat_state_prop_t` array for all the valid low
power states from platform for a specified `affinity level` and returns NULL
for an invalid `affinity level`. The array is expected to be NULL terminated.
This function is expected to be used by tests that need to compose the power
state parameter for use in PSCI_CPU_SUSPEND API or PSCI_STAT/RESIDENCY API.

### Function : plat_fwu_io_setup() [mandatory]

    Argument : void
    Return   : void

This function initializes the IO system used by the firmware update.

### Function : plat_arm_gic_init() [mandatory]

    Argument : void
    Return   : void

This function initializes the ARM Generic Interrupt Controller (GIC).

4.  Optional modifications
--------------------------

The following are helper functions implemented by the Test Framework that
perform common platform-specific tasks. A platform may choose to override these
definitions.

### Function : platform_get_stack()

    Argument : unsigned long
    Return   : unsigned long

This function returns the base address of the memory stack that has been
allocated for the CPU specified by MPIDR. The size of the stack allocated to
each CPU is specified by the platform defined constant `PLATFORM_STACK_SIZE`.

Common implementation of this function is provided in
[plat/common/aarch64/platform_mp_stack.S].

### Function : tftf_platform_end()

    Argument : void
    Return   : void

This function performs any operation required by the platform to properly finish
the test session.

The default implementation sends an EOT (End Of Transmission) character on the
UART. In the case of software models this can be used to directly shutdown the
model. When running on hardware it allows someone monitoring the UART to know
that the test has ended and the platform can be rebooted.

### Function : tftf_plat_reset()

    Argument : void
    Return   : void

This function resets the platform.

The default implementation uses the ARM watchdog peripheral (SP805) to generate
a watchdog timeout interrupt. This interrupt remains deliberately unserviced,
which eventually asserts the reset signal.

### Function : tftf_platform_setup()

    Argument : void
    Return   : void

Setup code for platform hardware. The default implementation initializes the IO
and GIC.

5.  Storage abstraction layer
-----------------------------

In order to improve platform independence and portability a storage abstraction
layer is used to store test results to non-volatile platform storage.

Each platform should register devices and their drivers via the Storage layer.
These drivers then need to be initialized in `tftf_platform_setup()` function.

It is mandatory to implement at least one storage driver. For the FVP and Juno
platforms the NOR Flash driver is provided as the default means to store test
results to storage. The storage layer is described in the header file
`include/lib/io_storage.h`. The implementation of the common library is in
`drivers/io/io_storage.c` and the driver files are located in `drivers/io/`.


6.  Build Flags
---------------

*   **PLAT_TESTS_SKIP_LIST**

This build flag can be defined by the platform to control exclusion of some
testcases from the default test plan for a platform. If used this needs to
point to a text file which follows the following criteria:
    - It contains list of tests to skip for this platform.
    - Should specify 1 test per line, using the following format:
      testsuite_name/testcase_name
      where `testsuite_name` and `testcase_name` are the names that appear in
      tests/tests.xml file.
    - Alternatively, it is possible to disable a test suite entirely, which will
      disable all test cases part of this test suite. To do so, only specify the
      test suite name, omitting the '/testcase_name' part.