Merge pull request #10005 from liamwhite/kernel-atomics

kernel: fix unbounded stack usage in atomics
This commit is contained in:
bunnei 2023-04-01 01:54:36 -07:00 committed by GitHub
commit 0730dc6c44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 37 deletions

View File

@ -35,24 +35,30 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
// TODO(bunnei): We should call CanAccessAtomic(..) here. // TODO(bunnei): We should call CanAccessAtomic(..) here.
// Load the value from the address. s32 current_value{};
const s32 current_value =
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
// Compare it to the desired one. while (true) {
if (current_value < value) { // Load the value from the address.
// If less than, we want to try to decrement. current_value =
const s32 decrement_value = current_value - 1; 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. // 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. // We're done.
@ -70,23 +76,29 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32
// TODO(bunnei): We should call CanAccessAtomic(..) here. // TODO(bunnei): We should call CanAccessAtomic(..) here.
s32 current_value{};
// Load the value from the address. // Load the value from the address.
const s32 current_value = while (true) {
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); current_value =
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
// Compare it to the desired one. // Compare it to the desired one.
if (current_value == value) { if (current_value == value) {
// If equal, we want to try to write the new 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. // 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. // We're done.

View File

@ -33,21 +33,26 @@ bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u
auto& monitor = system.Monitor(); auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
// Load the value from the address. u32 expected{};
const auto expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
// Orr in the new mask. while (true) {
u32 value = expected | new_orr_mask; // 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. // Orr in the new mask.
if (!expected) { u32 value = expected | new_orr_mask;
value = if_zero;
} // 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. // If we failed to store, try again.
return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask);
} }
// We're done. // We're done.