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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
|
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
import sys, pathlib
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
from contextlib import contextmanager
from m1n1.setup import *
from m1n1.find_regs import *
from m1n1 import asm
p.smp_start_secondaries()
class ARMPageTable:
PAGESIZE = 0x4000
def __init__(self, memalign, free):
self.memalign = memalign
self.free = free
self.l0 = self.memalign(self.PAGESIZE, self.PAGESIZE)
self.l1 = [self.memalign(self.PAGESIZE, self.PAGESIZE), self.memalign(
self.PAGESIZE, self.PAGESIZE)]
self.l2 = {}
p.write64(self.l0, self.make_table_pte(self.l1[0]))
p.write64(self.l0+8, self.make_table_pte(self.l1[1]))
def make_table_pte(self, addr):
# table mapping, access bit set
return addr | 0b11 | (1 << 10)
def map_page(self, vaddr, paddr, access_bits):
ap = (access_bits & 0b1100) >> 2
pxn = (access_bits & 0b0010) >> 1
uxn = (access_bits & 0b0001)
# block mapping, access bit set
pte = paddr | 0b01 | (1 << 10)
# move access bits in place
pte |= ap << 6
pte |= pxn << 54
pte |= uxn << 53
l0_idx = (vaddr >> (25+11+11)) & 1
l1_idx = (vaddr >> (25+11)) & 0x7ff
l2_idx = (vaddr >> 25) & 0x7ff
tbl = self.l2.get((l0_idx, l1_idx), None)
if not tbl:
tbl = self.memalign(self.PAGESIZE, self.PAGESIZE)
self.l2[(l0_idx, l1_idx)] = tbl
p.write64(self.l1[l0_idx] + 8*l1_idx, self.make_table_pte(tbl))
p.write64(tbl + 8*l2_idx, pte)
def map(self, vaddr, paddr, sz, access_bits):
assert sz % 0x2000000 == 0
assert vaddr % 0x2000000 == 0
assert paddr % 0x2000000 == 0
assert access_bits <= 0b1111
while sz > 0:
self.map_page(vaddr, paddr, access_bits)
sz -= 0x2000000
vaddr += 0x2000000
paddr += 0x2000000
def build_and_write_code(heap, code):
page = heap.memalign(0x4000, 0x4000)
compiled = asm.ARMAsm(code, page).data
iface.writemem(page, compiled)
p.dc_cvau(page, len(compiled))
p.ic_ivau(page, len(compiled))
return page
def setup_exception_vectors(heap, gxf=False):
if gxf:
elr = "S3_6_C15_C10_6"
eret = ".long 0x201400"
indicator = 0xf2
else:
elr = "ELR_EL1"
eret = "eret"
indicator = 0xf0
return build_and_write_code(heap, """
.rept 16
b 1f
.align 7
.endr
1:
// store that we failed
mov x10, 0x{indicator:x}
// move PC two instruction further and clear 0xf0 0000 0000 to
// make sure we end up in the r-x mapping either way and don't
// repeat the instruction that just faulted
// we skip the second instruction since that one is used to
// indicate success
ldr x11, =0x0fffffffff
mrs x12, {elr}
add x12, x12, #8
and x12, x12, x11
msr {elr}, x12
isb
{eret}
""".format(eret=eret, elr=elr, indicator=indicator))
print("Setting up..")
pagetable = ARMPageTable(u.memalign, u.free)
pagetable.map(0x800000000, 0x800000000, 0xc00000000, 0)
pagetable.map(0xf800000000, 0x800000000, 0xc00000000, 1)
el2_vectors = setup_exception_vectors(u.heap, gxf=False)
gl2_vectors = setup_exception_vectors(u.heap, gxf=True)
probe_page = build_and_write_code(u.heap, "mov x10, 0x80\nret\nret\nret\n")
probe_page_vaddr = probe_page | 0xf000000000
code_page = build_and_write_code(u.heap, """
#define SPRR_PERM_EL0 S3_6_C15_C1_5
#define SPRR_PERM_EL1 S3_6_C15_C1_6
#define SPRR_PERM_EL2 S3_6_C15_C1_7
#define GXF_CONFIG_EL2 s3_6_c15_c1_2
#define GXF_ENTER_EL2 s3_6_c15_c8_1
#define GXF_ABORT_EL2 s3_6_c15_c8_2
#define MPIDR_GL2 S3_6_C15_C10_1
#define VBAR_GL2 S3_6_C15_C10_2
#define SPSR_GL2 S3_6_C15_C10_3
#define ELR_GL2 S3_6_C15_C10_6
#define FAR_GL2 S3_6_C15_C10_7
#define genter .long 0x00201420
#define gexit .long 0x201400
// just store everything since i'm too lazy to think about
// register assignments
str x30, [sp, #-16]!
stp x28, x29, [sp, #-16]!
stp x26, x27, [sp, #-16]!
stp x24, x25, [sp, #-16]!
stp x22, x23, [sp, #-16]!
stp x20, x21, [sp, #-16]!
stp x18, x19, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x4, x5, [sp, #-16]!
stp x2, x3, [sp, #-16]!
stp x0, x1, [sp, #-16]!
mov x20, x0 // store SPRR value for later
mov x21, 0 // clear result
// setup exception vectors
ldr x0, =0x{vectors:x}
msr VBAR_EL2, x0
isb
// prepare MMU
ldr x0, =0x0400ff
msr MAIR_EL1, x0
ldr x0, =0x27510b510
msr TCR_EL1, x0
ldr x0, =0x{ttbr:x}
msr TTBR0_EL2, x0
// enable SPPR
mov x0, 1
msr s3_6_c15_c1_0, x0
msr s3_6_c15_c1_3, xzr
isb
// clear all SPPR registers
// (note that reads from/writes to EL1 will be redirected to EL2 anyway)
ldr x0, =0
msr SPRR_PERM_EL0, x0
msr SPRR_PERM_EL1, x0
msr SPRR_PERM_EL2, x0
msr s3_6_c15_c1_3, x0
// setup SPPR_EL2
msr SPRR_PERM_EL2, x20
isb
dsb ishst
tlbi vmalle1is
dsb ish
isb
msr s3_6_c15_c1_3, xzr
isb
// enable MMU
ldr x1, =0x1005
mrs x0, SCTLR_EL1
mov x3, x0
orr x0, x0, x1
msr SCTLR_EL1, x0
isb
// configure and enable GXF
mov x0, 1
msr GXF_CONFIG_EL2, x0
isb
ldr x0, =gxf_entry
msr GXF_ENTER_EL2, x0
ldr x0, =gxf_abort
msr GXF_ABORT_EL2, x0
isb
// test GXF access
genter
// test execute access
ldr x1, =0x{probe_page:x}
mov x10, 0
blr x1
lsl x21, x21, #8
orr x21, x21, x10
// test read access
ldr x1, =0x{probe_page:x}
mov x10, 0
ldr x1, [x1]
mov x10, 0x80
lsl x21, x21, #8
orr x21, x21, x10
// test write access
ldr x1, =0x{probe_page:x}
add x1, x1, 0x20
mov x10, 0
str x1, [x1]
mov x10, 0x80
lsl x21, x21, #8
orr x21, x21, x10
// disable MMU again
dsb ish
isb
msr SCTLR_EL1, x3
isb
mov x0, 0
msr GXF_CONFIG_EL2, x0
msr s3_6_c15_c1_0, x0
mov x0, x21
// restore everything except for x0
add sp, sp, #8
ldr x1, [sp], #8
ldp x2, x3, [sp], #16
ldp x4, x5, [sp], #16
ldp x6, x7, [sp], #16
ldp x8, x9, [sp], #16
ldp x10, x11, [sp], #16
ldp x12, x13, [sp], #16
ldp x14, x15, [sp], #16
ldp x16, x17, [sp], #16
ldp x18, x19, [sp], #16
ldp x20, x21, [sp], #16
ldp x22, x23, [sp], #16
ldp x24, x25, [sp], #16
ldp x26, x27, [sp], #16
ldp x28, x29, [sp], #16
ldr x30, [sp], #16
ret
gxf_entry:
// setup GL exception vectors
ldr x0, =0x{gxf_vectors:x}
msr VBAR_GL2, x0
isb
// we might double fault -> store state here
mrs x14, S3_6_C15_C10_3
mrs x15, S3_6_C15_C10_4
mrs x16, S3_6_C15_C10_5
mrs x17, ELR_GL2
mrs x18, FAR_GL2
// test execute access
ldr x1, =0x{probe_page:x}
mov x10, 0
blr x1
lsl x21, x21, #8
orr x21, x21, x10
// test read access
ldr x1, =0x{probe_page:x}
mov x10, 0
ldr x1, [x1]
mov x10, 0x80
lsl x21, x21, #8
orr x21, x21, x10
// test write access
ldr x1, =0x{probe_page:x}
add x1, x1, #0x20
mov x10, 0
str x1, [x1]
mov x10, 0x80
lsl x21, x21, #8
orr x21, x21, x10
// restore state in case we faulted in here
msr S3_6_C15_C10_3, x14
msr S3_6_C15_C10_4, x15
msr S3_6_C15_C10_5, x16
msr ELR_GL2, x17
msr FAR_GL2, x18
isb
gexit
gxf_abort:
// store that we failed
mov x10, 0xf1
// move PC two instruction further and clear 0xf0 0000 0000 to
// make sure we end up in the r-x mapping either way and don't
// repeat the instruction that just faulted
// we skip the second instruction since that one is used to
// indicate success
ldr x11, =0x0fffffffff
mrs x12, ELR_GL2
add x12, x12, #8
and x12, x12, x11
msr ELR_GL2, x12
isb
gexit
""".format(ttbr=pagetable.l0, vectors=el2_vectors, probe_page=probe_page_vaddr, gxf_vectors=gl2_vectors))
print("Running code now...")
for i in range(0x10):
sprr_val = 0x5 | ((i & 0xf) << 4)
ret = p.smp_call_sync(1, code_page, sprr_val)
glret = ret >> 24
glx = 'x' if (glret >> 16) & 0xff == 0x80 else '-'
glr = 'r' if (glret >> 8) & 0xff == 0x80 else '-'
glw = 'w' if glret & 0xff == 0x80 else '-'
x = 'x' if (ret >> 16) & 0xff == 0x80 else '-'
r = 'r' if (ret >> 8) & 0xff == 0x80 else '-'
w = 'w' if ret & 0xff == 0x80 else '-'
print("SPRR: {0:04b} result: {1:x} GL: {2}{3}{4} EL: {5}{6}{7}".format(
i, ret, glr, glw, glx, r, w, x))
|