1*** Variables ***
2# The values and addresses are totally arbitrary.
3${init_value_0x40}             0x11
4${init_value_0x80}             0x22
5${init_value_0x100}            0x33
6${init_value_0x140}            0x44
7${init_value_0x180}            0x55
8
9${per-core-memory}=            SEPARATOR=
10...                            """
11...                            memory2: Memory.ArrayMemory @ { sysbus new Bus.BusPointRegistration { address: 0x200; cpu: mockCpu0 } } ${\n}
12...                            ${SPACE*4}size: 0x100                                                                                   ${\n}
13...                                                                                                                                    ${\n}
14...                            memory3: Memory.ArrayMemory @ { sysbus new Bus.BusPointRegistration { address: 0x250; cpu: mockCpu1 } } ${\n}
15...                            ${SPACE*4}size: 0x500                                                                                   ${\n}
16...                            """
17
18${max_32bit_addr}              0xFFFFFFFF
19
20${platform_no_region_specified}   SEPARATOR=${\n}
21...                               """
22...                               mock: Mocks.MockDoubleWordPeripheralWithOnlyRegionReadMethod @ {
23...                               ${SPACE*4}sysbus new Bus.BusMultiRegistration { address: 0x100; size: 0x100; region: "nonexisting" }
24...                               }
25...                               """
26
27${platform_only_region_read}   SEPARATOR=${\n}
28...                            """
29...                            mock: Mocks.MockDoubleWordPeripheralWithOnlyRegionReadMethod @ {
30...                            ${SPACE*4}sysbus new Bus.BusMultiRegistration { address: 0x100; size: 0x100; region: "region" }
31...                            }
32...                            """
33
34*** Keywords ***
35Create Machine With CPU And Two MappedMemory Peripherals
36    Execute Command            using sysbus
37    Execute Command            mach create
38
39    # ARMv7A is used only because it can be created without any additional peripherals.
40    # Locking can be used with all CPUs.
41    Execute Command            machine LoadPlatformDescriptionFromString "cpu: CPU.ARMv7A @ sysbus { cpuType: \\"cortex-a9\\"}"
42    Execute Command            machine LoadPlatformDescriptionFromString "mem1: Memory.MappedMemory @ sysbus 0x10000 { size: 0x10000 }"
43    Execute Command            machine LoadPlatformDescriptionFromString "mem2: Memory.MappedMemory @ sysbus 0x80000 { size: 0x10000 }"
44
45Get ${peripheral} Size, Address And Range
46    ${size}=    Execute Command  ${peripheral} Size
47    ${size}=    Strip String     ${size}
48    ${ranges}=  Execute Command  sysbus GetRegistrationPoints ${peripheral}
49
50    # Let's make sure there's only one range.
51    ${count}=  Evaluate          """${ranges}""".count('<')
52    Should Be Equal As Integers  1  ${count}
53
54    ${range}  ${address}=  Evaluate
55    ...    [ re.search('<(0x[0-9A-F]*), .*>', """${ranges}""").group(i) for i in range(2) ]
56    ...    modules=re
57
58    RETURN  ${size}  ${address}  ${range}
59
60${lock_or_unlock:(Lock|Unlock)} Address Range From ${start} To ${end}
61    ${range}=     Evaluate   f"<{ hex(${start}) }, { hex(${end}) }>"
62    ${lock_or_unlock} Address Range ${range}
63
64${lock_or_unlock:(Lock|Unlock)} Address Range ${range}
65    ${set_lock}=  Evaluate   '${lock_or_unlock}' == 'Lock'
66    Execute Command          sysbus SetAddressRangeLocked ${range} ${set_lock}
67
68Range From ${start} To ${end} Should Be Accessible
69    ${range}=       Evaluate         f"<{ hex(${start}) }, { hex(${end}) }>"
70    ${locked_str}=  Execute Command  sysbus IsAddressRangeLocked ${range}
71    Should Start With                ${locked_str}  False
72
73No Blocked Access Should Be In Log
74    Should Not Be In Log     Tried to (read|write) .* which is inside a locked address range  treatAsRegex=True
75
76Blocked ${access_size}B Read From ${address} Should Be In Log
77    ${eval_addr}=  Evaluate  '0x' + hex(${address}).upper()[2:]
78    Wait For Log Entry       Tried to read ${access_size} bytes at ${eval_addr} which is inside a locked address range, returning 0
79
80Read From Sysbus And Check If Blocked
81    [Arguments]  ${address}  ${expected_value}=0x0  ${should_be_blocked}=True  ${access_type}=Byte  ${access_size}=1  ${cpu_context}=
82
83    ${read_value}=  Execute Command  sysbus Read${access_type} ${address} ${cpu_context}
84    IF    ${should_be_blocked}
85        Blocked ${access_size}B Read From ${address} Should Be In Log
86    ELSE
87        No Blocked Access Should Be In Log
88    END
89    Should Be Equal As Integers    ${read_value}  ${expected_value}  base=16
90
91Should Block Read Byte
92    [Arguments]  ${address}  ${cpu_context}=
93    Read From Sysbus And Check If Blocked    ${address}     cpu_context=${cpu_context}
94
95Should Block Read Quad
96    [Arguments]  ${address}  ${cpu_context}=
97    Read From Sysbus And Check If Blocked    ${address}  access_type=QuadWord  access_size=8  cpu_context=${cpu_context}
98
99Should Read Byte
100    [Arguments]  ${address}  ${expected_value}  ${cpu_context}=
101    Read From Sysbus And Check If Blocked    ${address}  ${expected_value}  should_be_blocked=False  cpu_context=${cpu_context}
102
103Should Read Quad
104    [Arguments]  ${address}  ${expected_value}  ${cpu_context}=
105    Read From Sysbus And Check If Blocked    ${address}  ${expected_value}  should_be_blocked=False  access_type=QuadWord  access_size=8  cpu_context=${cpu_context}
106
107Blocked ${access_size}B Write${access_type} Of ${value} To ${address} Should Be In Log
108    ${eval_addr}=  Evaluate  '0x' + hex(${address}).upper()[2:]
109    Wait For Log Entry       Tried to write ${access_size} bytes (${value}) at ${eval_addr} which is inside a locked address range, write ignored
110
111Write To Sysbus And Check If Blocked
112    [Arguments]  ${address}  ${value}  ${should_be_blocked}=True  ${access_type}=Byte  ${access_size}=1  ${cpu_context}=
113
114    Execute Command  sysbus Write${access_type} ${address} ${value} ${cpu_context}
115    IF    ${should_be_blocked}
116        Blocked ${access_size}B Write Of ${value} To ${address} Should Be In Log
117    ELSE
118        No Blocked Access Should Be In Log
119    END
120
121Should Block Write Byte
122    [Arguments]  ${address}  ${value}  ${cpu_context}=
123    Write To Sysbus And Check If Blocked    ${address}  ${value}  cpu_context=${cpu_context}
124
125Should Block Write Quad
126    [Arguments]  ${address}  ${value}  ${cpu_context}=
127    Write To Sysbus And Check If Blocked    ${address}  ${value}  access_type=QuadWord  access_size=8  cpu_context=${cpu_context}
128
129Should Write Byte
130    [Arguments]  ${address}  ${value}  ${cpu_context}=
131    Write To Sysbus And Check If Blocked    ${address}  ${value}  should_be_blocked=False  cpu_context=${cpu_context}
132
133Should Write Quad
134    [Arguments]  ${address}  ${value}  ${cpu_context}=
135    Write To Sysbus And Check If Blocked    ${address}  ${value}  should_be_blocked=False  access_type=QuadWord  access_size=8  cpu_context=${cpu_context}
136
137Should Write Byte To Non Existing Peripheral
138    [Arguments]  ${address}  ${value}  ${cpu_context}=
139    Execute Command            sysbus WriteByte ${address} ${value} ${cpu_context}
140    Wait For Log Entry         WriteByte to non existing peripheral at ${address}, value ${value}
141
142*** Test Cases ***
143Test Reading Bytes From Locked Sysbus Range
144    Execute Command            mach create
145    Execute Command            machine LoadPlatformDescriptionFromString "memory: Memory.ArrayMemory @ sysbus 0x100 { size: 0x100 }"
146    Create Log Tester          0
147
148    Execute Command            sysbus Tag <0x40 1> "test" ${init_value_0x40}
149    Execute Command            sysbus Tag <0x80 1> "test" ${init_value_0x80}
150    Should Write Byte          0x100  ${init_value_0x100}
151    Should Write Byte          0x140  ${init_value_0x140}
152    Should Write Byte          0x180  ${init_value_0x180}
153
154    Should Read Byte           0x40   ${init_value_0x40}
155    Should Read Byte           0x80   ${init_value_0x80}
156    Should Read Byte           0x100  ${init_value_0x100}
157    Should Read Byte           0x140  ${init_value_0x140}
158    Should Read Byte           0x180  ${init_value_0x180}
159
160    Provides                   sysbus-with-test-values
161
162    Execute Command            sysbus SetAddressRangeLocked <0x0 0x200> true
163    Should Block Read Byte     0x40
164    Should Block Read Byte     0x80
165    Should Block Read Byte     0x100
166    Should Block Read Byte     0x140
167    Should Block Read Byte     0x180
168
169    Provides                   sysbus-with-test-values-locked-below-0x200
170
171Test Accessing Locked Sysbus Range Boundaries With Wide Accesses
172    Requires                   sysbus-with-test-values
173    ${quad_test_value}=        Set Variable  0xFEDCBA9876543210
174
175    Execute Command            sysbus SetAddressRangeLocked <0x144, 0x17C> true
176
177    # Wide accesses should only succeed if all the bytes are outside a locked range.
178    Should Block Read Quad     0x140
179    Should Block Write Quad    0x140  ${quad_test_value}
180    Should Read Byte           0x140  ${init_value_0x140}
181
182    # 0x17C is the address of the last locked byte.
183    Should Block Read Quad     0x17C
184    Should Block Write Quad    0x17C  ${quad_test_value}
185
186    Should Read Byte           0x180  ${init_value_0x180}
187
188    Should Write Quad          0x17E  ${quad_test_value}
189    Should Read Quad           0x17E  ${quad_test_value}
190
191Test Reading After Unlocking Parts Of Locked Sysbus Range
192    Requires                   sysbus-with-test-values-locked-below-0x200
193
194    # Reconfigure locked ranges to unlock arbitrary ranges containing 0x80 and 0x140.
195    Execute Command            sysbus SetAddressRangeLocked <0x60, 0x15F> false
196    Execute Command            sysbus SetAddressRangeLocked <0x100, 0x13F> true
197
198    Should Block Read Byte     0x40
199    Should Read Byte           0x80   ${init_value_0x80}
200    Should Block Read Byte     0x100
201    Should Read Byte           0x140  ${init_value_0x140}
202    Should Block Read Byte     0x180
203
204Test Writing To A Locked Sysbus Range
205    Requires                   sysbus-with-test-values
206
207    ${new_value_0x100}=        Set Variable  0x66
208    ${new_value_0x140}=        Set Variable  0x77
209
210    # In the first round of writing, only the write to 0x100 should succeed
211    # and 0x140 in the second round. 0x180 is locked in both writing rounds
212    # so read at the end should return its initial value.
213
214    Execute Command            sysbus SetAddressRangeLocked <0x140, 0x1FF> true
215    Should Write Byte          0x100  ${new_value_0x100}
216    Should Block Write Byte    0x140  ${new_value_0x100}
217    Should Block Write Byte    0x180  ${new_value_0x100}
218
219    Execute Command            sysbus SetAddressRangeLocked <0x100, 0x1FF> true
220    Execute Command            sysbus SetAddressRangeLocked <0x140, 0x140> false
221    Should Block Write Byte    0x100  ${new_value_0x140}
222    Should Write Byte          0x140  ${new_value_0x140}
223    Should Block Write Byte    0x180  ${new_value_0x140}
224
225    Execute Command            sysbus SetAddressRangeLocked <0x100, 0x1FF> false
226    Should Read Byte           0x100  ${new_value_0x100}
227    Should Read Byte           0x140  ${new_value_0x140}
228    Should Read Byte           0x180  ${init_value_0x180}
229
230Test Writing To A Locked Sysbus Range With CPU Context
231    Requires                   sysbus-with-test-values
232    # Architecture doesn't matter, these CPUs are just mocks
233    Execute Command            machine LoadPlatformDescriptionFromString "mockCpu0: CPU.ARMv7A @ sysbus { cpuType: \\"cortex-a9\\" }"
234    Execute Command            machine LoadPlatformDescriptionFromString "mockCpu1: CPU.ARMv7A @ sysbus { cpuType: \\"cortex-a9\\" }"
235
236    # SerialExecution is necessary only because the logs might appear in any order when being run concurrently on two CPUs
237    # and this will cause the tests to timeout
238    Execute Command            machine SetSerialExecution True
239
240    Provides                   sysbus-with-mock-cpus
241
242    ${new_value_0x100}=        Set Variable  0x66
243    ${new_value_0x140}=        Set Variable  0x77
244
245    Execute Command            sysbus SetAddressRangeLocked <0x100, 0x1FF> true sysbus.mockCpu0
246    Should Block Write Byte    0x100  ${new_value_0x100}  sysbus.mockCpu0
247    Should Write Byte          0x100  ${new_value_0x100}
248    Should Block Write Byte    0x140  ${new_value_0x100}  sysbus.mockCpu0
249    Should Block Write Byte    0x180  ${new_value_0x100}  sysbus.mockCpu0
250
251    Execute Command            sysbus SetAddressRangeLocked <0x100, 0x1FF> true sysbus.mockCpu1
252    Execute Command            sysbus SetAddressRangeLocked <0x140, 0x140> false sysbus.mockCpu0
253    Should Block Write Byte    0x100  ${new_value_0x140}  sysbus.mockCpu0
254    Should Write Byte          0x140  ${new_value_0x140}  sysbus.mockCpu0
255    Should Block Write Byte    0x180  ${new_value_0x140}  sysbus.mockCpu1
256
257    Execute Command            sysbus SetAddressRangeLocked <0x100, 0x1FF> false sysbus.mockCpu0
258    Should Read Byte           0x100  ${new_value_0x100}
259    Should Read Byte           0x140  ${new_value_0x140}
260    Should Read Byte           0x180  ${init_value_0x180}
261
262Test Writing To A Locked Sysbus Range Registered Per CPU
263    Requires                   sysbus-with-mock-cpus
264
265    Execute Command            machine LoadPlatformDescriptionFromString ${per-core-memory}
266
267    ${new_value_0x200}=        Set Variable  0x99
268
269    Execute Command            sysbus SetAddressRangeLocked <0x200, 0x2FF> true sysbus.mockCpu0
270    Should Block Write Byte    0x200  ${new_value_0x200}  sysbus.mockCpu0
271
272    # For these, the range doesn't exist, as it's local to CPU0 only
273    Should Write Byte To Non Existing Peripheral    0x200  ${new_value_0x200}  sysbus.mockCpu1
274    Should Write Byte To Non Existing Peripheral    0x200  ${new_value_0x200}
275
276    Execute Command            sysbus SetAddressRangeLocked <0x200, 0x2FF> false sysbus.mockCpu0
277
278    # Now the lock is global, but the peripheral is still locally-mapped.
279    # Since locking has precedence over non-existent access, CPUs won't trip on non-existing access
280    # and all writes will fail (lock is on "any" context)
281    Execute Command            sysbus SetAddressRangeLocked <0x200, 0x2FF> true
282
283    Should Block Write Byte    0x200  ${new_value_0x200}
284    Should Block Write Byte    0x200  ${new_value_0x200}  sysbus.mockCpu1
285    Should Block Write Byte    0x200  ${new_value_0x200}  sysbus.mockCpu0
286
287    # The other range should still not be writable by its core
288    Should Block Write Byte    0x250  ${new_value_0x200}  sysbus.mockCpu1
289
290    # Unlock the global range
291    Execute Command            sysbus SetAddressRangeLocked <0x200, 0x2FF> false
292    # Re-lock it but with CPU1 only and repeat the previous steps
293    Execute Command            sysbus SetAddressRangeLocked <0x200, 0x2FF> true sysbus.mockCpu1
294
295    # CPU0 is unaffected by the lock, as is the access without context
296    Should Write Byte          0x200  ${new_value_0x200}
297    Should Block Write Byte    0x200  ${new_value_0x200}  sysbus.mockCpu1
298    Should Write Byte          0x200  ${new_value_0x200}  sysbus.mockCpu0
299
300    # The other range should still not be writable by its core
301    Should Block Write Byte    0x250  ${new_value_0x200}  sysbus.mockCpu1
302
303    Execute Command            sysbus SetAddressRangeLocked <0x200, 0x2FF> false sysbus.mockCpu1
304    # Now, unlock the first range, and lock the second range
305    # Cpu1 should fail on accessing the range
306    Execute Command            sysbus SetAddressRangeLocked <0x250, 0x7FF> true sysbus.mockCpu1
307    Should Block Write Byte    0x250  ${new_value_0x200}  sysbus.mockCpu1
308
309Test Registering Mapped Memory In Locked Range
310    # Waiting for abort logs is tricky and might hang the test if something goes wrong cause
311    # virtual timeouts don't really work with aborts; 20 seconds should be more than enough.
312    [Timeout]                  20 seconds
313
314    # We want to test IMapped memory here, so we need CPU's presence for a full test
315    # relocking is trivial for anything that isn't directly mapped to CPU (unmanaged memory)
316    Requires                   sysbus-with-mock-cpus
317    ${value}=                  Set Variable  0x66
318
319    Execute Command            sysbus SetAddressRangeLocked <0x4000, 0x4FFF> true
320
321    Execute Command            machine LoadPlatformDescriptionFromString "memory_locked: Memory.MappedMemory @ sysbus 0x4000 { size: 0x1000 }"
322    Execute Command            machine LoadPlatformDescriptionFromString "memory_unlocked: Memory.MappedMemory @ sysbus 0x5000 { size: 0x1000 }"
323
324    Should Write Byte          0x5000  ${value}
325    Should Block Write Byte    0x4000  ${value}
326
327    Execute Command            sysbus.mockCpu0 PC 0x4000
328    Execute Command            sysbus.mockCpu1 PC 0x5000
329
330    # Now, to really test if newly registered memory has been locked correctly, try executing code (instructions don't matter here)
331    # Cpu0 should abort immediately, and Cpu1 should fall out of memory range soon after
332    # We don't wait for the exact logs in case there's another CPU abort or a different order of aborts in which case we could wait forever.
333    ${log}=  Wait For Log Entry    CPU abort  timeout=1
334    Should Contain    ${log}       mockCpu0: CPU abort \[PC=0x4000\]: Trying to execute code from disabled or locked memory at 0x00004000
335
336    ${log}=  Wait For Log Entry    CPU abort  timeout=1
337    Should Contain    ${log}       mockCpu1: CPU abort \[PC=0x6000\]: Trying to execute code outside RAM or ROM at 0x00006000
338
339Locked MappedMemory Should Not Be Accessible From CPU
340    Create Machine With CPU And Two MappedMemory Peripherals
341    ${flash}=  Set Variable    mem1
342    ${ram}=    Set Variable    mem2
343
344    ${flash_size}  ${flash_addr}  ${flash_range}=  Get ${flash} Size, Address And Range
345    ${ram_size}    ${ram_addr}    ${ram_range}=    Get ${ram} Size, Address And Range
346
347    Execute Command            cpu ExecutionMode SingleStep
348    Execute Command            cpu PC ${ram_addr}
349    Create Log Tester          0
350
351    # With flash locked, the loads from [r3] and stores to [r3] should be blocked.
352    ${result_addr}=  Evaluate  hex(${flash_addr} + 0x1000)
353    Execute Command            cpu SetRegister 3 ${result_addr}
354
355    Execute Command            ${ram} WriteDoubleWord 0x00 0xe59f2028  # ldr   r2, [pc, #40] // =0x11111111
356    Execute Command            ${ram} WriteDoubleWord 0x04 0xe5832000  # str   r2, [r3]
357    Execute Command            ${ram} WriteDoubleWord 0x30 0x11111111  # this will be loaded by LDR instruction above
358
359    # Ranges have to fully contain all MappedMemory peripherals registered in the given range.
360    # Here we lock whole sysbus and then unlock ram.
361    Lock Address Range From 0x0 To ${max_32bit_addr}
362    Unlock Address Range ${ram_range}
363    Execute Command            cpu Step 2
364
365    Blocked 4B Write Of 0x11111111 To ${result_addr} Should Be In Log
366
367    Execute Command            ${ram} WriteDoubleWord 0x08 0xe59f2024  # ldr   r2, [pc, #34] // =0x22222222
368    Execute Command            ${ram} WriteDoubleWord 0x0c 0xe5832000  # str   r2, [r3]
369    Execute Command            ${ram} WriteDoubleWord 0x10 0xe3032333  # movw  r2, #0x3333
370    Execute Command            ${ram} WriteDoubleWord 0x14 0xe1c320b1  # strh  r2, [r3, #1]
371    Execute Command            ${ram} WriteDoubleWord 0x34 0x22222222  # this will be loaded by LDR instruction above
372
373    Unlock Address Range ${flash_range}
374    Execute Command            cpu Step 4
375
376    No Blocked Access Should Be In Log
377
378    Execute Command            ${ram} WriteDoubleWord 0x18 0xe3a02044  # mov   r2, #0x44
379    Execute Command            ${ram} WriteDoubleWord 0x1c 0xe5c32001  # strb  r2, [r3, #1]
380    Execute Command            ${ram} WriteDoubleWord 0x20 0xe5932000  # ldr   r2, [r3]
381
382    # Lock flash and some memory around it.
383    Lock Address Range From ${flash_addr}-${flash_size} To ${flash_addr}+${flash_size}*2
384    Execute Command            cpu Step 3
385
386    Blocked 1B Write Of 0x44 To ${result_addr}+1 Should Be In Log
387    Blocked 4B Read From ${result_addr} Should Be In Log
388
389    Execute Command            ${ram} WriteDoubleWord 0x24 0xe3a02055  # mov   r2, #0x55
390    Execute Command            ${ram} WriteDoubleWord 0x28 0xe5c32002  # strb  r2, [r3, #2]
391    Execute Command            ${ram} WriteDoubleWord 0x2c 0xe5932000  # ldr   r2, [r3]
392
393    Unlock Address Range From 0x0 To ${max_32bit_addr}
394    Execute Command            cpu Step 3
395
396    No Blocked Access Should Be In Log
397
398    ${res}=  Execute Command   sysbus ReadDoubleWord ${result_addr}
399    Should Be True             """${res}""".strip() == '0x22553322'
400
401Partial MappedMemory Locking Should Not Be Allowed With ICPUWithMappedMemory
402    # CPU is important; partial MappedMemory locking isn't allowed only with ICPUWithMappedMemory.
403    Create Machine With CPU And Two MappedMemory Peripherals
404
405    ${mem1_size}  ${mem1_addr}  ${mem1_range}=  Get mem1 Size, Address And Range
406    ${mem2_size}  ${mem2_addr}  ${mem2_range}=  Get mem2 Size, Address And Range
407    ${mem2_end}=  Evaluate        hex(${mem2_addr} + ${mem2_size} - 1)
408
409    ${error}=     Set Variable    Mapped peripherals registered at the given range * have to be fully included:
410    ${mem1_reg}=  Set Variable    \n\* machine-0.mem1 registered at ${mem1_range}
411    ${mem2_reg}=  Set Variable    \n\* machine-0.mem2 registered at ${mem2_range}
412
413    # Test partial locking of one or both MappedMemory peripherals.
414
415    Run Keyword And Expect Error  *${error}${mem1_reg}*
416    ...  Lock Address Range From 0x0 To ${mem1_addr}+0x10
417
418    Run Keyword And Expect Error  *${error}${mem1_reg}*
419    ...  Lock Address Range From ${mem1_addr}+0x10 To ${max_32bit_addr}
420
421    Run Keyword And Expect Error  *${error}${mem2_reg}*
422    ...  Lock Address Range From 0x0 To ${mem2_addr}+0x10
423
424    Run Keyword And Expect Error  *${error}${mem1_reg}${mem2_reg}*
425    ...  Lock Address Range From ${mem1_addr}+0x10 To ${mem2_addr}+0x10
426
427    # Make sure no range within 32-bit address space has been locked.
428    Range From 0x0 To ${max_32bit_addr} Should Be Accessible
429
430    # Lock mem1, mem2 and the address space in between.
431    Execute Command               sysbus SetAddressRangeLocked <${mem1_addr}, ${mem2_end}> true
432
433    # Test partial unlocking of one or both MappedMemory peripherals.
434
435    Run Keyword And Expect Error  *${error}${mem1_reg}*
436    ...  Unlock Address Range From 0x0 To ${mem1_addr}+0x10
437
438    Run Keyword And Expect Error  *${error}${mem1_reg}*
439    ...  Unlock Address Range From ${mem1_addr}+0x10 To ${max_32bit_addr}
440
441    Run Keyword And Expect Error  *${error}${mem2_reg}*
442    ...  Unlock Address Range From ${mem2_addr}+0x10 To ${max_32bit_addr}
443
444    Run Keyword And Expect Error  *${error}${mem1_reg}${mem2_reg}*
445    ...  Unlock Address Range From ${mem1_addr}+0x10 To ${mem2_addr}+0x10
446
447    # Make sure mem1, mem2 and the address space in between are still locked. Range
448    # is considered locked if the given range contains any locked range which is why
449    # `IsAddressRangeLocked` isn't used. Let's check accessing a byte every 0x8000.
450    @{locked_range_addresses}=  Evaluate
451    ...    [address for address in range(${mem1_addr}, ${mem2_end}, 0x8000)]
452    FOR  ${address}  IN  ${mem1_addr}  @{locked_range_addresses}
453        Log    ${address}
454        Should Block Read Byte    ${address}
455    END
456
457    # Unlock mem1, mem2 and the address space in between and verify there are no locks now.
458    Unlock Address Range <${mem1_addr}, ${mem2_end}>
459    Range From ${mem1_addr} To ${mem2_end} Should Be Accessible
460
461Symbols Should Be Dynamically Loaded and Unloaded On Request
462    ${bin}=                        Set Variable  @https://dl.antmicro.com/projects/renode/stm32l07--zephyr-shell_module.elf-s_1195760-e9474da710aca88c89c7bddd362f7adb4b0c4b70
463    ${cpu}=                        Set Variable  sysbus.cpu
464    ${main_symbol_name}=           Set Variable  "main"
465    ${main_symbol_address}=        Set Variable  0x0000000008007644
466
467    Execute Command                include @platforms/cpus/stm32l072.repl
468
469    # LoadELF without cpu context argument loads symbols in the global scope
470    Execute Command                sysbus LoadELF ${bin}
471    ${main_address_global}=        Execute Command  sysbus GetSymbolAddress ${main_symbol_name}
472    Should Be Equal As Numbers     ${main_symbol_address}  ${main_address_global}
473
474    # Symbol lookup fallbacks to the global scope if the per-cpu lookup is not found
475    ${main_address_local}=         Execute Command  sysbus GetSymbolAddress ${main_symbol_name} context=${cpu}
476    Should Be Equal As Numbers     ${main_symbol_address}  ${main_address_local}
477
478    # Global lookup is not cleared when the per-cpu lookup is cleared, so local lookup fallbacks to the global scope
479    Execute Command                sysbus ClearSymbols context=${cpu}
480    ${main_address_local}=         Execute Command  sysbus GetSymbolAddress ${main_symbol_name} context=${cpu}
481    Should Be Equal As Numbers     ${main_symbol_address}  ${main_address_local}
482
483    Execute Command                sysbus ClearSymbols
484    # Global lookup is cleared so both local and global lookup fail
485    Run Keyword And Expect Error   *Could not find any address for symbol: main*
486    ...                            Execute Command   sysbus GetSymbolAddress ${main_symbol_name} context=${cpu}
487    Run Keyword And Expect Error   *Could not find any address for symbol: main*
488    ...                            Execute Command   sysbus GetSymbolAddress ${main_symbol_name}
489
490    # Load symbols in the local scope so they are visible only for the given cpu
491    Execute Command                sysbus LoadSymbolsFrom ${bin} context=${cpu}
492    ${main_address_local}=         Execute Command  sysbus GetSymbolAddress ${main_symbol_name} context=${cpu}
493    Should Be Equal As Numbers     ${main_symbol_address}  ${main_address_local}
494    Run Keyword And Expect Error   *Could not find any address for symbol: main*
495    ...                            Execute Command   sysbus GetSymbolAddress ${main_symbol_name}
496
497Should Log All Peripherals Accesses Only When Enabled
498    ${log}=                        Set Variable   peripheral: ReadByte from 0x0 (unknown), returned 0x0.
499    Create Log Tester              0
500    Execute Command                mach create
501    Execute Command                machine LoadPlatformDescriptionFromString "peripheral: Mocks.MockBytePeripheralWithoutTranslations @ sysbus <0x0, +0x8>"
502
503    Execute Command                sysbus LogAllPeripheralsAccess True
504    Execute Command                sysbus ReadByte 0x0
505    Wait For Log Entry             ${log}
506
507    Execute Command                sysbus LogAllPeripheralsAccess False
508    Execute Command                sysbus ReadByte 0x0
509    Should Not Be In Log           ${log}
510
511Should Not Register Platform When Nonexisting Region Is Specified
512    Execute Command                mach create
513    Run Keyword And Expect Error   *No region "nonexisting" is available for Antmicro.Renode.Peripherals.Mocks.MockDoubleWordPeripheralWithOnlyRegionReadMethod*
514    ...                            Execute Command   machine LoadPlatformDescriptionFromString ${platform_no_region_specified}
515
516Should Not Register Region When Only Read Method Is Implemented
517    Execute Command                mach create
518    Run Keyword And Expect Error   *WriteDoubleWord is not specified for region*
519    ...                            Execute Command   machine LoadPlatformDescriptionFromString ${platform_only_region_read}
520
521