Skip to content

Commit

Permalink
WIP: switcher: mscratchc
Browse files Browse the repository at this point in the history
  • Loading branch information
nwf committed Nov 26, 2024
1 parent c5356fc commit 4c1fb36
Showing 1 changed file with 104 additions and 49 deletions.
153 changes: 104 additions & 49 deletions sdk/core/switcher/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
* - "LIVE IN:", a list of live (in) registers at this point of the code and/or
* - "*": the entire general purpose register file (no CSRs or SCRs implied)
* - "mcause"
* - "mscratchc"
* - "mtdc"
* - "mtval"
* - "mepcc"
Expand All @@ -87,7 +88,25 @@
*
* For all annotations, optional commentary given in parentheses and may
* continue onto adjacent lines.
*/
/*
* The switcher makes use of its Access Systems Registers (SR) permission to
* access two privileged registers: MTDC and MScratchC.
*
* - MTDC always holds an unsealed capability to the current, or last, on-core
* thread's TrustedStack. It is nullptr (0) across scheduling, as the
* scheduler event handler is not a real thread and must not be preempted (and
* may not make cross-compartment calls). This is updated by the scheduling
* path and read by the cross-call and exception paths.
*
* - MScratchC is zero while not handling an exception, so that it may be safely
* used to bootstrap register spill on the exception path. On exception
* paths, it must be any nonzero value, so that we may detect exception
* reentrancy (see exception_entry_asm and exception_reentered).
*
* The use of two registers in particular avoids the need to double-purpose MTDC
* during bootstrapping register spill and lets us argue that MTDC is never any
* type other than an optional pointer to a TrustedStack.
*/
/*
* Multiple points in the switcher are exposed to callers via sentries (either
Expand Down Expand Up @@ -241,6 +260,8 @@ __Z26compartment_switcher_entryz:
* Atlas:
* mtdc: pointer to this thread's TrustedStack
* (may be 0 from buggy/malicious scheduler thread)
* mscratchc: zero
* (may be nonzero from buggy/malicious scheduler thread)
* ra: caller return address
* (at the moment, this is ensured because we enter via an
* IRQ-disabling forward sentry, which requires ra as the destination
Expand Down Expand Up @@ -892,7 +913,8 @@ exception_entry_asm:
* LIVE IN: mcause, mtval, mtdc, *
*
* Atlas:
* mtdc: either pointer to TrustedStack or zero
* mtdc: pointer to TrustedStack
* mscratchc: zero iff not reentered
* mcause, mtval: architecture-specified exception information. These are
* assumed correct -- for example, that it is impossible for
* untrusted code to enter the exception path with
Expand All @@ -906,11 +928,11 @@ exception_entry_asm:
* here with interrupts off and precious few registers available to us, so
* swap it with the csp (we'll put it back, later).
*/
cspecialrw csp, mtdc, csp
cspecialrw csp, mscratchc, csp

/*
* If we read out zero, we've reentered the exception and are about to trap
* (in spillRegisters, which uses sp as its authority).
* If we read out nonzero, we've reentered the exception and are about to
* trap (in spillRegisters, which uses sp as its authority).
*
* Failure to guard here would mean that the trap in spillRegisters below
* would re-enter the trap-handler with an unknown value (the first trap's
Expand All @@ -919,14 +941,30 @@ exception_entry_asm:
* spilling registers to a potentially attacker-controlled pointer, at the
* very least, and that's something to avoid.
*/
cseqx sp, csp, cnull
beqz sp, .Lexception_reentered

cspecialr csp, mtdc
// Atlas update: sp: pointer to on-core TrustedStack

/*
* The guest sp/csp (x2/c2) is now in mtdc. Will be spilled later, but we
* spill all the other 14 registers now.
*/
trustedSpillRegisters cra, cgp, ctp, ct0, ct1, ct2, cs0, cs1, ca0, ca1, ca2, ca3, ca4, ca5

