Merge pull request #10005 from liamwhite/kernel-atomics
kernel: fix unbounded stack usage in atomics
This commit is contained in:
		| @@ -35,24 +35,30 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address | ||||
|  | ||||
|     // TODO(bunnei): We should call CanAccessAtomic(..) here. | ||||
|  | ||||
|     // Load the value from the address. | ||||
|     const s32 current_value = | ||||
|         static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); | ||||
|     s32 current_value{}; | ||||
|  | ||||
|     // Compare it to the desired one. | ||||
|     if (current_value < value) { | ||||
|         // If less than, we want to try to decrement. | ||||
|         const s32 decrement_value = current_value - 1; | ||||
|     while (true) { | ||||
|         // Load the value from the address. | ||||
|         current_value = | ||||
|             static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); | ||||
|  | ||||
|         // Compare it to the desired one. | ||||
|         if (current_value < value) { | ||||
|             // If less than, we want to try to decrement. | ||||
|             const s32 decrement_value = current_value - 1; | ||||
|  | ||||
|             // Decrement and try to store. | ||||
|             if (monitor.ExclusiveWrite32(current_core, GetInteger(address), | ||||
|                                          static_cast<u32>(decrement_value))) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|         // Decrement and try to store. | ||||
|         if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), | ||||
|                                       static_cast<u32>(decrement_value))) { | ||||
|             // If we failed to store, try again. | ||||
|             DecrementIfLessThan(system, out, address, value); | ||||
|         } else { | ||||
|             // Otherwise, clear our exclusive hold and finish | ||||
|             monitor.ClearExclusive(current_core); | ||||
|             break; | ||||
|         } | ||||
|     } else { | ||||
|         // Otherwise, clear our exclusive hold and finish | ||||
|         monitor.ClearExclusive(current_core); | ||||
|     } | ||||
|  | ||||
|     // We're done. | ||||
| @@ -70,23 +76,29 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 | ||||
|  | ||||
|     // TODO(bunnei): We should call CanAccessAtomic(..) here. | ||||
|  | ||||
|     s32 current_value{}; | ||||
|  | ||||
|     // Load the value from the address. | ||||
|     const s32 current_value = | ||||
|         static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); | ||||
|     while (true) { | ||||
|         current_value = | ||||
|             static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); | ||||
|  | ||||
|     // Compare it to the desired one. | ||||
|     if (current_value == value) { | ||||
|         // If equal, we want to try to write the new value. | ||||
|         // Compare it to the desired one. | ||||
|         if (current_value == value) { | ||||
|             // If equal, we want to try to write the new value. | ||||
|  | ||||
|             // Try to store. | ||||
|             if (monitor.ExclusiveWrite32(current_core, GetInteger(address), | ||||
|                                          static_cast<u32>(new_value))) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|         // Try to store. | ||||
|         if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), | ||||
|                                       static_cast<u32>(new_value))) { | ||||
|             // If we failed to store, try again. | ||||
|             UpdateIfEqual(system, out, address, value, new_value); | ||||
|         } else { | ||||
|             // Otherwise, clear our exclusive hold and finish. | ||||
|             monitor.ClearExclusive(current_core); | ||||
|             break; | ||||
|         } | ||||
|     } else { | ||||
|         // Otherwise, clear our exclusive hold and finish. | ||||
|         monitor.ClearExclusive(current_core); | ||||
|     } | ||||
|  | ||||
|     // We're done. | ||||
|   | ||||
| @@ -33,21 +33,26 @@ bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u | ||||
|     auto& monitor = system.Monitor(); | ||||
|     const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); | ||||
|  | ||||
|     // Load the value from the address. | ||||
|     const auto expected = monitor.ExclusiveRead32(current_core, GetInteger(address)); | ||||
|     u32 expected{}; | ||||
|  | ||||
|     // Orr in the new mask. | ||||
|     u32 value = expected | new_orr_mask; | ||||
|     while (true) { | ||||
|         // Load the value from the address. | ||||
|         expected = monitor.ExclusiveRead32(current_core, GetInteger(address)); | ||||
|  | ||||
|     // If the value is zero, use the if_zero value, otherwise use the newly orr'd value. | ||||
|     if (!expected) { | ||||
|         value = if_zero; | ||||
|     } | ||||
|         // Orr in the new mask. | ||||
|         u32 value = expected | new_orr_mask; | ||||
|  | ||||
|         // If the value is zero, use the if_zero value, otherwise use the newly orr'd value. | ||||
|         if (!expected) { | ||||
|             value = if_zero; | ||||
|         } | ||||
|  | ||||
|         // Try to store. | ||||
|         if (monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|     // Try to store. | ||||
|     if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) { | ||||
|         // If we failed to store, try again. | ||||
|         return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask); | ||||
|     } | ||||
|  | ||||
|     // We're done. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user