1/*
2 * Copyright (c) 2015, Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#include <asm.h>
25#include <arch/asm_macros.h>
26#include <err.h>
27
28/**
29 * int mmutest_arch_rodata_pnx(void) - Test that rodata section is mapped pnx
30 *
31 * Returns ERR_FAULT if rodata is not executable.
32 * Return 0 if rodata is executable.
33 */
34.section .rodata
35.align 2
36	set_fault_handler	.Lmmutest_fault
37FUNCTION(mmutest_arch_rodata_pnx)
38	mov	x0, #0
39
40	ret
41
42/**
43 * int mmutest_arch_data_pnx(void) - Test that data section is mapped pnx
44 *
45 * Returns ERR_FAULT if data is not executable.
46 * Return 0 if data is executable.
47 */
48.section .data
49.align 2
50	set_fault_handler	.Lmmutest_fault
51FUNCTION(mmutest_arch_data_pnx)
52	mov	x0, #0
53
54	ret
55.section .text
56
57/**
58 * int mmutest_arch_rodata_ro(void) - Test that rodata section is mapped read-only
59 *
60 * Returns ERR_FAULT if rodata is not writable
61 * Returns 1 if write to rodata is silently dropped
62 * Returns 0 if rodata is writable
63 */
64FUNCTION(mmutest_arch_rodata_ro)
65	adrl	x0, .Ltest_rodata_long
66
67	set_fault_handler	.Lmmutest_fault
68	str	wzr, [x0]
69
70	ldr	w0, [x0]
71	ret
72
73.section .rodata
74.Ltest_rodata_long:
75	.long	0x1
76
77.section .text
78
79/**
80 * int mmutest_arch_store_uint32(uint32_t *ptr, bool user) - Test if ptr is writable
81 * @ptr:  Memory location to test
82 * @user: Use unprivileged store
83 *
84 * Returns ERR_FAULT if ptr is not writable
85 * Returns ERR_GENERIC if ptr is not readable
86 * Returns 2 if write does not fault, but data is lost on readback from memory
87 * Returns 1 if write does not fault, but data is lost on readback from cache
88 * Returns 0 if ptr is writable
89 */
90FUNCTION(mmutest_arch_store_uint32)
91	cbnz	x1, .Lmmutest_arch_store_uint32_user
92
93	set_fault_handler	.Lmmutest_setup_fault
94	ldr	w3, [x0]
95	mvn	w3, w3
96
97	set_fault_handler	.Lmmutest_fault
98	str	w3, [x0]
99	dmb	sy
100	ldr	w2, [x0]
101
102	b	.Lmmutest_arch_store_uint32_str_done
103
104.Lmmutest_arch_store_uint32_user:
105	set_fault_handler	.Lmmutest_setup_fault
106	ldtr	w3, [x0]
107	mvn	w3, w3
108
109	set_fault_handler	.Lmmutest_fault
110	sttr	w3, [x0]
111	dmb	sy
112	ldtr	w2, [x0]
113
114.Lmmutest_arch_store_uint32_str_done:
115
116	cmp	w3, w2
117	bne	.Lmmutest_arch_store_uint32_cache_read_mismatch
118
119	push	x0, x1
120	push	x3, x30
121	mov	x1, #4
122	bl	arch_clean_invalidate_cache_range
123	pop	x3, x30
124	pop	x0, x1
125
126	cbnz	x1, .Lmmutest_arch_store_uint32_memory_reload_user
127
128	ldr	w2, [x0]
129	b	.Lmmutest_arch_store_uint32_memory_reload_done
130
131.Lmmutest_arch_store_uint32_memory_reload_user:
132	ldtr	w2, [x0]
133
134.Lmmutest_arch_store_uint32_memory_reload_done:
135	cmp	w3, w2
136	bne	.Lmmutest_arch_store_uint32_memory_mismatch
137
138	mov	x0, xzr
139	ret
140
141.Lmmutest_arch_store_uint32_cache_read_mismatch:
142	mov	x0, #1
143	ret
144
145.Lmmutest_arch_store_uint32_memory_mismatch:
146	mov	x0, #2
147	ret
148
149/**
150 * int mmutest_arch_nop(int ret) - Return ret
151 *
152 * Returns ret if run from executable page.
153 * Does not return if run from non-executable page.
154 */
155FUNCTION(mmutest_arch_nop)
156	ret
157FUNCTION(mmutest_arch_nop_end)
158
159.Lmmutest_setup_fault:
160	mov	x0, #ERR_GENERIC
161	ret
162
163.Lmmutest_fault:
164	mov	x0, #ERR_FAULT
165	ret
166