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	set_fault_handler	.Lmmutest_fault
36FUNCTION(mmutest_arch_rodata_pnx)
37	xor	%eax, %eax
38
39	ret
40
41/**
42 * int mmutest_arch_data_pnx(void) - Test that data section is mapped pnx
43 *
44 * Returns ERR_FAULT if data is not executable.
45 * Return 0 if data is executable.
46 */
47.section .data
48	set_fault_handler	.Lmmutest_fault
49FUNCTION(mmutest_arch_data_pnx)
50	xor	%eax, %eax
51
52	ret
53.section .text
54
55/**
56 * int mmutest_arch_rodata_ro(void) - Test that rodata section is mapped read-only
57 *
58 * Returns ERR_FAULT if rodata is not writable
59 * Returns 1 if write to rodata is silently dropped
60 * Returns 0 if rodata is writable
61 */
62FUNCTION(mmutest_arch_rodata_ro)
63	leaq	.Ltest_rodata_long(%rip), %rax
64
65	set_fault_handler	.Lmmutest_fault
66	movl	$0, (%rax)
67
68	movl	(%rax), %eax
69	ret
70
71.section .rodata
72	.balign	4
73.Ltest_rodata_long:
74	.long	0x1
75
76.section .text
77
78/**
79 * int mmutest_arch_store_uint32(uint32_t *ptr, bool user) - Test if ptr is writable
80 * @ptr:  Memory location to test
81 * @user: Use unprivileged store
82 *
83 * Returns ERR_FAULT if ptr is not writable
84 * Returns ERR_GENERIC if ptr is not readable
85 * Returns 2 if write does not fault, but data is lost on readback from memory
86 * Returns 1 if write does not fault, but data is lost on readback from cache
87 * Returns 0 if ptr is writable
88 */
89FUNCTION(mmutest_arch_store_uint32)
90	test	%sil, %sil
91	jnz	.Lmmutest_arch_store_uint32_user
92
93	set_fault_handler	.Lmmutest_setup_fault
94	movl	(%rdi), %edx
95	not	%edx
96
97	set_fault_handler	.Lmmutest_fault
98	movl	%edx, (%rdi)
99	mfence
100	movl	(%rdi), %ecx
101
102	jmp	.Lmmutest_arch_store_uint32_str_done
103
104.Lmmutest_arch_store_uint32_user:
105	/* TODO: call helper functions to write then read from user-space */
106	movl	$ERR_NOT_IMPLEMENTED, %eax
107	ret
108
109.Lmmutest_arch_store_uint32_str_done:
110
111	cmp	%edx, %ecx
112	jne	.Lmmutest_arch_store_uint32_cache_read_mismatch
113
114	push	%rdi
115	push	%rsi
116	push	%rdx
117	movq	$4, %rsi
118	call	arch_clean_invalidate_cache_range
119	pop	%rdx
120	pop	%rsi
121	pop	%rdi
122
123	test	%sil, %sil
124	jnz	.Lmmutest_arch_store_uint32_memory_reload_user
125
126	movl	(%rdi), %ecx
127	jmp	.Lmmutest_arch_store_uint32_memory_reload_done
128
129.Lmmutest_arch_store_uint32_memory_reload_user:
130	/* TODO: call helper function to read from user-space */
131
132.Lmmutest_arch_store_uint32_memory_reload_done:
133	cmp	%edx, %ecx
134	jne	.Lmmutest_arch_store_uint32_memory_mismatch
135
136	xor	%eax, %eax
137	ret
138
139.Lmmutest_arch_store_uint32_cache_read_mismatch:
140	movl	$1, %eax
141	ret
142
143.Lmmutest_arch_store_uint32_memory_mismatch:
144	movl	$2, %eax
145	ret
146
147/**
148 * int mmutest_arch_nop(int ret) - Return ret
149 *
150 * Returns ret if run from executable page.
151 * Does not return if run from non-executable page.
152 */
153FUNCTION(mmutest_arch_nop)
154	ret
155FUNCTION(mmutest_arch_nop_end)
156
157.Lmmutest_setup_fault:
158	movl	$ERR_GENERIC, %eax
159	ret
160
161.Lmmutest_fault:
162	movl	$ERR_FAULT, %eax
163	ret
164