Skip to content

Commit 143b9c4

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

File tree

3 files changed

+287
-0
lines changed

3 files changed

+287
-0
lines changed
+13
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
+14
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

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
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+
39+
// Note that the test has commenced
40+
#if defined(__thumb__)
41+
"movs r2, #0\n" // LLD Command 2, Arg 1: Number to print (0)
42+
"bl lld_print_r2\n"
43+
#else
44+
"li a2, 0\n"
45+
"jal ra, lld_print_a2\n"
46+
#endif
47+
48+
49+
// Print all of the interesting starting values
50+
// 1. app_start: where app starts in flash
51+
// 2. mem_start: where app-accesible RAM starts
52+
// 3. memory_len: *total* length of app allocation (incl grant)
53+
// 4. app_heap_break: max app-accesible address
54+
// 5. the initial stack pointer when process was created
55+
// 6. the current stack pointer (should be same as 5)
56+
#if defined(__thumb__)
57+
"movs r2, #1\n"
58+
"movs r3, r4\n"
59+
"bl lld_print_r2r3\n"
60+
"movs r2, #2\n"
61+
"movs r3, r5\n"
62+
"bl lld_print_r2r3\n"
63+
"movs r2, #3\n"
64+
"movs r3, r6\n"
65+
"bl lld_print_r2r3\n"
66+
"movs r2, #4\n"
67+
"movs r3, r7\n"
68+
"bl lld_print_r2r3\n"
69+
"movs r2, #5\n"
70+
"movs r3, r8\n"
71+
"bl lld_print_r2r3\n"
72+
"movs r2, #6\n"
73+
"mov r3, sp\n"
74+
#else
75+
"li a2, 1\n"
76+
"mv a3, s0\n"
77+
"jal ra, lld_print_a2a3\n"
78+
"li a2, 2\n"
79+
"mv a3, s1\n"
80+
"jal ra, lld_print_a2a3\n"
81+
"li a2, 3\n"
82+
"mv a3, s2\n"
83+
"jal ra, lld_print_a2a3\n"
84+
"li a2, 4\n"
85+
"mv a3, s3\n"
86+
"jal ra, lld_print_a2a3\n"
87+
"li a2, 5\n"
88+
"mv a3, s4\n"
89+
"jal ra, lld_print_a2a3\n"
90+
"li a2, 6\n"
91+
"mv a3, sp\n"
92+
"jal ra, lld_print_a2a3\n"
93+
#endif
94+
95+
96+
// 7. Read all app-accessible memory: [mem_start , app_heap_break)
97+
// Assumed invariant: app_heap_break >= [mem_start + 4]
98+
#if defined(__thumb__)
99+
"movs r2, #7\n"
100+
"bl lld_print_r2\n"
101+
102+
"movs r3, r5\n" // r3 (loop var) = mem_start
103+
"test_7_loop:\n"
104+
"ldr r2, [r3]\n" // read *r3
105+
"add r3, r3, #4\n" // increment r3=r3+4
106+
"cmp r3, r7\n"
107+
"ble test_7_loop\n" // if r3 < app_heap_break[r7], loop
108+
#else
109+
"li a2, 7\n"
110+
"jal ra, lld_print_a2\n"
111+
112+
"mv t1, s1\n"
113+
"test_7_loop:\n"
114+
"lw t0, 0(t1)\n"
115+
"addi t1, t1, 4\n"
116+
"blt t1, s3, test_7_loop\n"
117+
#endif
118+
119+
120+
// 8. Write all app-accessible memory: [mem_start , app_heap_break)
121+
// Assumed invariant: app_heap_break >= [mem_start + 4]
122+
#if defined(__thumb__)
123+
"movs r2, #8\n"
124+
"bl lld_print_r2\n"
125+
126+
"movs r3, r5\n" // r3 (loop var) = mem_start
127+
"test_8_loop:\n"
128+
"str r2, [r3]\n" // read *r3
129+
"add r3, r3, #4\n" // increment r3=r3+4
130+
"cmp r3, r7\n"
131+
"ble test_8_loop\n" // if r3 < app_heap_break[r7], loop
132+
#else
133+
"li a2, 8\n"
134+
"jal ra, lld_print_a2\n"
135+
136+
"mv t1, s1\n"
137+
"test_8_loop:\n"
138+
"sw t0, 0(t1)\n"
139+
"addi t1, t1, 4\n"
140+
"blt t1, s3, test_8_loop\n"
141+
#endif
142+
143+
144+
// 9. Read all app-accessible flash: [app_start , memop(6))
145+
// Flash length is not a startup argument, so we must use
146+
// memop(6) to get the end of app flash first.
147+
#if defined(__thumb__)
148+
"movs r2, #9\n"
149+
"bl lld_print_r2\n"
150+
151+
"movs r0, #6\n"
152+
"movs r1, #0\n"
153+
"svc 5\n"
154+
"movs r11, r1\n"
155+
156+
"movs r2, #9\n"
157+
"movs r3, r11\n"
158+
"bl lld_print_r2r3\n"
159+
160+
"movs r3, r4\n" // r3 (loop var) = app_start
161+
"test_9_loop:\n"
162+
"ldr r2, [r3]\n" // read *r3
163+
"add r3, r3, #4\n" // increment r3=r3+4
164+
"cmp r3, r11\n"
165+
"ble test_9_loop\n" // if r3 < memop(6)[r11], loop
166+
#else
167+
"li a2, 9\n"
168+
"jal ra, lld_print_a2\n"
169+
170+
"li a0, 6\n"
171+
"li a1, 0\n"
172+
"li a4, 5\n"
173+
"ecall\n"
174+
"mv t2, a1\n"
175+
176+
"li a2, 9\n"
177+
"mv a3, t2\n"
178+
"jal ra, lld_print_a2a3\n"
179+
180+
"mv t1, s0\n"
181+
"test_9_loop:\n"
182+
"lw t0, 0(t1)\n"
183+
"addi t1, t1, 4\n"
184+
"blt t1, t2, test_9_loop\n"
185+
#endif
186+
187+
188+
// 10. Return success
189+
// Indicate all tests are done and exit.
190+
#if defined(__thumb__)
191+
"movs r2, #10\n"
192+
"bl lld_print_r2\n"
193+
194+
"movs r0, #0\n" // exit-terminate
195+
"movs r1, #0\n" // completion: sucess
196+
"svc 6\n" // Exit syscall
197+
#else
198+
"li a2, 10\n"
199+
"jal ra, lld_print_a2\n"
200+
201+
"li a0, 0\n"
202+
"li a1, 0\n"
203+
"li a4, 6\n"
204+
"ecall\n"
205+
#endif
206+
207+
208+
// -1. Unreachable/error
209+
#if defined(__thumb__)
210+
"loop_error:\n"
211+
"movs r2, #0\n"
212+
"sub r2, r2, #1\n"
213+
"bl lld_print_r2\n"
214+
"b loop_error\n"
215+
#else
216+
"loop_error:\n"
217+
"li a2, -1\n"
218+
"jal ra, lld_print_a2\n"
219+
"j loop_error\n"
220+
#endif
221+
222+
223+
224+
// Function to invoke LLD print of one number
225+
// r2/a2 must be set to desired number
226+
// may clobber any caller-save b/c of syscall rules
227+
#if defined(__thumb__)
228+
"lld_print_r2:\n"
229+
"movs r0, #8\n" // LLD is driver number 8
230+
"movs r1, #2\n" // LLD Command 2: Print one number
231+
"svc 2\n" // Invoke Command syscall
232+
"bx lr\n" // Return.
233+
#else
234+
"lld_print_a2:\n"
235+
"li a0, 8\n" // LLD is driver number 8
236+
"li a1, 2\n" // LLD Command 2: Print one number
237+
"li a4, 2\n" // Command is syscall 2
238+
"ecall\n" // Invoke Command syscall
239+
"jr ra\n" // Return.
240+
#endif
241+
242+
// Function to invoke LLD print of two numbers
243+
// r2,r3/a2,a3 must be set to desired number
244+
// may clobber any caller-save b/c of syscall rules
245+
#if defined(__thumb__)
246+
"lld_print_r2r3:\n"
247+
"movs r0, #8\n" // LLD is driver number 8
248+
"movs r1, #3\n" // LLD Command 3: Print one number
249+
"svc 2\n" // Invoke Command syscall
250+
"bx lr\n" // Return.
251+
#else
252+
"lld_print_a2a3:\n"
253+
"li a0, 8\n" // LLD is driver number 8
254+
"li a1, 3\n" // LLD Command 3: Print one number
255+
"li a4, 2\n" // Command is syscall 2
256+
"ecall\n" // Invoke Command syscall
257+
"jr ra\n" // Return.
258+
#endif
259+
);
260+
}

0 commit comments

Comments
 (0)