1*** Variables ***
2${PRIV_ALL}                         0x3
3${PRIV_WRITE}                       0x2
4${PRIV_READ}                        0x1
5${PRIV_NONE}                        0x0
6${START_PC}                         0x0
7${DMA_ADDR}                         0x45000000
8${IOMMU_ADDR}                       0x46000000
9
10*** Keywords ***
11Create Platform
12    Execute Command                 using sysbus
13    Execute Command                 mach create "risc-v"
14
15    Execute Command                 machine LoadPlatformDescriptionFromString "clint: IRQControllers.CoreLevelInterruptor @ sysbus 0x44000000 { frequency: 66000000 }"
16    Execute Command                 machine LoadPlatformDescriptionFromString "cpu: CPU.RiscV32 @ sysbus { timeProvider: clint; cpuType: \\"rv32gc\\" }"
17    Execute Command                 machine LoadPlatformDescriptionFromString "mem: Memory.MappedMemory @ sysbus 0x0 { size: 0x100000 }"
18    Execute Command                 machine LoadPlatformDescriptionFromString "iommu0: Miscellaneous.WindowIOMMU @ sysbus ${IOMMU_ADDR} { IRQ -> cpu@1 }"
19    Execute Command                 machine LoadPlatformDescriptionFromString "dma0: SimpleDMA @ { sysbus ${DMA_ADDR}; iommu0 0 }"
20
21    Execute Command                 sysbus WriteDoubleWord ${START_PC} 0x000000ef  # jal  ra, 0
22    Execute Command                 cpu PC ${START_PC}
23
24Write Range With Doublewords
25    [Arguments]                     ${start_addr}  ${length}  ${value}
26    ${end_addr}=                    Evaluate  ${start_addr}+${length}
27    ${bytesPerDoubleword}=          Evaluate  4
28    FOR   ${addr}  IN RANGE         ${start_addr}  ${end_addr}  ${bytesPerDoubleWord}
29        Execute Command             sysbus WriteDoubleWord ${addr} ${value}
30    END
31
32Write To Address By DMA
33    [Arguments]                     ${dma_addr_hex}  ${addr}  ${value}
34    ${dma_addr}=                    Convert To Integer  ${dma_addr_hex}
35    Execute Command                 sysbus WriteDoubleWord ${dma_addr+0} ${value}
36    Execute Command                 sysbus WriteDoubleWord ${dma_addr+4} ${addr}
37
38Read From Address By DMA
39    [Arguments]                     ${dma_addr_hex}  ${addr}
40    ${dma_addr}=                    Convert To Integer  ${dma_addr_hex}
41    Execute Command                 sysbus WriteDoubleWord ${dma_addr+8} ${addr}
42    ${read_value}=                  Execute Command  sysbus ReadDoubleWord ${dma_addr+0}
43    RETURN                          ${read_value}
44
45Define Window
46    [Arguments]                     ${window_index}  ${start_addr}  ${end_addr}  ${offset}  ${priv}
47
48    ${window_register}=             Evaluate  4 * ${window_index} + ${IOMMU_ADDR}
49    ${start_register}=              Evaluate  0x0 + ${window_register}
50    ${end_register}=                Evaluate  0x400 + ${window_register}
51    ${offset_register}=             Evaluate  0x800 + ${window_register}
52    ${priv_register}=               Evaluate  0xC00 + ${window_register}
53
54    Execute Command                 sysbus WriteDoubleWord ${start_register} ${start_addr}
55    Execute Command                 sysbus WriteDoubleWord ${end_register} ${end_addr}
56    Execute Command                 sysbus WriteDoubleWord ${offset_register} ${offset}
57    Execute Command                 sysbus WriteDoubleWord ${priv_register} ${priv}
58
59*** Test Cases ***
60Simple DMA Should Read And Write
61    Create Platform
62
63    Write Range With Doublewords    0x100  0x110  0x01234567
64    Define Window                   0  0x0  0x10000  0x0  ${PRIV_ALL}
65
66    Write To Address By DMA         ${DMA_ADDR}  0x104  0x89abcdef
67    ${written_value}=               Execute Command  sysbus ReadDoubleWord 0x104
68    Should Be Equal As Integers     ${written_value}  0x89abcdef
69
70    ${read_value}=                  Read From Address By DMA  ${DMA_ADDR}  0x100
71    Should Be Equal As Integers     ${read_value}  0x01234567
72
73    ${read_value}=                  Read From Address By DMA  ${DMA_ADDR}  0x104
74    Should Be Equal As Integers     ${read_value}  0x89abcdef
75
76Address Are Translated
77    Create Platform
78
79    Define Window                   0  0x1000  0x1100  256  ${PRIV_ALL}
80    Define Window                   1  0x1200  0x1300  -256  ${PRIV_ALL}
81
82    Write To Address By DMA         ${DMA_ADDR}  0x1000  0x01234567
83    ${read_value}=                  Execute Command  sysbus ReadDoubleWord 0x1100
84    Should Be Equal As Integers     ${read_value}  0x01234567
85    ${read_value}=                  Execute Command  sysbus ReadDoubleWord 0x1000
86    Should Be Equal As Integers     ${read_value}  0x0
87
88    Write To Address By DMA         ${DMA_ADDR}  0x1200  0x89abcdef
89    ${read_value}=                  Execute Command  sysbus ReadDoubleWord 0x1100
90    Should Be Equal As Integers     ${read_value}  0x89abcdef
91    ${read_value}=                  Execute Command  sysbus ReadDoubleWord 0x1000
92    Should Be Equal As Integers     ${read_value}  0x0
93
94IOMMU Fault Triggers IRQ
95    Create Platform
96    Create Log Tester               0
97    Execute Command                 logLevel -1
98
99    Define Window                   0  0x0000  0x1000  0x0  ${PRIV_NONE}
100    Start Emulation
101
102    Read From Address By DMA        ${DMA_ADDR}  0x0FFA
103    Wait For Log Entry              IOMMU fault at 0xFFA when trying to access as Read
104    Wait For Log Entry              Setting the IRQ
105    Wait For Log Entry              Setting CPU IRQ #1
106
107Permissions Are Respected
108    Create Platform
109    Create Log Tester               0
110    Execute Command                 logLevel -1
111
112    Define Window                   0  0x0000  0x1000  0x0  ${PRIV_NONE}
113    Define Window                   1  0x1000  0x2000  0x0  ${PRIV_ALL}
114    Write Range With Doublewords    0x1000  0x1FFF  0x01234567
115    Define Window                   3  0x2000  0x3000  0x0  ${PRIV_NONE}
116    Define Window                   5  0x3000  0x4000  0x0  ${PRIV_WRITE}
117    Define Window                   6  0x4000  0x5000  0x0  ${PRIV_READ}
118
119    Read From Address By DMA        ${DMA_ADDR}  0x0FFA
120    Wait For Log Entry              IOMMU fault at 0xFFA
121
122    Write To Address By DMA         ${DMA_ADDR}  0x0FFC  0x0
123    Wait For Log Entry              IOMMU fault at 0xFFC
124
125    Write To Address By DMA         ${DMA_ADDR}  0x1000  0x0
126    Should Not Be In Log            IOMMU fault at 0x1000
127
128    Write To Address By DMA         ${DMA_ADDR}  0x1FFF  0x0
129    Read From Address By DMA        ${DMA_ADDR}  0x1FFF
130    Should Not Be In Log            IOMMU fault at 0x1FFF
131
132    Write To Address By DMA         ${DMA_ADDR}  0x2000  0x0
133    Wait For Log Entry              IOMMU fault at 0x2000
134
135    Write To Address By DMA         ${DMA_ADDR}  0x3000  0x0
136    Should Not Be In Log            IOMMU fault at 0x3000
137
138    Read From Address By DMA        ${DMA_ADDR}  0x3000
139    Wait For Log Entry              IOMMU fault at 0x3000
140
141    Read From Address By DMA        ${DMA_ADDR}  0x4000
142    Should Not Be In Log            IOMMU fault at 0x4000
143
144    Write To Address By DMA         ${DMA_ADDR}  0x4000  0x0
145    Wait For Log Entry              IOMMU fault at 0x4000
146
147Throws Error On Registering Two IOMMUs For One Peripheral
148    Create Platform
149    Create Log Tester               0
150
151    Execute Command                 machine LoadPlatformDescriptionFromString "iommu1: Miscellaneous.WindowIOMMU @ sysbus 0x47000000"
152    Run Keyword And Expect Error    *Trying to change the BusController from *  Execute Command  machine LoadPlatformDescriptionFromString "dma1: SimpleDMA @ { sysbus 0x48000000; iommu0 1; iommu1 0 }"
153
154Defining Invalid Window Throws
155    # This test case doesn't check 64-bit unsigned integer overflow
156    Create Platform
157
158    Define Window                   0  0x0  0xffffffff  0x7fffffff  ${PRIV_NONE}
159    Define Window                   0  0x100  0x100  0x0  ${PRIV_NONE}
160    Define Window                   0  0x101  0x100  0  ${PRIV_NONE}
161    Wait For Log Entry              MMUWindow has start address .* grater than end address  treatAsRegex=true
162
163    Define Window                   0  0x100  0x1000  -256  ${PRIV_NONE}
164    Should Not Be In Log            MMUWindow has incorrect offset
165    Define Window                   0  0x100  0x1000  -257  ${PRIV_ALL}
166    Wait For Log Entry              MMUWindow has incorrect offset
167    Write To Address By DMA         ${DMA_ADDR}  0x200  0x0
168    Wait For Log Entry              The window at index .* match the address, but isn't validated sucesfully  treatAsRegex=true
169
170    Define Window                   0  0x100  0x1000  0  ${PRIV_NONE}
171    Define Window                   1  0x1000  0x1004  0  ${PRIV_NONE}
172    Define Window                   1  0xFFF  0x1004  0  ${PRIV_NONE}
173    Wait For Log Entry              MMUWindows .* overlap each other  treatAsRegex=true
174    Define Window                   1  0x000  0x101  0  ${PRIV_NONE}
175    Wait For Log Entry              MMUWindows .* overlap each other  treatAsRegex=true
176
177Restrict Access From Two Peripherals
178    Create Platform
179    Execute Command                 machine LoadPlatformDescriptionFromString "dma1: SimpleDMA @ { sysbus 0x48000000; iommu0 1 }"
180    Create Log Tester               0
181    Execute Command                 logLevel -1
182
183    Define Window                   0  0x0000  0x1000  0x0  ${PRIV_NONE}
184    Define Window                   1  0x1000  0x2000  0x0  ${PRIV_ALL}
185    Write Range With Doublewords    0x1000  0x1FFF  0x01234567
186
187    Write To Address By DMA         ${DMA_ADDR}  0x0FFC  0x0
188    Wait For Log Entry              IOMMU fault at 0xFFC
189
190    Write To Address By DMA         ${DMA_ADDR}  0x1000  0x0
191    Should Not Be In Log            IOMMU fault at 0x1000
192
193    Write To Address By DMA         0x48000000  0x0FFC  0x0
194    Wait For Log Entry              IOMMU fault at 0xFFC
195
196    Write To Address By DMA         0x48000000  0x1000  0x0
197    Should Not Be In Log            IOMMU fault at 0x1000
198