Skip to content

Commit 1f5aefd

Browse files
committed
Enable hardware stack zeroing.
This replaces the software stack zeroing path with offload to a hardware engine, when available. The hardware zeroing pipeline is controlled by the ZTOP SCR (currently assumed to be number 27). This zeroes from the top of the capability in ZTOP to the bottom. We assume that short-lived cross-compartment calls or returns from deeply nested calls will result in ranges where each is a subset of another, so we try to coalesce. We could probably do better aggregating overlapping but not subset ranges.
1 parent 452d404 commit 1f5aefd

File tree

5 files changed

+118
-22
lines changed

5 files changed

+118
-22
lines changed

sdk/core/loader/boot.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ namespace
787787
threadTStack->mstatus =
788788
(priv::MSTATUS_MPIE |
789789
(priv::MSTATUS_PRV_M << priv::MSTATUS_MPP_SHIFT));
790-
#ifdef CONFIG_MSHWM
790+
#ifdef CHERIOT_HAS_MSHWM
791791
threadTStack->mshwm = stack.top();
792792
threadTStack->mshwmb = stack.base();
793793
#endif

sdk/core/switcher/entry.S

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@
1818
*/
1919
#define CSR_MSHWMB 0xbc2
2020

21+
/**
22+
* The special capability register for the fast zeroing control.
23+
* Writing a capability here starts zeroing from the address of this register
24+
* down to the base.
25+
*
26+
* TODO: This is a made up number, it might need to be a different one.
27+
*/
28+
#define SCR_ZTOP 0x1c
29+
2130
#define MAX_FAULTS_PER_COMPARTMENT_CALL 1024
2231

2332
#define SPILL_SLOT_cs0 0
@@ -126,6 +135,46 @@ switcher_scheduler_entry_csp:
126135
* and integer register. All three registers are clobbered.
127136
*/
128137
.macro zero_stack base top scratch
138+
#ifdef CHERIOT_HAS_ZTOP
139+
// Derive the capability to the range that should be zeroed.
140+
// This is stored in base, leaving top as a second scratch register to use
141+
csub \top, c\top, c\base
142+
csetboundsexact c\base, c\base, \top
143+
144+
// Wait for any prior zeroing to finish.
145+
cspecialr c\scratch, SCR_ZTOP
146+
// If ztop is untagged, no zeroing is happening and our attempt to store
147+
// relative to ztop will trap.
148+
cgettag \top, c\scratch
149+
beqz \top, 2f
150+
// If we've already reached the bottom then do nothing.
151+
// NOTE: This can be deleted if ZTOP's tag is cleared when zeroing finishes.
152+
cgetbase \top, c\scratch
153+
beq \top, \scratch, 2f
154+
// If the current zeroing range is a subset of range that we're about to
155+
// zero, don't bother waiting, just zero from the start.
156+
ctestsubset \top, c\base, c\scratch
157+
bnez \top, 2f
158+
// If the requested range is a subset of the previous requested range,
159+
// restart zeroing that instead
160+
// NOTE: This may result in zeroing things too many times, we're trading
161+
// some throughput for latency here. This might be the wrong choice.
162+
ctestsubset \top, c\scratch, c\base
163+
bnez \top, 1f
164+
// Store a byte at the bottom of the zeroed region. This will block until
165+
// we've finished the zeroing.
166+
cgetbase \top, c\scratch
167+
csetaddr c\top, c\scratch, \top
168+
csb zero, 0(c\top)
169+
j 2f
170+
1:
171+
cmove c\base, c\scratch
172+
2:
173+
// Set the new value
174+
cspecialw SCR_ZTOP, c\base
175+
176+
#else
177+
129178
addi \scratch, \top, -32
130179
addi \top, \top, -16
131180
bgt \base, \scratch, 1f
@@ -143,6 +192,8 @@ switcher_scheduler_entry_csp:
143192
csc cnull, 0(c\base)
144193
csc cnull, 8(c\base)
145194
2:
195+
196+
#endif
146197
.endm
147198

