blob: f79fee8e3754b4ff82423865f2fa9f0d8a7dea06 [file] [log] [blame]
Mate Toth-Pala8797e12020-06-05 21:14:26 +02001#############
2IRQ test tool
3#############
4
5************
6Introduction
7************
8
9This tool is to test interrupt handling in TF-M. Testing different interrupt
10scenarios is important as the ARMv8-M architecture does complex operations when
11interrupt happens, especially when security boundary crossing happens. These
12operations need to be considered by the TF-M implementation, as in a typical use
13case there is a separate scheduler on the Non-Secure and the secure side as
14well, and the SPM needs to maintain a consistent state, which might not be
15trivial.
16
17The aim of the tool is to be able to test scenarios, that are identified to be
18problematic, in a reproducible way, and do this in an automated way, so regular
19regression testing can have a low cost.
20
21******************
22How the tool works
23******************
24
25The tool is a set of Python scripts which need to be run **inside** a debugger.
26Currently Arm Development Studio and GDB are supported. During the test run, the
27script interacts with the debugger, sets breakpoints, triggers interrupts by
28writing into system registers, starts the target, and when the target is
29stopped, it examines the target's state.
30
31A typical execution scenario looks like this:
32
33.. uml::
34
35 @startuml
36
37 participant CPU
38 participant Debugger
39
40 CPU -> CPU: start_from_reset_handler
41 activate CPU
42
43 Debugger -> CPU: Attach & pause
44 deactivate CPU
45 Debugger-> Debugger: start_script
46 Activate Debugger
47
48 note right
49 Read config files ...
50
51 execute step 1
52 end note
53
54 Debugger -> CPU: set_breakpoint
55
56 Debugger -> CPU: Continue
57 deactivate Debugger
58 activate CPU
59
60
61 ... executing ...
62
63 loop for all the remaining steps
64
65 CPU->Debugger: bkpt hit
66 deactivate CPU
67 activate Debugger
68
69 note right
70 Sanity check on the triggered breakpoint
71 (is this the breakpoint expected)
72 If so, continue the sequence
73 end note
74
75 Debugger -> CPU: set_breakpoint
76
77 alt if required by step
78 Debugger -> CPU: set interrupt pending
79 end alt
80
81 Debugger -> CPU: Continue
82 deactivate Debugger
83 activate CPU
84
85 ... executing ...
86
87 end loop
88
89 CPU->Debugger: bkpt hit
90 deactivate CPU
91 activate Debugger
92
93 Debugger->Debugger: End of script
94 Deactivate Debugger
95
96
97 @enduml
98
99Once started inside the debugger, the script automatically deduces the debugger
100it is running in, by trying to import the support libraries for a specific
101debugger. The order the debuggers are tried in the following order:
102
103#. Arm Development studio
104#. GDB
105
106If both check fails, the script falls back to 'dummy' mode which means that the
107calls to the debugger log the call, and returns successfully.
108
109.. note::
110
111 This 'dummy' mode can be used out of a debugger environment as well.
112
113.. important::
114
115 The script assumes that the symbols for the software being debugged/tested
116 are loaded in the debugger.
117
118The available parameters are:
119
120+----------------------+---------------------------------+--------------------------------------------------+
121| short option | long option | meaning |
122+======================+=================================+==================================================+
123| ``-w`` | ``--sw-break`` | Use sw breakpoint (the default is HW breakpoint) |
124+----------------------+---------------------------------+--------------------------------------------------+
125| ``-q <IRQS>`` | ``--irqs <IRQS>`` | The name of the IRQs json |
126+----------------------+---------------------------------+--------------------------------------------------+
127| ``-t <TESTCASE>`` | ``--testcase <TESTCASE>`` | The name of the file containing the testcase |
128+----------------------+---------------------------------+--------------------------------------------------+
129| ``-b <BREAKPOINTS>`` | ``--breakpoints <BREAKPOINTS>`` | The name of the breakpoints json file |
130+----------------------+---------------------------------+--------------------------------------------------+
131
132***********
133Input files
134***********
135
136Breakpoints
137===========
138
139below is a sample file for breakpoints:
140
141.. code:: json
142
143 {
144 "breakpoints": {
145 "irq_test_iteration_before_service_calls": {
146 "file": "core_ns_positive_testsuite.c",
147 "line": 692
148 },
149 "irq_test_service1_high_handler": {
150 "symbol": "SPM_CORE_IRQ_TEST_1_SIGNAL_HIGH_isr"
151 },
152 "irq_test_service2_prepare_veneer": {
153 "offset": "4",
154 "symbol": "tfm_spm_irq_test_2_prepare_test_scenario_veneer"
155 }
156 }
157 }
158
159Each point where a breakpoint is to be set by the tool should be enumerated in
160this file, in the "breakpoints" object. For each breakpoint an object needs to
161be created. The name of the object can be used in the testcase description. The
162possible fields for a breakpoint object can be seen in the example above.
163
164tools/generate_breakpoints.py
165-----------------------------
166
167This script helps to automate the generation of the breakpoints from source files.
168Each code location that is to be used in a testcase, should be annotated with
169one of the following macro in the source files:
170
171.. code:: c
172
173 /* Put breakpoint on the address of the symbol */
174 #define IRQ_TEST_TOOL_SYMBOL(name, symbol)
175
176 /* Put a breakpoint on the address symbol + offset */
177 #define IRQ_TEST_TOOL_SYMBOL_OFFSET(name, symbol, offset)
178
179 /* Put a breakpoint at the specific location in the code where the macro is
180 * called. This creates a file + line type breakpoint
181 */
182 #define IRQ_TEST_TOOL_CODE_LOCATION(name)
183
184Usage of the script:
185
186.. code::
187
188 $ python3 generate_breakpoints.py --help
189 usage: generate_breakpoints.py [-h] tfm_source outfile
190
191 positional arguments:
192 tfm_source path to the TF-M source code
193 outfile The output json file with the breakpoints
194
195 optional arguments:
196 -h, --help show this help message and exit
197
198
199
200IRQs
201====
202
203.. code:: json
204
205 {
206 "irqs": {
207 "test_service1_low": {
208 "line_num" : 51
209 },
210 "ns_irq_low": {
211 "line_num" : 40
212 }
213 }
214 }
215
216Each IRQ that is to be triggered should have an object created inside the "irqs"
217object. The name of these objects is the name that could be used in a testcase
218description. The only valid field of the IRQ objects is "line_num" which refers
219to the number of the interrupt line.
220
221Testcase
222========
223
224.. code:: json
225
226 {
227 "description" : ["Trigger Non-Secure interrupt during SPM execution in",
228 "privileged mode"],
229 "steps": [
230 {
231 "wait_for" : "irq_test_iteration_start"
232 },
233 {
234 "wait_for" : "spm_partition_start"
235 },
236 {
237 "description" : ["Trigger the interrupt, but expect the operation",
238 "to be finished before the handler is called"],
239 "expect" : "spm_partition_start_ret_success",
240 "trigger" : "ns_irq_low"
241 },
242 {
243 "wait_for" : "ns_irq_low_handler"
244 },
245 {
246 "wait_for" : "irq_test_service2_prepare"
247 }
248 ]
249 }
250
251The test is executed by the script on a step by step basis. When the script is
252started, it processes the first step, then starts the target. After a breakpoint
253is hit, it processes the next target, and continues. This iteration is repeated
254until all the steps are processed
255
256For each step, the following activities are executed:
257
258#. All the breakpoints are cleared in the debugger
259#. If there is a 'wait_for' field, a breakpoint is set for the location
260 specified.
261#. If there is a 'trigger' field, an IRQ is pended by writing to NVIC
262 registers.
263#. If there is an 'expect' field, a breakpoint is set for the location
264 specified. Then the testcase file is scanned starting with the next step,
265 and a breakpoint is set at the first location specified with a 'wait_for'
266 field. Next time, when the execution is stopped, the breakpoint that was hit
267 is compared to the expected breakpoint.
268
269Each object can have a description field to add comments.
270
271**********************
272How to call the script
273**********************
274
275Arm Development Studio
276======================
277
278The script can be called directly from the debugger's command window:
279
280.. code:: shell
281
282 source irq_test.py -q irqs.json -b breakpoints_gen.json -t test_01.json
283
284GDB
285===
286
287The script should be sourced inside GDB, without passing any arguments to
288it.
289
290.. code:: shell
291
292 (gdb) source irq_test.py
293
294
295That registers a custom command ``test_irq``. ``test_irq`` should be called
296with three parameters: breakpoints, irqs, and the test file. This command will
297actually execute the tests.
298
299.. note::
300
301 This indirection in case of GDB is necessary because it is not possible to
302 pass parameters to the script when it is sourced.
303
304.. important::
305
306 The script needs to be run from the <TF-M root>/tools/irq_test directory
307 as the 'current working dir' is added as module search path.
308
309A typical execution of the script in GDB would look like the following:
310
311.. code::
312
313 (gdb) target remote localhost: 3333
314 (gdb) add-symbol-file /path/to/binaries/tfm_s.axf 0x1A020400
315 (gdb) add-symbol-file /path/to/binaries/tfm_ns.axf 0x0A070400
316 (gdb) add-symbol-file /path/to/binaries/mcuboot.axf 0x1A000000
317 (gdb) source /path/to/script/irq_test.py
318 (gdb) test_irq -q /path/to/data/irqs.json -b /path/to/data/breakpoints.json -t /path/to/data/test_03.json
319
320.. note::
321 ``add-symbol-file`` command is used above as other commands like ``file``
322 and ``symbol-file`` seem to be dropping the previously loaded symbols. The
323 addresses the axf files are loaded at are depending on the platform they
324 are built to. The address needs to be specified is the start of the code
325 section
326
327**********************
328Implementation details
329**********************
330
331Class hierarchy:
332
333.. uml::
334
335 @startuml
336
337 class gdb.Command
338 note right: Library provided by GDB
339
340 class TestIRQsCommand
341 note right: Only used in case debugger is GDB
342
343 gdb.Command <|.. TestIRQsCommand : implements
344
345 TestIRQsCommand o-- TestExecutor : Creates >
346
347 "<Main>" o-- TestExecutor : Creates >
348 note right on link
349 Only if running in Arm DS
350 end note
351
352 TestExecutor o-- AbstractDebugger : has a concrete >
353
354 AbstractDebugger <|.. GDBDebugger : implements
355 AbstractDebugger <|.. DummyDebugger : implements
356 AbstractDebugger <|.. ArmDSDebugger : implements
357
358 GDBDebugger o-- Breakpoint : has multiple >
359
360 GDBDebugger o-- Location : has multiple >
361 DummyDebugger o-- Location : has multiple >
362 ArmDSDebugger o-- Location : has multiple >
363
364 @enduml
365
366
367*****************************
368Possible further improvements
369*****************************
370
371- Add priority property to the IRQs data file
372- Add possibility to run randomized scenarios, to realise stress testing.
373
374
375--------------
376
377*Copyright (c) 2020, Arm Limited. All rights reserved.*