summaryrefslogtreecommitdiff
path: root/lib/ultralib/src/os/setintmask.s
diff options
context:
space:
mode:
authorDerek Hensley <hensley.derek58@gmail.com>2025-02-21 16:03:51 -0800
committerGitHub <noreply@github.com>2025-02-21 17:03:51 -0700
commit8c6ae625aef6d07741cd8925f422f43ae24b198c (patch)
tree741fafdf5cf11006a23a9019451082c269fe4922 /lib/ultralib/src/os/setintmask.s
parentf013a028f42a1b11134bc5f22f28e9f48236b6f0 (diff)
Ultralib Update (#233)
* git subrepo pull (merge) lib/ultralib subrepo: subdir: "lib/ultralib" merged: "74f0eee" upstream: origin: "git@github.com:decompals/ultralib.git" branch: "main" commit: "2717d45" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo" commit: "cce3d93" * New ultralib fixes * Update some includes in tools * git subrepo commit (merge) lib/ultralib subrepo: subdir: "lib/ultralib" merged: "3a702eaf" upstream: origin: "git@github.com:decompals/ultralib.git" branch: "main" commit: "48f9f908" git-subrepo: version: "0.4.9" origin: "git@github.com:ingydotnet/git-subrepo.git" commit: "ea10886" * Update warnings file
Diffstat (limited to 'lib/ultralib/src/os/setintmask.s')
-rw-r--r--lib/ultralib/src/os/setintmask.s100
1 files changed, 69 insertions, 31 deletions
diff --git a/lib/ultralib/src/os/setintmask.s b/lib/ultralib/src/os/setintmask.s
index f19ed17..b9f93b0 100644
--- a/lib/ultralib/src/os/setintmask.s
+++ b/lib/ultralib/src/os/setintmask.s
@@ -10,47 +10,85 @@
.text
.set noreorder
-LEAF(osSetIntMask)
- mfc0 ta0, C0_SR
+/**
+ * OSIntMask osSetIntMask(OSIntMask);
+ *
+ * Sets the interrupt enable mask for the current thread. External interrupts
+ * originating either in the CPU or the RCP may be "masked out" so that they
+ * are not handled. This is sometimes important for critical code sections
+ * that must not be interrupted.
+ * Interrupts that are not enabled in the global interrupt mask __OSGlobalIntMask
+ * cannot be set here. The global interrupt mask is OS-internal and is not
+ * expected to change during runtime.
+ * The returned value is the previous interrupt enable mask so that it can be
+ * restored later.
+ *
+ * @bug Some usage of the global interrupt mask is broken both in here and in the
+ * exception handler routines.
+ * While a thread is running, the C0_SR interrupt enable bits contain the
+ * interrupt enable bits for the current thread masked by the global
+ * interrupt mask. There is an attempt to recover only the original interrupt
+ * enable bits belonging to the thread itself using the operation
+ * (SR | ~__OSGlobalIntMask).
+ * However, this does not work as intended and can cause interrupts to end
+ * up enabled when not intended to be. The same issue is present for the
+ * RCP interrupt enable bits in MI_INTR_MASK_REG.
+ * This does not cause issues in practice as __OSGlobalIntMask is almost always
+ * OS_IM_ALL, so the operation is usually simply (SR | 0).
+ */
+LEAF(osSetIntMask)
+ /* Extract interrupt enable bits from current SR */
+ mfc0 ta0, C0_SR
- andi v0, ta0, OS_IM_CPU
+ andi v0, ta0, OS_IM_CPU
- la t0, __OSGlobalIntMask
- lw t3, 0(t0)
-
- xor t0, t3,-1
- andi t0, t0,(SR_IMASK)
- or v0, v0,t0
+ /* Get value of __OSGlobalIntMask */
+ la t0, __OSGlobalIntMask
+ lw t3, 0(t0)
- lw t2, PHYS_TO_K1(MI_INTR_MASK_REG)
- beqz t2, 1f
- srl t1, t3,0x10
+ /* Bitwise-OR in the disabled CPU bits of __OSGlobalIntMask */
+ xor t0, t3, ~0
+ andi t0, t0, SR_IMASK
+ or v0, v0, t0
- xor t1, t1,-1
- andi t1, t1, MI_INTR_MASK
- or t2, t2,t1
+ /* Fetch MI_INTR_MASK_REG */
+ lw t2, PHYS_TO_K1(MI_INTR_MASK_REG)
+ /* If there are RCP interrupts masked */
+ beqz t2, 1f
+ srl t1, t3, 0x10
+
+ /* Bitwise-OR in the disabled RCP bits of __OSGlobalIntMask */
+ xor t1, t1, ~0
+ andi t1, t1, (RCP_IMASK >> RCP_IMASKSHIFT)
+ or t2, t2, t1
1:
- sll t2, t2,0x10
- or v0, v0,t2
+ /* Shift the RCP bits to not conflict with the CPU bits */
+ sll t2, t2, RCP_IMASKSHIFT
+ /* OR the CPU and RCP bits together */
+ or v0, v0, t2
- and t0, a0, MI_INTR_MASK<<0x10
- and t0, t0,t3
- srl t0, t0,0xf
- lhu t2, __osRcpImTable(t0)
- sw t2, PHYS_TO_K1(MI_INTR_MASK_REG)
-
- andi t0, a0, OS_IM_CPU
- andi t1, t3, SR_IMASK
- and t0, t0,t1
+ /* Extract RCP interrupt enable bits from requested mask and mask with __OSGlobalIntMask */
+ and t0, a0, RCP_IMASK
+ and t0, t0, t3
+ /* Convert to a value for MI_INTR_MASK_REG and set it */
+ srl t0, t0, (RCP_IMASKSHIFT - 1)
+ lhu t2, __osRcpImTable(t0)
+ sw t2, PHYS_TO_K1(MI_INTR_MASK_REG)
- and ta0, ta0, ~SR_IMASK
- or ta0, ta0,t0
+ /* Extract CPU interrupt enable bits from requested mask and mask with __OSGlobalIntMask */
+ andi t0, a0, OS_IM_CPU
+ andi t1, t3, SR_IMASK
+ and t0, t0, t1
- mtc0 ta0, C0_SR
- nop
+ and ta0, ta0, ~SR_IMASK
+ /* Bitwise OR in the remaining bits of SR and set new SR */
+ or ta0, ta0, t0
+
+ mtc0 ta0, C0_SR
nop
- jr ra
nop
+ jr ra
+ nop
END(osSetIntMask)
.rdata