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
|
XBURST = {}
function XBURST.read_cp0(reg, sel)
return DEV.read32_cop({0, reg, sel})
end
function XBURST.write_cp0(reg, sel, val)
DEV.write32_cop({0, reg, sel}, val)
end
XBURST.prid_table = {
[0x0ad0024f] = "JZ4740",
[0x1ed0024f] = "JZ4755",
[0x2ed0024f] = "JZ4760(B)",
[0x3ee1024f] = "JZ4780"
}
XBURST.at_table = {
[0] = "MIPS32",
[1] = "MIPS64 with 32-bit segments",
[2] = "MIPS64"
}
XBURST.ar_table = {
[0] = "Release 1",
[1] = "Release 2 (or more)"
}
XBURST.mt_table = {
[0] = "None",
[1] = "Standard TLB",
[2] = "BAT",
[3] = "Fixed Mapping",
[4] = "Dual VTLB and FTLB"
}
XBURST.is_table = {
[0] = 64,
[1] = 128,
[2] = 256,
[3] = 512,
[4] = 1024,
[5] = 2048,
[6] = 4096,
[7] = 32
}
XBURST.il_table = {
[0] = 0,
[1] = 4,
[2] = 8,
[3] = 16,
[4] = 32,
[5] = 64,
[6] = 128
}
function XBURST.get_table_or(tbl, index, dflt)
if tbl[index] ~= nil then
return tbl[index]
else
return dflt
end
end
function XBURST.do_ebase_test()
XBURST.write_cp0(15, 1, 0x80000000)
print(string.format(" Value after writing 0x80000000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) ~= 0x80000000 then
return "Value 0x8000000 does not stick, EBASE is probably not working"
end
XBURST.write_cp0(15, 1, 0x80040000)
print(string.format(" Value after writing 0x80040000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) ~= 0x80040000 then
return "Value 0x80040000 does not stick, EBASE is probably not working"
end
return "EBase seems to work"
end
function XBURST.do_ebase_cfg7gate_test()
-- test gate in config7
config7_old = XBURST.read_cp0(16, 7)
XBURST.write_cp0(16, 7, bit32.replace(config7_old, 0, 7)) -- disable EBASE[30] modification
print(string.format(" Disable config7 gate: write 0x%x to Config7", bit32.replace(config7_old, 0, 7)))
XBURST.write_cp0(15, 1, 0xfffff000)
print(string.format(" Value after writing 0xfffff000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) == 0xfffff000 then
return "Config7 gate has no effect but modifications are allowed anyway"
end
XBURST.write_cp0(16, 7, bit32.replace(config7_old, 1, 7)) -- enable EBASE[30] modification
print(string.format(" Enable config7 gate: write 0x%x to Config7", bit32.replace(config7_old, 1, 7)))
XBURST.write_cp0(15, 1, 0xc0000000)
print(string.format(" Value after writing 0xc0000000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) ~= 0xc0000000 then
return "Config7 gate does not work"
end
XBURST.write_cp0(16, 7, config7_old)
return "Config7 gate seems to work"
end
function XBURST.do_ebase_exc_test(mem_addr)
if (mem_addr % 0x1000) ~= 0 then
return " memory address for exception test must aligned on a 0x1000 boundary";
end
print(string.format("Exception test with EBASE at 0x%x...", mem_addr))
print(" Writing instructions to memory")
-- create instructions in memory
exc_addr = mem_addr + 0x180 -- general exception vector
data_addr = mem_addr + 0x300
-- lui k0,<low part of data_addr>
-- ori k0,k0,<high part>
DEV.write32(exc_addr + 0, 0x3c1a0000 + bit32.rshift(data_addr, 16))
DEV.write32(exc_addr + 4, 0x375a0000 + bit32.band(data_addr, 0xffff))
-- lui k1,0xdead
-- ori k1,k1,0xbeef
DEV.write32(exc_addr + 8, 0x3c1bdead)
DEV.write32(exc_addr + 12, 0x377bbeef)
-- sw k1,0(k0)
DEV.write32(exc_addr + 16, 0xaf5b0000)
-- mfc0 k0,c0_epc
-- addi k0,k0,4
-- mtc0 k0,c0_epc
DEV.write32(exc_addr + 20, 0x401a7000)
DEV.write32(exc_addr + 24, 0x235a0004)
DEV.write32(exc_addr + 28, 0x409a7000)
-- eret
-- nop
DEV.write32(exc_addr + 32, 0x42000018)
DEV.write32(exc_addr + 36, 0)
-- fill data with some initial value
DEV.write32(data_addr, 0xcafebabe)
-- write instructions to trigger an interrupt
bug_addr = mem_addr
-- syscall
DEV.write32(bug_addr + 0, 0x0000000c)
-- jr ra
-- nop
DEV.write32(bug_addr + 4, 0x03e00008)
DEV.write32(bug_addr + 8, 0)
-- make sure we are the right shape for the test: SR should have BEV cleared,
-- mask all interrupts, enable interrupts
old_sr = XBURST.read_cp0(12, 0)
print(string.format(" Old SR: 0x%x", old_sr))
XBURST.write_cp0(12, 0, 0xfc00) -- BEV set to 0, all interrupts masked and interrupt disabled
print(string.format(" New SR: 0x%x", XBURST.read_cp0(12, 0)))
-- change EBASE
old_ebase = XBURST.read_cp0(15, 1)
XBURST.write_cp0(15, 1, mem_addr)
print(string.format(" EBASE: %x", XBURST.read_cp0(15, 1)))
-- test
print(string.format(" Before: %x", DEV.read32(data_addr)))
DEV.call(bug_addr)
print(string.format(" After: %x", DEV.read32(data_addr)))
success = DEV.read32(data_addr) == 0xdeadbeef
-- restore SR and EBASE
XBURST.write_cp0(12, 0, old_sr)
XBURST.write_cp0(15, 1, ebase_old)
return success and "Exception and EBASE are working" or "Exception and EBASE are NOT working"
end
function XBURST.test_ebase(mem_addr)
-- EBase
ebase_old = XBURST.read_cp0(15, 1)
sr_old = XBURST.read_cp0(12, 0)
print("Testing EBASE...")
print(" Disable BEV")
XBURST.write_cp0(12, 0, bit32.replace(sr_old, 0, 22)) -- clear BEV
print(string.format(" SR value: 0x%x", XBURST.read_cp0(12, 0)))
print(string.format(" EBASE value: 0x%x", ebase_old))
print(" Test result: " .. XBURST.do_ebase_test())
print(" Config7 result: " .. XBURST.do_ebase_cfg7gate_test())
XBURST.write_cp0(12, 0, sr_old)
XBURST.write_cp0(15, 1, ebase_old)
-- now try with actual exceptions
if mem_addr == nil then
print(" Not doing exception test, please specify memory to use: sram, ram")
return
end
print(" Exception result: " .. XBURST.do_ebase_exc_test(mem_addr))
end
function XBURST.test_ext_inst(mem_addr)
data_addr = mem_addr + 0x80
-----------
-- test ext
-----------
for pos = 0, 31 do
for size = 1, 32 - pos do
-- lui v0,<low part of data_addr>
-- addiu v0,v0,<high part>
-- lw v1,0(v0)
DEV.write32(mem_addr + 0, 0x3c020000 + bit32.rshift(data_addr, 16))
DEV.write32(mem_addr + 4, 0x8c430000 + bit32.band(data_addr, 0xffff))
DEV.write32(mem_addr + 8, 0x8c430000)
-- ext v1, v1, pos, size
DEV.write32(mem_addr + 12, 0x7c630000 + bit32.rshift(size - 1, 11) + bit32.rshift(pos, 6))
-- sw v1,0(v0)
DEV.write32(mem_addr + 16, 0xac430000)
-- jr ra
-- nop
DEV.write32(mem_addr + 20, 0x03e00008)
DEV.write32(mem_addr + 24, 0)
-- write some random data
data = math.random(0xffffffff)
print(string.format(" data: %x", data))
DEV.write32(data_addr, data)
DEV.call(mem_addr)
ext_data = DEV.read32(data_addr)
print(string.format(" result: %x vs %x", ext_data, bit32.extract(data, pos, size)))
break
end
break
end
end
function XBURST.test_ei_di_inst(mem_addr)
-- save SR and disable interrupts
old_sr = XBURST.read_cp0(12, 0)
XBURST.write_cp0(12, 0, bit32.replace(old_sr, 0, 0)) -- clear EI
print("Testing ei")
print(" Test SR")
print(" Enable interrupts with CP0")
XBURST.write_cp0(12, 0, bit32.replace(old_sr, 1, 0)) -- set EI
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
print(" Disable interrupts with CP0")
XBURST.write_cp0(12, 0, bit32.replace(old_sr, 0, 0)) -- clear EI
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
print(" Test ei/di")
print(" Enable interrupts with ei")
-- ei
-- jr ra
-- nop
DEV.write32(mem_addr + 4, 0x41606020)
DEV.write32(mem_addr + 4, 0x03e00008)
DEV.write32(mem_addr + 8, 0)
DEV.call(mem_addr)
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
print(" Disable interrupts with di")
-- di
DEV.write32(mem_addr + 4, 0x41606000)
DEV.call(mem_addr)
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
-- restore SR
XBURST.write_cp0(old_sr)
end
function XBURST.init()
-- enable CP1 in SR
sr_old = XBURST.read_cp0(12, 0)
XBURST.write_cp0(12, 0, bit32.replace(sr_old, 1, 29)) -- set CU1
print("XBurst:")
-- PRId
XBURST.prid = XBURST.read_cp0(15, 0)
print(string.format(" PRId: 0x%x", XBURST.prid))
print(" CPU: " .. XBURST.get_table_or(XBURST.prid_table, XBURST.prid, "unknown"))
-- Config
XBURST.config = XBURST.read_cp0(16, 0)
print(string.format(" Config: 0x%x", XBURST.config))
print(" Architecture Type: " .. XBURST.get_table_or(XBURST.at_table,
bit32.extract(XBURST.config, 13, 2), "unknown"))
print(" Architecture Level: " .. XBURST.get_table_or(XBURST.ar_table,
bit32.extract(XBURST.config, 10, 3), "unknown"))
print(" MMU Type: " .. XBURST.get_table_or(XBURST.mt_table,
bit32.extract(XBURST.config, 7, 3), "unknown"))
-- Config1
XBURST.config1 = XBURST.read_cp0(16, 1)
print(string.format(" Config1: 0x%x", XBURST.config1))
-- don't print of no MMU
if bit32.extract(XBURST.config, 7, 3) ~= 0 then
print(string.format(" MMU Size: %d", bit32.extract(XBURST.config1, 25, 6) + 1))
end
print(" ICache")
print(" Sets per way: " .. XBURST.get_table_or(XBURST.is_table,
bit32.extract(XBURST.config1, 22, 3), "unknown"))
print(" Ways: " .. (1 + bit32.extract(XBURST.config1, 16, 3)))
print(" Line size: " .. XBURST.get_table_or(XBURST.il_table,
bit32.extract(XBURST.config1, 19, 3), "unknown"))
print(" DCache")
print(" Sets per way: " .. XBURST.get_table_or(XBURST.is_table,
bit32.extract(XBURST.config1, 13, 3), "unknown"))
print(" Ways: " .. (1 + bit32.extract(XBURST.config1, 7, 3)))
print(" Line size: " .. XBURST.get_table_or(XBURST.il_table,
bit32.extract(XBURST.config1, 10, 3), "unknown"))
print(" FPU: " .. (bit32.extract(XBURST.config1, 0) == 1 and "yes" or "no"))
-- Config 2
XBURST.config2 = XBURST.read_cp0(16, 2)
print(string.format(" Config2: 0x%x", XBURST.config2))
-- Config 3
XBURST.config3 = XBURST.read_cp0(16, 3)
print(string.format(" Config3: 0x%x", XBURST.config3))
print(" Vectored interrupt: " .. (bit32.extract(XBURST.config2, 5) and "yes" or "no"))
-- Config 7
XBURST.config7 = XBURST.read_cp0(16, 7)
print(string.format(" Config7: 0x%x", XBURST.config7))
-- restore SR
XBURST.write_cp0(12, 0, sr_old)
end
|