[#53750] tests: sysbus: Test accessing locked mapped memory from CPU
diff --git a/tests/unit-tests/sysbus.robot b/tests/unit-tests/sysbus.robot
index f5bdc74..fcf8869 100644
--- a/tests/unit-tests/sysbus.robot
+++ b/tests/unit-tests/sysbus.robot
@@ -15,17 +15,62 @@
... ${SPACE*4}size: 0x500 ${\n}
... """
+${max_32bit_addr} 0xFFFFFFFF
+
*** Keywords ***
+Create Machine With CPU And Two MappedMemory Peripherals
+ Execute Command using sysbus
+ Execute Command mach create
+
+ # ARMv7A is used only because it can be created without any additional peripherals.
+ # Locking can be used with all CPUs.
+ Execute Command machine LoadPlatformDescriptionFromString "cpu: CPU.ARMv7A @ sysbus { cpuType: \\"cortex-a9\\"}"
+ Execute Command machine LoadPlatformDescriptionFromString "mem1: Memory.MappedMemory @ sysbus 0x10000 { size: 0x10000 }"
+ Execute Command machine LoadPlatformDescriptionFromString "mem2: Memory.MappedMemory @ sysbus 0x80000 { size: 0x10000 }"
+
+Get ${peripheral} Size, Address And Range
+ ${size}= Execute Command ${peripheral} Size
+ ${size}= Strip String ${size}
+ ${ranges}= Execute Command sysbus GetRegistrationPoints ${peripheral}
+
+ # Let's make sure there's only one range.
+ ${count}= Evaluate """${ranges}""".count('<')
+ Should Be Equal As Integers 1 ${count}
+
+ ${range} ${address}= Evaluate
+ ... [ re.search('<(0x[0-9A-F]*), .*>', """${ranges}""").group(i) for i in range(2) ]
+ ... modules=re
+
+ [Return] ${size} ${address} ${range}
+
+${lock_or_unlock:(Lock|Unlock)} Address Range From ${start} To ${end}
+ ${range}= Evaluate f"<{ hex(${start}) }, { hex(${end}) }>"
+ ${lock_or_unlock} Address Range ${range}
+
+${lock_or_unlock:(Lock|Unlock)} Address Range ${range}
+ ${set_lock}= Evaluate '${lock_or_unlock}' == 'Lock'
+ Execute Command sysbus SetAddressRangeLocked ${range} ${set_lock}
+
+Range From ${start} To ${end} Should Be Accessible
+ ${range}= Evaluate f"<{ hex(${start}) }, { hex(${end}) }>"
+ ${locked_str}= Execute Command sysbus IsAddressRangeLocked ${range}
+ Should Start With ${locked_str} False
+
+No Blocked Access Should Be In Log
+ Should Not Be In Log Tried to (read|write) .* which is inside a locked address range treatAsRegex=True
+
+Blocked ${access_size}B Read From ${address} Should Be In Log
+ ${eval_addr}= Evaluate '0x' + hex(${address}).upper()[2:]
+ Wait For Log Entry Tried to read ${access_size} bytes at ${eval_addr} which is inside a locked address range, returning 0
+
Read From Sysbus And Check If Blocked
[Arguments] ${address} ${expected_value}=0x0 ${should_be_blocked}=True ${access_type}=Byte ${access_size}=1 ${cpu_context}=
- ${blocked_read_log}= Set Variable Tried to read ${access_size} bytes at ${address} which is inside a locked address range, returning 0
-
- ${read_value}= Execute Command sysbus Read${access_type} ${address} ${cpu_context}
+ ${read_value}= Execute Command sysbus Read${access_type} ${address} ${cpu_context}
IF ${should_be_blocked}
- Wait For Log Entry ${blocked_read_log}
+ Blocked ${access_size}B Read From ${address} Should Be In Log
ELSE
- Should Not Be In Log ${blocked_read_log}
+ No Blocked Access Should Be In Log
END
Should Be Equal As Integers ${read_value} ${expected_value} base=16
@@ -45,15 +90,18 @@
[Arguments] ${address} ${expected_value} ${cpu_context}=
Read From Sysbus And Check If Blocked ${address} ${expected_value} should_be_blocked=False access_type=QuadWord access_size=8 cpu_context=${cpu_context}
+Blocked ${access_size}B Write${access_type} Of ${value} To ${address} Should Be In Log
+ ${eval_addr}= Evaluate '0x' + hex(${address}).upper()[2:]
+ Wait For Log Entry Tried to write ${access_size} bytes (${value}) at ${eval_addr} which is inside a locked address range, write ignored
+
Write To Sysbus And Check If Blocked
[Arguments] ${address} ${value} ${should_be_blocked}=True ${access_type}=Byte ${access_size}=1 ${cpu_context}=
- Execute Command sysbus Write${access_type} ${address} ${value} ${cpu_context}
- ${blocked_write_log}= Set Variable Tried to write ${access_size} bytes (${value}) at ${address} which is inside a locked address range, write ignored
+ Execute Command sysbus Write${access_type} ${address} ${value} ${cpu_context}
IF ${should_be_blocked}
- Wait For Log Entry ${blocked_write_log}
+ Blocked ${access_size}B Write Of ${value} To ${address} Should Be In Log
ELSE
- Should Not Be In Log ${blocked_write_log}
+ No Blocked Access Should Be In Log
END
Should Block Write Byte
@@ -264,6 +312,128 @@
Wait For Log Entry mockCpu0: CPU abort \[PC=0x4000\]: Trying to execute code from disabled or locked memory at 0x00004000 timeout=10
Wait For Log Entry mockCpu1: CPU abort \[PC=0x6000\]: Trying to execute code outside RAM or ROM at 0x00006000 timeout=10
+Locked MappedMemory Should Not Be Accessible From CPU
+ Create Machine With CPU And Two MappedMemory Peripherals
+ ${flash}= Set Variable mem1
+ ${ram}= Set Variable mem2
+
+ ${flash_size} ${flash_addr} ${flash_range}= Get ${flash} Size, Address And Range
+ ${ram_size} ${ram_addr} ${ram_range}= Get ${ram} Size, Address And Range
+
+ Execute Command cpu ExecutionMode SingleStep
+ Execute Command cpu PC ${ram_addr}
+ Create Log Tester 0
+
+ # With flash locked, the loads from [r3] and stores to [r3] should be blocked.
+ ${result_addr}= Evaluate hex(${flash_addr} + 0x1000)
+ Execute Command cpu SetRegisterUnsafe 3 ${result_addr}
+
+ Execute Command ${ram} WriteDoubleWord 0x00 0xe59f2028 # ldr r2, [pc, #40] // =0x11111111
+ Execute Command ${ram} WriteDoubleWord 0x04 0xe5832000 # str r2, [r3]
+ Execute Command ${ram} WriteDoubleWord 0x30 0x11111111 # this will be loaded by LDR instruction above
+
+ # Ranges have to fully contain all MappedMemory peripherals registered in the given range.
+ # Here we lock whole sysbus and then unlock ram.
+ Lock Address Range From 0x0 To ${max_32bit_addr}
+ Unlock Address Range ${ram_range}
+ Execute Command cpu Step 2
+
+ Blocked 4B Write Of 0x11111111 To ${result_addr} Should Be In Log
+
+ Execute Command ${ram} WriteDoubleWord 0x08 0xe59f2024 # ldr r2, [pc, #34] // =0x22222222
+ Execute Command ${ram} WriteDoubleWord 0x0c 0xe5832000 # str r2, [r3]
+ Execute Command ${ram} WriteDoubleWord 0x10 0xe3032333 # movw r2, #0x3333
+ Execute Command ${ram} WriteDoubleWord 0x14 0xe1c320b1 # strh r2, [r3, #1]
+ Execute Command ${ram} WriteDoubleWord 0x34 0x22222222 # this will be loaded by LDR instruction above
+
+ Unlock Address Range ${flash_range}
+ Execute Command cpu Step 4
+
+ No Blocked Access Should Be In Log
+
+ Execute Command ${ram} WriteDoubleWord 0x18 0xe3a02044 # mov r2, #0x44
+ Execute Command ${ram} WriteDoubleWord 0x1c 0xe5c32001 # strb r2, [r3, #1]
+ Execute Command ${ram} WriteDoubleWord 0x20 0xe5932000 # ldr r2, [r3]
+
+ # Lock flash and some memory around it.
+ Lock Address Range From ${flash_addr}-${flash_size} To ${flash_addr}+${flash_size}*2
+ Execute Command cpu Step 3
+
+ Blocked 1B Write Of 0x44 To ${result_addr}+1 Should Be In Log
+ Blocked 4B Read From ${result_addr} Should Be In Log
+
+ Execute Command ${ram} WriteDoubleWord 0x24 0xe3a02055 # mov r2, #0x55
+ Execute Command ${ram} WriteDoubleWord 0x28 0xe5c32002 # strb r2, [r3, #2]
+ Execute Command ${ram} WriteDoubleWord 0x2c 0xe5932000 # ldr r2, [r3]
+
+ Unlock Address Range From 0x0 To ${max_32bit_addr}
+ Execute Command cpu Step 3
+
+ No Blocked Access Should Be In Log
+
+ ${res}= Execute Command sysbus ReadDoubleWord ${result_addr}
+ Should Be True """${res}""".strip() == '0x22553322'
+
+Partial MappedMemory Locking Should Not Be Allowed With ICPUWithMappedMemory
+ # CPU is important; partial MappedMemory locking isn't allowed only with ICPUWithMappedMemory.
+ Create Machine With CPU And Two MappedMemory Peripherals
+
+ ${mem1_size} ${mem1_addr} ${mem1_range}= Get mem1 Size, Address And Range
+ ${mem2_size} ${mem2_addr} ${mem2_range}= Get mem2 Size, Address And Range
+ ${mem2_end}= Evaluate hex(${mem2_addr} + ${mem2_size} - 1)
+
+ ${error}= Set Variable Mapped peripherals registered at the given range * have to be fully included:
+ ${mem1_reg}= Set Variable \n\* machine-0.mem1 registered at ${mem1_range}
+ ${mem2_reg}= Set Variable \n\* machine-0.mem2 registered at ${mem2_range}
+
+ # Test partial locking of one or both MappedMemory peripherals.
+
+ Run Keyword And Expect Error *${error}${mem1_reg}*
+ ... Lock Address Range From 0x0 To ${mem1_addr}+0x10
+
+ Run Keyword And Expect Error *${error}${mem1_reg}*
+ ... Lock Address Range From ${mem1_addr}+0x10 To ${max_32bit_addr}
+
+ Run Keyword And Expect Error *${error}${mem2_reg}*
+ ... Lock Address Range From 0x0 To ${mem2_addr}+0x10
+
+ Run Keyword And Expect Error *${error}${mem1_reg}${mem2_reg}*
+ ... Lock Address Range From ${mem1_addr}+0x10 To ${mem2_addr}+0x10
+
+ # Make sure no range within 32-bit address space has been locked.
+ Range From 0x0 To ${max_32bit_addr} Should Be Accessible
+
+ # Lock mem1, mem2 and the address space in between.
+ Execute Command sysbus SetAddressRangeLocked <${mem1_addr}, ${mem2_end}> true
+
+ # Test partial unlocking of one or both MappedMemory peripherals.
+
+ Run Keyword And Expect Error *${error}${mem1_reg}*
+ ... Unlock Address Range From 0x0 To ${mem1_addr}+0x10
+
+ Run Keyword And Expect Error *${error}${mem1_reg}*
+ ... Unlock Address Range From ${mem1_addr}+0x10 To ${max_32bit_addr}
+
+ Run Keyword And Expect Error *${error}${mem2_reg}*
+ ... Unlock Address Range From ${mem2_addr}+0x10 To ${max_32bit_addr}
+
+ Run Keyword And Expect Error *${error}${mem1_reg}${mem2_reg}*
+ ... Unlock Address Range From ${mem1_addr}+0x10 To ${mem2_addr}+0x10
+
+ # Make sure mem1, mem2 and the address space in between are still locked. Range
+ # is considered locked if the given range contains any locked range which is why
+ # `IsAddressRangeLocked` isn't used. Let's check accessing a byte every 0x8000.
+ @{locked_range_addresses}= Evaluate
+ ... [address for address in range(${mem1_addr}, ${mem2_end}, 0x8000)]
+ FOR ${address} IN ${mem1_addr} @{locked_range_addresses}
+ Log ${address}
+ Should Block Read Byte ${address}
+ END
+
+ # Unlock mem1, mem2 and the address space in between and verify there are no locks now.
+ Unlock Address Range <${mem1_addr}, ${mem2_end}>
+ Range From ${mem1_addr} To ${mem2_end} Should Be Accessible
+
Symbols Should Be Dynamically Loaded and Unloaded On Request
${bin}= Set Variable @https://dl.antmicro.com/projects/renode/stm32l07--zephyr-shell_module.elf-s_1195760-e9474da710aca88c89c7bddd362f7adb4b0c4b70
${cpu}= Set Variable sysbus.cpu
@@ -299,4 +469,4 @@
Should Be Equal As Numbers ${main_symbol_address} ${main_address_local}
Run Keyword And Expect Error *No symbol with name `main` found*
... Execute Command sysbus GetSymbolAddress ${main_symbol_name}
-
\ No newline at end of file
+