/*
* Copy the nonzero mtdc (currently in sp) into mscratchc and read back
* the stashed value of csp into the now-dead ct1.
*/
cspecialrw ct1, mscratchc, csp
/*
* Atlas update:
* mscratchc: TrustedStack pointer
* t1: interrupted thread's csp value
*/
csc ct1, TrustedStack_offset_csp(csp)

/*
* The control flow of an exiting thread rejoins us (that is, running
* threads which have taken an exception, be that a trap or an interrupt)
Expand All @@ -941,28 +979,11 @@ exception_entry_asm:
* LIVE IN: mcause, mtval, mtdc, sp
*
* Atlas:
* mtdc: the interrupted context's sp (or zero, if coming from
* .Lcommon_thread_exit)
* mtdc: pointer to TrustedStack
* mscratchc: nonzero (a copy of mtdc if from above, XXX)
* sp: TrustedStack pointer (and in particular a spill frame we can use)
*/

/*
* mtdc got swapped with the thread's csp, store it and clobber mtdc with
* zero (using t1 as a scratch register, because using source register index
* 0 with cspecialrw means "don't write" rather than "write zero"). The
* trusted stack pointer is solely in csp, now; if we take another trap
* before a new one is installed, or if the scheduler enables interrupts and
* we take one, we'll pull this zero out of mtdc, above.
*/
zeroOne t1
cspecialrw ct1, mtdc, ct1
csc ct1, TrustedStack_offset_csp(csp)
/*
* Atlas update:
* mtdc: zero
* sp: (still) TrustedStack pointer
*/

// Store the rest of the special registers
cspecialr ct0, mepcc
csc ct0, TrustedStack_offset_mepcc(csp)
Expand Down Expand Up @@ -1033,8 +1054,20 @@ exception_entry_asm:
* tp, t0, t1, t2, s0, s1, a4, a5: dead
*/

// Zero everything apart from things explicitly passed to scheduler.
zeroAllRegistersExcept ra, sp, gp, a0, a1, a2, a3
// The scheduler is not a real thread; null out mtdc
zeroOne a4
cspecialw mtdc, ca4
/*
* Atlas update:
* mtdc: zero
* a4: zero
*/

/*
* Zero everything apart from things explicitly passed to scheduler or just
* zeroed.
*/
zeroAllRegistersExcept ra, sp, gp, a0, a1, a2, a3, a4

// Call the scheduler. This returns the new thread in ca0.
cjalr cra
Expand All @@ -1043,11 +1076,12 @@ exception_entry_asm:
/*
* IFROM: above
* IRQ ASSUME: deferred (reachable only by IRQ-deferring reverse sentry)
* IRQ REQUIRE: deferred (mtdc is zero)
* LIVE IN: a0
* IRQ REQUIRE: deferred (mscratchc is nonzero)
* LIVE IN: mtdc, mscratchc, a0
*
* Atlas:
* mtdc: (still) zero
* mscratchc: nonzero
* a0: sealed trusted stack pointer to bring onto core
*/
/*
Expand Down Expand Up @@ -1150,10 +1184,17 @@ exception_entry_asm:
#endif
cspecialw mepcc, ct2

zeroOne t2
cspecialw mscratchc, ct2
// Atlas update: mscratchc: zero, since we are exiting the exception path

/*
* reloadRegisters restores registers in the order given, and we ensure that
* sp/csp (x2/c2) will be loaded last and will overwrite the trusted stack
* pointer with the thread's stack pointer.
*
* Even though we have zeroed mscratchc and so risk not detecting a fault
* here, these accesses are to the TrustedStack and so will not fault.
*/
trustedReloadRegisters cra, cgp, ctp, ct0, ct1, ct2, cs0, cs1, ca0, ca1, ca2, ca3, ca4, ca5, csp
mret
Expand All @@ -1172,10 +1213,11 @@ exception_entry_asm:
* FROM: .Lhandle_error_try_stackless
* FROM: .Lswitch_csp_check
* IRQ REQUIRE: any
* LIVE IN: mtdc
* LIVE IN: mtdc, mscratchc
*
* Atlas:
* mtdc: pointer to TrustedStack
* mscratchc: zero
*/
li a0, -ECOMPARTMENTFAIL
li a1, 0
Expand All @@ -1197,20 +1239,12 @@ exception_entry_asm:
* FROM: .Lexception_might_handle
* FROM: .Lhandle_injected_error
* IRQ REQUIRE: deferred (TrustedStack spill frame is precious)
* LIVE IN: sp
* LIVE IN: mtdc, sp
*
* Atlas:
* sp: pointer to TrustedStack
*/
/*
* We're now out of the exception path, so make sure that mtdc contains
* the trusted stack pointer.
*/
cspecialw mtdc, csp
/*
* Atlas update:
* mtdc: pointer to TrustedStack
* sp: (still) pointer to TrustedStack
* sp: a copy of mtdc
* mscratchc: nonzero
*/