148199
.section .text, "ax", @progbits
@@ -200,7 +251,7 @@ compartment_switcher_entry:
200251
sub s1, s0, s1
201252
csetboundsexact ct2, csp, s1
202253
csetaddr csp, ct2, s0
203-
#ifdef CONFIG_MSHWM
254+
#ifdef CHERIOT_HAS_MSHWM
204255
// Read and align the stack high water mark
205256
csrr gp, CSR_MSHWM
206257
and gp, gp, ~0xf
@@ -213,7 +264,7 @@ compartment_switcher_entry:
213264
#endif
214265
zero_stack t2, s0, gp
215266
after_zero:
216-
#ifdef CONFIG_MSHWM
267+
#ifdef CHERIOT_HAS_MSHWM
217268
// store new stack top as stack high water mark
218269
csrw CSR_MSHWM, sp
219270
#endif
@@ -347,11 +398,20 @@ exception_entry_asm:
347398
csc ct0, TrustedStack_offset_mepcc(csp)
348399
csrr t1, mstatus
349400
csw t1, TrustedStack_offset_mstatus(csp)
350-
#ifdef CONFIG_MSHWM
401+
#ifdef CHERIOT_HAS_MSHWM
351402
csrr t1, CSR_MSHWM
352403
csw t1, TrustedStack_offset_mshwm(csp)
353404
csrr t1, CSR_MSHWMB
354405
csw t1, TrustedStack_offset_mshwmb(csp)
406+
#endif
407+
#ifdef CHERIOT_HAS_ZTOP
408+
// Stop zeroing and capture the current zeroing value. Note: cspecialr is
409+
// encoded as cspecialrw and so we can't just use cnull as the source. We
410+
// probably could use the current ct1 value, since it's guaranteed to be
411+
// untagged at this point in the code.
412+
cmove ct1, cnull
413+
cspecialrw ct1, SCR_ZTOP, ct1
414+
csc ct1, TrustedStack_offset_ztop(csp)
355415
#endif
356416
csrr t1, mcause
357417
csw t1, TrustedStack_offset_mcause(csp)
@@ -432,11 +492,15 @@ exception_entry_asm:
432492
.Linstall_context:
433493
clw x1, TrustedStack_offset_mstatus(csp)
434494
csrw mstatus, x1
435-
#ifdef CONFIG_MSHWM
495+
#ifdef CHERIOT_HAS_MSHWM
436496
clw x1, TrustedStack_offset_mshwm(csp)
437497
csrw CSR_MSHWM, x1
438498
clw x1, TrustedStack_offset_mshwmb(csp)
439499
csrw CSR_MSHWMB, x1
500+
#endif
501+
#ifdef CHERIOT_HAS_ZTOP
502+
clc c1, TrustedStack_offset_ztop(csp)
503+
cspecialw SCR_ZTOP, c1
440504
#endif
441505
cspecialw mepcc, ct2
442506
csb zero, TrustedStack_offset_inForcedUnwind(csp)
@@ -657,7 +721,7 @@ exception_entry_asm:
657721

658722
// Load the trusted stack pointer to ct1
659723
cspecialr ct1, mtdc
660-
#ifdef CONFIG_MSHWM
724+
#ifdef CHERIOT_HAS_MSHWM
661725
// Update the spilled copy of the stack high water mark to ensure that we
662726
// will clear all of the stack used by the error handler and the spilled
663727
// context.
@@ -761,7 +825,7 @@ exception_entry_asm:
761825
clc cgp, SPILL_SLOT_cgp(csp)
762826
cincoffset csp, csp, SPILL_SLOT_SIZE
763827
#ifndef CONFIG_NO_SWITCHER_SAFETY
764-
#ifdef CONFIG_MSHWM
828+
#ifdef CHERIOT_HAS_MSHWM
765829
// read and align the stack high water mark
766830
// we will use this as base address for stack clearing
767831
// note that it cannot be greater than stack top as we
@@ -774,7 +838,7 @@ exception_entry_asm:
774838
cgetaddr t1, csp
775839
csetaddr ct2, csp, tp
776840
zero_stack t2, t1, tp
777-
#ifdef CONFIG_MSHWM
841+
#ifdef CHERIOT_HAS_MSHWM
778842
csrw CSR_MSHWM, sp
779843
#endif
780844
#endif // CONFIG_NO_SWITCHER_SAFETY

sdk/core/switcher/trusted-stack-assembly.h

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,39 @@ EXPORT_ASSEMBLY_OFFSET(TrustedStack, c12, 12 * 8)
1919
EXPORT_ASSEMBLY_OFFSET(TrustedStack, c13, 13 * 8)
2020
EXPORT_ASSEMBLY_OFFSET(TrustedStack, c14, 14 * 8)
2121
EXPORT_ASSEMBLY_OFFSET(TrustedStack, c15, 15 * 8)
22-
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mstatus, 16 * 8)
23-
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mcause, (16 * 8) + 4)
24-
#ifdef CONFIG_MSHWM
25-
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mshwm, 17 * 8)
26-
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mshwmb, (17 * 8) + 4)
22+
#ifdef CHERIOT_HAS_ZTOP
23+
EXPORT_ASSEMBLY_OFFSET(TrustedStack, ztop, 16 * 8)
24+
# define TSTACK_HAS_ZTOP 1
25+
#else
26+
# define TSTACK_HAS_ZTOP 0
27+
#endif
28+
EXPORT_ASSEMBLY_OFFSET(TrustedStack,
29+
mstatus,
30+
(16 + TSTACK_HAS_ZTOP) * 8)
31+
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mcause, TrustedStack_offset_mstatus + 4)
32+
#ifdef CHERIOT_HAS_MSHWM
33+
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mshwm, (17 + TSTACK_HAS_ZTOP) * 8)
34+
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mshwmb, TrustedStack_offset_mshwm + 4)
2735

