Exclusive Monitor: Rework exclusive monitor interface.

This commit is contained in:
Fernando Sahmkow 2020-03-10 18:07:44 -04:00 committed by MerryMage
parent b5d8b24a3c
commit 97b9d3e058
15 changed files with 278 additions and 151 deletions

View file

@ -83,6 +83,13 @@ struct UserCallbacks {
virtual void MemoryWrite64(VAddr vaddr, std::uint64_t value) = 0;
virtual void MemoryWrite128(VAddr vaddr, Vector value) = 0;
// Writes through these callbacks may not be aligned.
virtual bool MemoryWriteExclusive8(VAddr vaddr, std::uint8_t value, std::uint8_t expected) = 0;
virtual bool MemoryWriteExclusive16(VAddr vaddr, std::uint16_t value, std::uint16_t expected) = 0;
virtual bool MemoryWriteExclusive32(VAddr vaddr, std::uint32_t value, std::uint32_t expected) = 0;
virtual bool MemoryWriteExclusive64(VAddr vaddr, std::uint64_t value, std::uint64_t expected) = 0;
virtual bool MemoryWriteExclusive128(VAddr vaddr, Vector value, Vector expected) = 0;
// If this callback returns true, the JIT will assume MemoryRead* callbacks will always
// return the same value at any point in time for this vaddr. The JIT may use this information
// in optimizations.

View file

@ -6,14 +6,17 @@
#pragma once
#include <atomic>
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <vector>
namespace Dynarmic {
namespace A64 {
using VAddr = std::uint64_t;
using Vector = std::array<std::uint64_t, 2>;
class ExclusiveMonitor {
public:
@ -26,31 +29,45 @@ public:
/// Marks a region containing [address, address+size) to be exclusive to
/// processor processor_id.
void Mark(size_t processor_id, VAddr address, size_t size);
template <typename T, typename Function>
T ReadAndMark(size_t processor_id, VAddr address, Function op) {
static_assert(std::is_trivially_copyable_v<T>);
const VAddr masked_address = address & RESERVATION_GRANULE_MASK;
Lock();
exclusive_addresses[processor_id] = masked_address;
const T value = op();
std::memcpy(exclusive_values[processor_id].data(), &value, sizeof(T));
Unlock();
return value;
}
/// Checks to see if processor processor_id has exclusive access to the
/// specified region. If it does, executes the operation then clears
/// the exclusive state for processors if their exclusive region(s)
/// contain [address, address+size).
template <typename Function>
bool DoExclusiveOperation(size_t processor_id, VAddr address, size_t size, Function op) {
if (!CheckAndClear(processor_id, address, size)) {
template <typename T, typename Function>
bool DoExclusiveOperation(size_t processor_id, VAddr address, Function op) {
static_assert(std::is_trivially_copyable_v<T>);
if (!CheckAndClear(processor_id, address)) {
return false;
}
op();
T saved_value;
std::memcpy(&saved_value, exclusive_values[processor_id].data(), sizeof(T));
const bool result = op(saved_value);
Unlock();
return true;
return result;
}
/// Unmark everything.
void Clear();
/// Unmark processor id
void Clear(size_t processor_id);
void ClearProcessor(size_t processor_id);
private:
bool CheckAndClear(size_t processor_id, VAddr address, size_t size);
bool CheckAndClear(size_t processor_id, VAddr address);
void Lock();
void Unlock();
@ -59,6 +76,7 @@ private:
static constexpr VAddr INVALID_EXCLUSIVE_ADDRESS = 0xDEAD'DEAD'DEAD'DEADull;
std::atomic_flag is_locked;
std::vector<VAddr> exclusive_addresses;
std::vector<Vector> exclusive_values;
};
} // namespace A64