//.Lhandle_error_switcher_pcc:
Expand Down Expand Up @@ -1253,6 +1287,16 @@ exception_entry_asm:
li a0, 0
// Atlas update: a0: stackful (0) or stackless (1) indicator, currently 0

/*
* At this point, all paths out are going to take us off the exception path:
* either we're off to .Lcommon_force_unwind, or we're off to the fault
* handler. Zero mscratchc; if we trap in here, we'll try force unwinding
* via the exception path rather than wedging the machine.
*
* Reuse the zero we just put in a register.
*/
cspecialw mscratchc, ca0

// Allocate space for the register save frame on the stack.
cincoffset ct0, ct0, -(16*8)

Expand Down Expand Up @@ -1709,8 +1753,16 @@ exception_entry_asm:
/*
* FROM: switcher_after_compartment_call
* IRQ REQUIRE: any
* LIVE IN: mtdc, mscratchc, tp
*
* Atlas:
* mtdc: pointer to TrustedStack
* mscratchc: zero (because the switcher is not on the exception path)
* tp: a nonzero value (a copy of mtdc)
*/
csrci mstatus, 0x8
cspecialw mscratchc, ctp
// Atlas update: mscratchc: nonzero (a copy of mtdc)
//.Lcommon_deferred_irqs_and_thread_exit:
// IRQ ASSUME: deferred

Expand All @@ -1722,10 +1774,11 @@ exception_entry_asm:
* FROM: above
* FROM: .Lhandle_error_not_switcher
* IRQ REQUIRE: deferred (about to zero out MTDC and join exception path)
* LIVE IN: mtdc
* LIVE IN: mtdc, mscratchc
*
* Atlas:
* mtdc: pointer to TrustedStack
* mscratchc: nonzero of some form
*/
csrw mcause, MCAUSE_THREAD_EXIT
/*
Expand All @@ -1737,14 +1790,7 @@ exception_entry_asm:
* scheduler's event handler.
*/
csrw mtval, MCAUSE_THREAD_EXIT
/*
* The thread exit code expects the TrustedStack pointer to be in csp and
* the thread's stack pointer to be in mtdc. After thread exit, we don't
* need the stack pointer so just put zero there.
*/
zeroOne sp
cspecialrw csp, mtdc, csp
// LIVE OUT: mtdc, sp
// LIVE OUT: sp
j .Lexception_exiting_threads_rejoin

/*
Expand All @@ -1763,9 +1809,18 @@ exception_entry_asm:
*/
auipcc ctp, %cheriot_compartment_hi(.Lswitch_entry_first_spill)
cincoffset ctp, ctp, %cheriot_compartment_lo_i(.Lhandle_error_in_switcher)
// Atlas update: tp: pointer to .Lswitch_entry_first_spill

/*
* We're exiting the exception path one way or another (force unwind or by
* installing a return context), so zero mscratchc. This doubles as zeroing
* the 2nd return register.
*/
zeroOne a1
cspecialw mscratchc, ca1

bne t1, tp, .Lcommon_force_unwind
li a0, -ENOTENOUGHSTACK
li a1, 0

/*
* Cause the interrupted thread to resume as if a return had just executed.
Expand Down

0 comments on commit 4c1fb36

Please sign in to comment.