2836
// Size of everything up to this point
29-
#define TSTACK_REGFRAME_SZ (18 * 8)
37+
# define TSTACK_REGFRAME_SZ ((18 + TSTACK_HAS_ZTOP) * 8)
3038
// frameoffset, inForcedUnwind and padding
31-
#define TSTACK_HEADER_SZ 16
39+
# define TSTACK_HEADER_SZ 16
3240
#else
3341
// Size of everything up to this point
34-
#define TSTACK_REGFRAME_SZ ((16 * 8) + (2* 4))
42+
# define TSTACK_REGFRAME_SZ ((16 * 8) + (2 * 4))
3543
// frameoffset, inForcedUnwind and padding
36-
#define TSTACK_HEADER_SZ 8
44+
# define TSTACK_HEADER_SZ 8
3745
#endif
3846
// The basic trusted stack is the size of the save area, 8 bytes of state for
3947
// unwinding information, and then a single trusted stack frame used for the
4048
// unwind state of the initial thread. (8 * 3) is the size of TrustedStackFrame
4149
// and will match the value below.
42-
EXPORT_ASSEMBLY_SIZE(TrustedStack, TSTACK_REGFRAME_SZ + TSTACK_HEADER_SZ + (8 * 3))
43-
EXPORT_ASSEMBLY_OFFSET(TrustedStack, frames, TSTACK_REGFRAME_SZ + TSTACK_HEADER_SZ)
50+
EXPORT_ASSEMBLY_SIZE(TrustedStack,
51+
TSTACK_REGFRAME_SZ + TSTACK_HEADER_SZ + (8 * 3))
52+
EXPORT_ASSEMBLY_OFFSET(TrustedStack,
53+
frames,
54+
TSTACK_REGFRAME_SZ + TSTACK_HEADER_SZ)
4455
EXPORT_ASSEMBLY_OFFSET(TrustedStack, frameoffset, TSTACK_REGFRAME_SZ)
4556
EXPORT_ASSEMBLY_OFFSET(TrustedStack, inForcedUnwind, TSTACK_REGFRAME_SZ + 2)
4657

sdk/core/switcher/tstack.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ struct TrustedStackFrame
2828
uint16_t errorHandlerCount;
2929
};
3030

31+
#if defined(CHERIOT_HAS_ZTOP) && !defined(CHERIOT_HAS_MSHWM)
32+
# error Platforms with ZTOP must have MSHWM
33+
#endif
34+
3135
template<size_t NFrames>
3236
struct TrustedStackGeneric
3337
{
@@ -47,9 +51,12 @@ struct TrustedStackGeneric
4751
void *c13;
4852
void *c14;
4953
void *c15;
54+
#ifdef CHERIOT_HAS_ZTOP
55+
void *ztop;
56+
#endif
5057
size_t mstatus;
5158
size_t mcause;
52-
#ifdef CONFIG_MSHWM
59+
#ifdef CHERIOT_HAS_MSHWM
5360
uint32_t mshwm;
5461
uint32_t mshwmb;
5562
#endif
@@ -61,7 +68,7 @@ struct TrustedStackGeneric
6168
uint8_t inForcedUnwind;
6269
// Padding up to multiple of 16-bytes.
6370
uint8_t padding[
64-
#ifdef CONFIG_MSHWM
71+
#ifdef CHERIOT_HAS_MSHWM
6572
13
6673
#else
6774
5

sdk/xmake.lua

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,22 @@ rule("firmware")
314314

315315
local loader = target:deps()['cheriot.loader'];
316316

317+
if board.fast_stack_zeroing and not board.stack_high_water_mark then
318+
error("Fast stack zeroing requires the stack high-water mark")
319+
end
320+
if board.stack_high_water_mark then
321+
add_defines("CHERIOT_HAS_MSHWM")
322+
if (board.fast_stack_zeroing) then
323+
add_defines("CHERIOT_HAS_ZTOP")
324+
-- If we have ztop, we need space to spill and reload it.
325+
loader:set('loader_trusted_stack_size', loader:get('loader_trusted_stack_size') + 8)
326+
end
327+
else
328+
-- If we don't have the stack high watermark, the trusted stack is smaller.
329+
loader:set('loader_trusted_stack_size', 168)
330+
end
317331
if board.stack_high_water_mark then
318-
add_defines("CONFIG_MSHWM")
332+
add_defines("CHERIOT_HAS_MSHWM")
319333
else
320334
-- If we don't have the stack high watermark, the trusted stack is smaller.
321335
loader:set('loader_trusted_stack_size', 168)

0 commit comments

Comments
 (0)