Page MenuHomeFreeBSD

Handle the possibility of preemption after an "ic" or "tlbi" instruction
ClosedPublic

Authored by alc on Sun, Dec 1, 5:42 PM.

Details

Summary

On a context switch, handle the possibility that the old thread was preempted after an "ic" or "tlbi" instruction but before it performed a "dsb" instruction. If the old thread migrates to a new processor, its completion of a "dsb" instruction on that new processor does not guarantee that the "ic" or "tlbi" instructions performed on the old processor have completed.

This issue is not restricted to the kernel. Since locore.S sets the UCI bit in SCTLR, user-space programs can perform "ic ivau" instructions (as well as some forms of the "dc" instruction).

Diff Detail

Repository
rS FreeBSD src repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

alc created this revision.Sun, Dec 1, 5:42 PM
kib accepted this revision.Sun, Dec 1, 8:06 PM
This revision is now accepted and ready to land.Sun, Dec 1, 8:06 PM
markj accepted this revision.Mon, Dec 2, 4:52 PM
mmel accepted this revision.Mon, Dec 2, 6:10 PM
andrew accepted this revision.Tue, Dec 3, 11:58 AM

Which context synchronization event are you using after the dsb? ARMv8.5 adds the ARMv8.5-CSEH (Context synchronization and exception handling) extension that allows us to remove exceptions as a context synchronization event. It might pay to document where we know we are relying on exception entry/exit for these to help later if we decide to use the extension.

alc added a comment.Wed, Dec 4, 12:08 AM

Which context synchronization event are you using after the dsb? ARMv8.5 adds the ARMv8.5-CSEH (Context synchronization and exception handling) extension that allows us to remove exceptions as a context synchronization event. It might pay to document where we know we are relying on exception entry/exit for these to help later if we decide to use the extension.

None really. Suppose that I am a thread that is preempted in the middle of a function F, which is one of the various "ic" or "tlbi" issuing functions. Further, suppose that I am then migrated to a new processor. If switching to a new thread on my old processor requires an address space change, then we are guaranteed that an "isb" instruction will be performed. In contrast, where the new thread and I share the same address space, we are not certain to perform an "isb" instruction as part of the context switch. However, I'm going to argue that this doesn't matter. Until I have completed F, and this new thread has synchronized with me in some way, it really isn't entitled to make any assumptions about the state in which I left the old processor. Simply having a context synchronization event as part of the context switch doesn't really achieve anything.

So, in regards to ARMv8.5-CSEH, I don't see how it comes into play for context switches. On the other hand, what are today redundant "isb" instructions in the TLB invalidation functions that are used after user-space page table changes would become necessary with ARMv8.5-CSEH enabled.

kib added a comment.Wed, Dec 4, 1:51 PM
In D22622#495703, @alc wrote:

Which context synchronization event are you using after the dsb? ARMv8.5 adds the ARMv8.5-CSEH (Context synchronization and exception handling) extension that allows us to remove exceptions as a context synchronization event. It might pay to document where we know we are relying on exception entry/exit for these to help later if we decide to use the extension.

None really. Suppose that I am a thread that is preempted in the middle of a function F, which is one of the various "ic" or "tlbi" issuing functions. Further, suppose that I am then migrated to a new processor. If switching to a new thread on my old processor requires an address space change, then we are guaranteed that an "isb" instruction will be performed. In contrast, where the new thread and I share the same address space, we are not certain to perform an "isb" instruction as part of the context switch. However, I'm going to argue that this doesn't matter. Until I have completed F, and this new thread has synchronized with me in some way, it really isn't entitled to make any assumptions about the state in which I left the old processor. Simply having a context synchronization event as part of the context switch doesn't really achieve anything.

But isn't the problem that we modified page table entry on one processor, while issued isb on another ?

So, in regards to ARMv8.5-CSEH, I don't see how it comes into play for context switches. On the other hand, what are today redundant "isb" instructions in the TLB invalidation functions that are used after user-space page table changes would become necessary with ARMv8.5-CSEH enabled.

alc added a comment.Wed, Dec 4, 5:22 PM
In D22622#495862, @kib wrote:
In D22622#495703, @alc wrote:

Which context synchronization event are you using after the dsb? ARMv8.5 adds the ARMv8.5-CSEH (Context synchronization and exception handling) extension that allows us to remove exceptions as a context synchronization event. It might pay to document where we know we are relying on exception entry/exit for these to help later if we decide to use the extension.

None really. Suppose that I am a thread that is preempted in the middle of a function F, which is one of the various "ic" or "tlbi" issuing functions. Further, suppose that I am then migrated to a new processor. If switching to a new thread on my old processor requires an address space change, then we are guaranteed that an "isb" instruction will be performed. In contrast, where the new thread and I share the same address space, we are not certain to perform an "isb" instruction as part of the context switch. However, I'm going to argue that this doesn't matter. Until I have completed F, and this new thread has synchronized with me in some way, it really isn't entitled to make any assumptions about the state in which I left the old processor. Simply having a context synchronization event as part of the context switch doesn't really achieve anything.

But isn't the problem that we modified page table entry on one processor, while issued isb on another ?

Page table updates are performed using ordinary stores, and as such they are ordered by the memory barriers within our locking primitives, in this case, the memory barriers provided by the thread lock. In general, we are performing a "dsb" instruction after any page table update. (That "dsb" instruction may be provided by the TLB invalidation function.) If we performed that "dsb" instruction on the old processor, before the thread migrated, then we know that the page table update is globally visible before the thread resumes on the new processor. If, on the other hand, the "dsb" instruction is performed after the migration, the thread lock's memory barriers make the page table updates "observable" to the new processor and this "dsb" instruction. So, the "dsb" instruction isn't going to complete until it can guarantee that subsequent instructions executed on the new processor are using the updated page table entries. The exception being that the processor is allowed to fetch and decode instructions subsequent to the "dsb" instruction, but that's all it can do. However, the subsequent "isb" instruction will flush those fetched and decoded instructions, and cause them to be refetched using the updated mapping.

That ordinary memory barriers, i.e., acquires, releases, "dmb"'s, don't order the effects of "ic" and "tlbi" instructions across processors seems to be a peculiarity of those instructions.

This revision was automatically updated to reflect the committed changes.