2018-09-25 22:34:45 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "vm.h"
|
|
|
|
|
#include "Utilities/cond.h"
|
2019-07-27 00:34:10 +02:00
|
|
|
#include "util/atomic.hpp"
|
2018-09-29 00:12:00 +02:00
|
|
|
|
2018-09-25 22:34:45 +02:00
|
|
|
namespace vm
|
|
|
|
|
{
|
2020-09-02 23:58:29 +02:00
|
|
|
enum reservation_lock_bit : u64
|
|
|
|
|
{
|
|
|
|
|
stcx_lockb = 1 << 0, // Exclusive conditional reservation lock
|
|
|
|
|
dma_lockb = 1 << 1, // Inexclusive unconditional reservation lock
|
|
|
|
|
putlluc_lockb = 1 << 6, // Exclusive unconditional reservation lock
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-25 22:34:45 +02:00
|
|
|
// Get reservation status for further atomic update: last update timestamp
|
|
|
|
|
inline atomic_t<u64>& reservation_acquire(u32 addr, u32 size)
|
|
|
|
|
{
|
|
|
|
|
// Access reservation info: stamp and the lock bit
|
2020-04-11 10:16:28 +02:00
|
|
|
return *reinterpret_cast<atomic_t<u64>*>(g_reservations + (addr & 0xff80) / 2);
|
2018-09-25 22:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update reservation status
|
2020-08-15 06:56:34 +02:00
|
|
|
inline std::pair<bool, u64> try_reservation_update(u32 addr, u32 size, bool lsb = false)
|
2018-09-25 22:34:45 +02:00
|
|
|
{
|
|
|
|
|
// Update reservation info with new timestamp
|
2020-08-15 06:56:34 +02:00
|
|
|
auto& res = reservation_acquire(addr, size);
|
|
|
|
|
const u64 rtime = res;
|
|
|
|
|
|
|
|
|
|
return {!(rtime & 127) && res.compare_and_swap_test(rtime, rtime + 128), rtime};
|
2018-09-25 22:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-15 06:56:34 +02:00
|
|
|
void reservation_update(u32 addr, u32 size, bool lsb = false);
|
|
|
|
|
|
2018-09-25 22:34:45 +02:00
|
|
|
// Get reservation sync variable
|
2019-09-19 01:57:08 +02:00
|
|
|
inline atomic_t<u64>& reservation_notifier(u32 addr, u32 size)
|
2018-09-25 22:34:45 +02:00
|
|
|
{
|
2020-04-11 10:16:28 +02:00
|
|
|
return *reinterpret_cast<atomic_t<u64>*>(g_reservations + (addr & 0xff80) / 2);
|
2018-09-25 22:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-02 23:58:29 +02:00
|
|
|
u64 reservation_lock_internal(u32, atomic_t<u64>&, u64);
|
|
|
|
|
|
|
|
|
|
inline bool reservation_trylock(atomic_t<u64>& res, u64 rtime, u64 lock_bits = stcx_lockb)
|
|
|
|
|
{
|
|
|
|
|
if (res.compare_and_swap_test(rtime, rtime + lock_bits)) [[likely]]
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-09-25 22:34:45 +02:00
|
|
|
|
2020-09-02 23:58:29 +02:00
|
|
|
inline std::pair<atomic_t<u64>&, u64> reservation_lock(u32 addr, u32 size, u64 lock_bits = stcx_lockb)
|
2018-09-25 22:34:45 +02:00
|
|
|
{
|
2020-05-23 15:36:32 +02:00
|
|
|
auto res = &vm::reservation_acquire(addr, size);
|
2020-09-02 23:58:29 +02:00
|
|
|
auto rtime = res->load();
|
2018-09-25 22:34:45 +02:00
|
|
|
|
2020-09-02 23:58:29 +02:00
|
|
|
if (rtime & 127 || !reservation_trylock(*res, rtime, lock_bits)) [[unlikely]]
|
2018-09-25 22:34:45 +02:00
|
|
|
{
|
2020-05-23 15:36:32 +02:00
|
|
|
static atomic_t<u64> no_lock{};
|
|
|
|
|
|
2020-09-02 23:58:29 +02:00
|
|
|
rtime = reservation_lock_internal(addr, *res, lock_bits);
|
|
|
|
|
|
|
|
|
|
if (rtime == umax)
|
2020-05-23 15:36:32 +02:00
|
|
|
{
|
|
|
|
|
res = &no_lock;
|
|
|
|
|
}
|
2018-09-25 22:34:45 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-02 23:58:29 +02:00
|
|
|
return {*res, rtime};
|
2020-05-08 19:41:15 +02:00
|
|
|
}
|
2018-09-25 22:34:45 +02:00
|
|
|
} // namespace vm
|