Skip to content

Commit 301cd99

Browse files
committed
tests: add an MPU test that circumvents libc
1 parent 39f83a8 commit 301cd99

File tree

3 files changed

+278
-0
lines changed

3 files changed

+278
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Makefile for user application
2+
3+
# Specify this directory relative to the current application.
4+
TOCK_USERLAND_BASE_DIR = ../../../..
5+
6+
# Which files to compile.
7+
C_SRCS := $(wildcard *.c)
8+
9+
STACK_SIZE := 1024
10+
11+
# Include userland master makefile. Contains rules and flags for actually
12+
# building the application.
13+
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
MPU No LibC
2+
===========
3+
4+
This test verifies that an application can read and write all of the memory it
5+
has been allocated in ram, and can read all of its memory in flash.
6+
7+
This test is raw assembly, and circumvents the usual libtock-c crt0 and any
8+
other userspace startup. Of note, the application will never call `brk` or
9+
`sbrk` or any other `memop` which would change the application memory layout
10+
beyond the initial configuration provided by the kernel.
11+
12+
The application uses low-level debug to print its progress. A successful run
13+
will see debug numbers [0,10], and then terminate the process with a successful
14+
exit code.

examples/tests/mpu/mpu_no_libc/main.c

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
/* vim: set sw=2 expandtab tw=80: */
2+
3+
// Allow _start to go undeclared
4+
#pragma GCC diagnostic ignored "-Wmissing-declarations"
5+
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
6+
7+
__attribute__ ((section(".start"), used))
8+
__attribute__ ((naked))
9+
__attribute__ ((noreturn))
10+
void _start(void* app_start __attribute__((unused)),
11+
void* mem_start __attribute__((unused)),
12+
void* memory_len __attribute__((unused)),
13+
void* app_heap_break __attribute__((unused))) {
14+
__asm__ volatile (
15+
// This minimal test evaluates whether memory protection is configured
16+
// as-expected. It uses the low-level debug (LLD) mechanism to print
17+
// incremental numbers as it progresses, but provides no other output as it is
18+
// all assembly to precisely control behavior (and never sets up a stack
19+
// beyond the minimal one provided by the kernel).
20+
21+
// First, save all the variables in hardware-stacked, callee-save registers
22+
#if defined(__thumb__)
23+
"movs r4, r0\n" // r4 = app_start
24+
"movs r5, r1\n" // r5 = mem_start
25+
"movs r6, r2\n" // r6 = memory_len
26+
"movs r7, r3\n" // r7 = app_heap_break
27+
"mov r8, sp\n" // r8 = stack pointer
28+
#elif defined(__riscv)
29+
"mv s0, a0\n" // s0 = app_start
30+
"mv s1, a1\n" // s1 = mem_start
31+
"mv s2, a2\n" // s2 = memory_len
32+
"mv s3, a3\n" // s3 = app_heap_break
33+
"mv s4, sp\n" // s4 = stack pointer
34+
#else
35+
#error Unknown arch. Note: Subsequent code assumes only two archs.
36+
#endif
37+
38+
// Note that the test has commenced
39+
#if defined(__thumb__)
40+
"movs r2, #0\n" // LLD Command 2, Arg 1: Number to print (0)
41+
"bl lld_print_r2\n"
42+
#else
43+
"li a2, 0\n"
44+
"jal ra, lld_print_a2\n"
45+
#endif
46+
47+
// Print all of the interesting starting values
48+
// 1. app_start: where app starts in flash
49+
// 2. mem_start: where app-accesible RAM starts
50+
// 3. memory_len: *total* length of app allocation (incl grant)
51+
// 4. app_heap_break: max app-accesible address
52+
// 5. the initial stack pointer when process was created
53+
// 6. the current stack pointer (should be same as 5)
54+
#if defined(__thumb__)
55+
"movs r2, #1\n"
56+
"movs r3, r4\n"
57+
"bl lld_print_r2r3\n"
58+
"movs r2, #2\n"
59+
"movs r3, r5\n"
60+
"bl lld_print_r2r3\n"
61+
"movs r2, #3\n"
62+
"movs r3, r6\n"
63+
"bl lld_print_r2r3\n"
64+
"movs r2, #4\n"
65+
"movs r3, r7\n"
66+
"bl lld_print_r2r3\n"
67+
"movs r2, #5\n"
68+
"movs r3, r8\n"
69+
"bl lld_print_r2r3\n"
70+
"movs r2, #6\n"
71+
"mov r3, sp\n"
72+
#else
73+
"li a2, 1\n"
74+
"mv a3, s0\n"
75+
"jal ra, lld_print_a2a3\n"
76+
"li a2, 2\n"
77+
"mv a3, s1\n"
78+
"jal ra, lld_print_a2a3\n"
79+
"li a2, 3\n"
80+
"mv a3, s2\n"
81+
"jal ra, lld_print_a2a3\n"
82+
"li a2, 4\n"
83+
"mv a3, s3\n"
84+
"jal ra, lld_print_a2a3\n"
85+
"li a2, 5\n"
86+
"mv a3, s4\n"
87+
"jal ra, lld_print_a2a3\n"
88+
"li a2, 6\n"
89+
"mv a3, sp\n"
90+
"jal ra, lld_print_a2a3\n"
91+
#endif
92+
93+
// 7. Read all app-accessible memory: [mem_start , app_heap_break)
94+
// Assumed invariant: app_heap_break >= [mem_start + 4]
95+
#if defined(__thumb__)
96+
"movs r2, #7\n"
97+
"bl lld_print_r2\n"
98+
99+
"movs r3, r5\n" // r3 (loop var) = mem_start
100+
"test_7_loop:\n"
101+
"ldr r2, [r3]\n" // read *r3
102+
"add r3, r3, #4\n" // increment r3=r3+4
103+
"cmp r3, r7\n"
104+
"ble test_7_loop\n" // if r3 < app_heap_break[r7], loop
105+
#else
106+
"li a2, 7\n"
107+
"jal ra, lld_print_a2\n"
108+
109+
"mv t1, s1\n"
110+
"test_7_loop:\n"
111+
"lw t0, 0(t1)\n"
112+
"addi t1, t1, 4\n"
113+
"blt t1, s3, test_7_loop\n"
114+
#endif
115+
116+
// 8. Write all app-accessible memory: [mem_start , app_heap_break)
117+
// Assumed invariant: app_heap_break >= [mem_start + 4]
118+
#if defined(__thumb__)
119+
"movs r2, #8\n"
120+
"bl lld_print_r2\n"
121+
122+
"movs r3, r5\n" // r3 (loop var) = mem_start
123+
"test_8_loop:\n"
124+
"str r2, [r3]\n" // read *r3
125+
"add r3, r3, #4\n" // increment r3=r3+4
126+
"cmp r3, r7\n"
127+
"ble test_8_loop\n" // if r3 < app_heap_break[r7], loop
128+
#else
129+
"li a2, 8\n"
130+
"jal ra, lld_print_a2\n"
131+
132+
"mv t1, s1\n"
133+
"test_8_loop:\n"
134+
"sw t0, 0(t1)\n"
135+
"addi t1, t1, 4\n"
136+
"blt t1, s3, test_8_loop\n"
137+
#endif
138+
139+
// 9. Read all app-accessible flash: [app_start , memop(6))
140+
// Flash length is not a startup argument, so we must use
141+
// memop(6) to get the end of app flash first.
142+
#if defined(__thumb__)
143+
"movs r2, #9\n"
144+
"bl lld_print_r2\n"
145+
146+
"movs r0, #6\n"
147+
"movs r1, #0\n"
148+
"svc 5\n"
149+
"movs r11, r1\n"
150+
151+
"movs r2, #9\n"
152+
"movs r3, r11\n"
153+
"bl lld_print_r2r3\n"
154+
155+
"movs r3, r4\n" // r3 (loop var) = app_start
156+
"test_9_loop:\n"
157+
"ldr r2, [r3]\n" // read *r3
158+
"add r3, r3, #4\n" // increment r3=r3+4
159+
"cmp r3, r11\n"
160+
"ble test_9_loop\n" // if r3 < memop(6)[r11], loop
161+
#else
162+
"li a2, 9\n"
163+
"jal ra, lld_print_a2\n"
164+
165+
"li a0, 6\n"
166+
"li a1, 0\n"
167+
"li a4, 5\n"
168+
"ecall\n"
169+
"mv t2, a1\n"
170+
171+
"li a2, 9\n"
172+
"mv a3, t2\n"
173+
"jal ra, lld_print_a2a3\n"
174+
175+
"mv t1, s0\n"
176+
"test_9_loop:\n"
177+
"lw t0, 0(t1)\n"
178+
"addi t1, t1, 4\n"
179+
"blt t1, t2, test_9_loop\n"
180+
#endif
181+
182+
// 10. Return success
183+
// Indicate all tests are done and exit.
184+
#if defined(__thumb__)
185+
"movs r2, #10\n"
186+
"bl lld_print_r2\n"
187+
188+
"movs r0, #0\n" // exit-terminate
189+
"movs r1, #0\n" // completion: sucess
190+
"svc 6\n" // Exit syscall
191+
#else
192+
"li a2, 10\n"
193+
"jal ra, lld_print_a2\n"
194+
195+
"li a0, 0\n"
196+
"li a1, 0\n"
197+
"li a4, 6\n"
198+
"ecall\n"
199+
#endif
200+
201+
// -1. Unreachable/error
202+
#if defined(__thumb__)
203+
"loop_error:\n"
204+
"movs r2, #0\n"
205+
"sub r2, r2, #1\n"
206+
"bl lld_print_r2\n"
207+
"b loop_error\n"
208+
#else
209+
"loop_error:\n"
210+
"li a2, -1\n"
211+
"jal ra, lld_print_a2\n"
212+
"j loop_error\n"
213+
#endif
214+
215+
// Function to invoke LLD print of one number
216+
// r2/a2 must be set to desired number
217+
// may clobber any caller-save b/c of syscall rules
218+
#if defined(__thumb__)
219+
"lld_print_r2:\n"
220+
"movs r0, #8\n" // LLD is driver number 8
221+
"movs r1, #2\n" // LLD Command 2: Print one number
222+
"svc 2\n" // Invoke Command syscall
223+
"bx lr\n" // Return.
224+
#else
225+
"lld_print_a2:\n"
226+
"li a0, 8\n" // LLD is driver number 8
227+
"li a1, 2\n" // LLD Command 2: Print one number
228+
"li a4, 2\n" // Command is syscall 2
229+
"ecall\n" // Invoke Command syscall
230+
"jr ra\n" // Return.
231+
#endif
232+
233+
// Function to invoke LLD print of two numbers
234+
// r2,r3/a2,a3 must be set to desired number
235+
// may clobber any caller-save b/c of syscall rules
236+
#if defined(__thumb__)
237+
"lld_print_r2r3:\n"
238+
"movs r0, #8\n" // LLD is driver number 8
239+
"movs r1, #3\n" // LLD Command 3: Print one number
240+
"svc 2\n" // Invoke Command syscall
241+
"bx lr\n" // Return.
242+
#else
243+
"lld_print_a2a3:\n"
244+
"li a0, 8\n" // LLD is driver number 8
245+
"li a1, 3\n" // LLD Command 3: Print one number
246+
"li a4, 2\n" // Command is syscall 2
247+
"ecall\n" // Invoke Command syscall
248+
"jr ra\n" // Return.
249+
#endif
250+
);
251+
}

0 commit comments

Comments
 (0)