mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
kernel: fix atomic operations
Atomic operations were previously broken. RISC-V breaks atomic operations into multiple instructions, and there is some state kept between those instructions. This state is not visible, and is internal to the processor. We were ignoring this state, which resulted in inconsistencies throughout the system. The following sequence was possible: 1. A thread loads a value, and obtains the `reservation set` 2. A context switch happens on the following instruction 3. A different thread loads the value, modifies it, and continues 4. A third thread (or a different process) loads a value and obtains the `reservation set` 5. The original thread runs, sees the `reservation set` is held, and updates the value, clobbering what the second thread did in #3 A workaround for this is to perform a dummy `sc` as part of the context switch. This invalidates any atomic operations that may be pending. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
935b1a17a4
commit
dc097e32d8
7 changed files with 20 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -154,6 +154,11 @@ _xous_resume_context:
|
|||
move sp, a0
|
||||
|
||||
LOAD x1, 0*REGBYTES(sp)
|
||||
// Clear any reservations, invalidating any atomic operations
|
||||
#ifndef SKIP_MULTICORE
|
||||
sc.w zero, x1, 0*REGBYTES(sp)
|
||||
#endif
|
||||
|
||||
// Skip SP for now
|
||||
LOAD x3, 2*REGBYTES(sp)
|
||||
LOAD x4, 3*REGBYTES(sp)
|
||||
|
|
@ -206,6 +211,21 @@ _xous_syscall_return_result:
|
|||
csrw sepc, t0
|
||||
|
||||
LOAD x1, 0*REGBYTES(sp)
|
||||
// An atomic operation is broken up into multiple instructions.
|
||||
// A program first issues a `lr` instruction, which basically
|
||||
// raises a flag saying that an atomic operation is now live. It
|
||||
// then issues an `sc` instruction, and if the flag is still held
|
||||
// it succeeds and clears the flag.
|
||||
//
|
||||
// This flag is a bit of state within the processor, and the
|
||||
// RISC-V spec doesn't say how to access it. However, it is only
|
||||
// one bit, and we can clear the bit by performing a dummy `sc`
|
||||
// here. This will cause a failure in any atomic operation in the
|
||||
// program we're switching to.
|
||||
#ifndef SKIP_MULTICORE
|
||||
sc.w zero, x1, 0*REGBYTES(sp)
|
||||
#endif
|
||||
|
||||
// Skip SP for now
|
||||
LOAD x3, 2*REGBYTES(sp)
|
||||
LOAD x4, 3*REGBYTES(sp)
|
||||
|
|
|
|||
Loading…
Reference in a new issue