258 lines
8.7 KiB
C++
258 lines
8.7 KiB
C++
#pragma once
|
|
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*
|
|
* @modified Tom Clay, 2026 - Adapted for ReXGlue runtime
|
|
*/
|
|
|
|
#include <type_traits>
|
|
|
|
#include <rex/system/xmemory.h>
|
|
#include <rex/system/xtypes.h>
|
|
|
|
namespace rex::system::util {
|
|
|
|
// List is designed for storing pointers to objects in the guest heap.
|
|
// All values in the list should be assumed to be in big endian.
|
|
|
|
// Pass LIST_ENTRY pointers.
|
|
// struct MYOBJ {
|
|
// uint32_t stuff;
|
|
// LIST_ENTRY list_entry; <-- pass this
|
|
// ...
|
|
// }
|
|
|
|
class NativeList {
|
|
public:
|
|
NativeList();
|
|
explicit NativeList(memory::Memory* memory);
|
|
|
|
void Insert(uint32_t list_entry_ptr);
|
|
bool IsQueued(uint32_t list_entry_ptr);
|
|
void Remove(uint32_t list_entry_ptr);
|
|
uint32_t Shift();
|
|
bool HasPending();
|
|
|
|
uint32_t head() const { return head_; }
|
|
void set_head(uint32_t head) { head_ = head; }
|
|
|
|
void set_memory(memory::Memory* mem) { memory_ = mem; }
|
|
|
|
private:
|
|
const uint32_t kInvalidPointer = 0xE0FE0FFF;
|
|
|
|
private:
|
|
memory::Memory* memory_ = nullptr;
|
|
uint32_t head_;
|
|
};
|
|
|
|
// Guest-memory linked list utilities.
|
|
// VirtualTranslator is any type with TranslateVirtual<T*>(uint32_t)
|
|
// and HostToGuestVirtual(void*) methods (e.g. memory::Memory*).
|
|
// Overloads also accept a raw uint32_t guest pointer in place of the
|
|
// translator when the caller already has the guest address.
|
|
|
|
template <typename VirtualTranslator>
|
|
X_LIST_ENTRY* XeHostList(uint32_t ptr, VirtualTranslator context) {
|
|
return context->template TranslateVirtual<X_LIST_ENTRY*>(ptr);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
uint32_t XeGuestList(X_LIST_ENTRY* ptr, VirtualTranslator context) {
|
|
return context->HostToGuestVirtual(ptr);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInitializeListHead(X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
if constexpr (std::is_unsigned_v<VirtualTranslator>) {
|
|
entry->blink_ptr = context;
|
|
entry->flink_ptr = context;
|
|
} else {
|
|
uint32_t orig_ptr = XeGuestList(entry, context);
|
|
entry->blink_ptr = orig_ptr;
|
|
entry->flink_ptr = orig_ptr;
|
|
}
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
bool XeIsListEmpty(X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
return XeHostList(entry->flink_ptr, context) == entry;
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeRemoveEntryList(X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
uint32_t front = entry->flink_ptr;
|
|
uint32_t back = entry->blink_ptr;
|
|
XeHostList(back, context)->flink_ptr = front;
|
|
XeHostList(front, context)->blink_ptr = back;
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeRemoveEntryList(uint32_t entry, VirtualTranslator context) {
|
|
XeRemoveEntryList(XeHostList(entry, context), context);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
uint32_t XeRemoveHeadList(X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
uint32_t result = entry->flink_ptr;
|
|
XeRemoveEntryList(result, context);
|
|
return result;
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
uint32_t XeRemoveTailList(X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
uint32_t result = entry->blink_ptr;
|
|
XeRemoveEntryList(result, context);
|
|
return result;
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertTailList(X_LIST_ENTRY* list_head, uint32_t list_head_guest, X_LIST_ENTRY* host_entry,
|
|
uint32_t entry, VirtualTranslator context) {
|
|
uint32_t old_tail = list_head->blink_ptr;
|
|
host_entry->flink_ptr = list_head_guest;
|
|
host_entry->blink_ptr = old_tail;
|
|
XeHostList(old_tail, context)->flink_ptr = entry;
|
|
list_head->blink_ptr = entry;
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertTailList(uint32_t list_head, uint32_t entry, VirtualTranslator context) {
|
|
XeInsertTailList(XeHostList(list_head, context), list_head, XeHostList(entry, context), entry,
|
|
context);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertTailList(X_LIST_ENTRY* list_head, uint32_t entry, VirtualTranslator context) {
|
|
XeInsertTailList(list_head, XeGuestList(list_head, context), XeHostList(entry, context), entry,
|
|
context);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertTailList(X_LIST_ENTRY* list_head, X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
XeInsertTailList(list_head, XeGuestList(list_head, context), entry, XeGuestList(entry, context),
|
|
context);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertHeadList(X_LIST_ENTRY* list_head, uint32_t list_head_guest, X_LIST_ENTRY* host_entry,
|
|
uint32_t entry, VirtualTranslator context) {
|
|
uint32_t old_list_head_flink = list_head->flink_ptr;
|
|
host_entry->flink_ptr = old_list_head_flink;
|
|
host_entry->blink_ptr = list_head_guest;
|
|
XeHostList(old_list_head_flink, context)->blink_ptr = entry;
|
|
list_head->flink_ptr = entry;
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertHeadList(uint32_t list_head, uint32_t entry, VirtualTranslator context) {
|
|
XeInsertHeadList(XeHostList(list_head, context), list_head, XeHostList(entry, context), entry,
|
|
context);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertHeadList(X_LIST_ENTRY* list_head, uint32_t entry, VirtualTranslator context) {
|
|
XeInsertHeadList(list_head, XeGuestList(list_head, context), XeHostList(entry, context), entry,
|
|
context);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertHeadList(uint32_t list_head, X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
XeInsertHeadList(XeHostList(list_head, context), list_head, entry, XeGuestList(entry, context),
|
|
context);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void XeInsertHeadList(X_LIST_ENTRY* list_head, X_LIST_ENTRY* entry, VirtualTranslator context) {
|
|
XeInsertHeadList(list_head, XeGuestList(list_head, context), entry, XeGuestList(entry, context),
|
|
context);
|
|
}
|
|
|
|
// Typed intrusive list built on X_LIST_ENTRY.
|
|
// TObject is the containing struct, EntryListOffset is offsetof the
|
|
// X_LIST_ENTRY member within TObject.
|
|
template <typename TObject, size_t EntryListOffset>
|
|
struct X_TYPED_LIST : public X_LIST_ENTRY {
|
|
using this_type = X_TYPED_LIST<TObject, EntryListOffset>;
|
|
|
|
static X_LIST_ENTRY* ObjectListEntry(TObject* obj) {
|
|
return reinterpret_cast<X_LIST_ENTRY*>(
|
|
&reinterpret_cast<char*>(obj)[static_cast<ptrdiff_t>(EntryListOffset)]);
|
|
}
|
|
|
|
static TObject* ListEntryObject(X_LIST_ENTRY* entry) {
|
|
return reinterpret_cast<TObject*>(
|
|
&reinterpret_cast<char*>(entry)[-static_cast<ptrdiff_t>(EntryListOffset)]);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
struct ForwardIterator {
|
|
VirtualTranslator vt;
|
|
uint32_t current_entry;
|
|
|
|
ForwardIterator& operator++() {
|
|
current_entry = vt->template TranslateVirtual<X_LIST_ENTRY*>(current_entry)->flink_ptr;
|
|
return *this;
|
|
}
|
|
|
|
bool operator!=(uint32_t other_ptr) const { return current_entry != other_ptr; }
|
|
|
|
TObject& operator*() {
|
|
return *ListEntryObject(vt->template TranslateVirtual<X_LIST_ENTRY*>(current_entry));
|
|
}
|
|
};
|
|
|
|
template <typename VirtualTranslator>
|
|
struct ForwardIteratorBegin {
|
|
VirtualTranslator vt;
|
|
this_type* const thiz;
|
|
|
|
ForwardIterator<VirtualTranslator> begin() {
|
|
return ForwardIterator<VirtualTranslator>{vt, thiz->flink_ptr};
|
|
}
|
|
|
|
uint32_t end() { return vt->HostToGuestVirtual(thiz); }
|
|
};
|
|
|
|
template <typename VirtualTranslator>
|
|
ForwardIteratorBegin<VirtualTranslator> IterateForward(VirtualTranslator vt) {
|
|
return ForwardIteratorBegin<VirtualTranslator>{vt, this};
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void Initialize(VirtualTranslator translator) {
|
|
XeInitializeListHead(this, translator);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void InsertHead(TObject* entry, VirtualTranslator translator) {
|
|
XeInsertHeadList(static_cast<X_LIST_ENTRY*>(this), ObjectListEntry(entry), translator);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
void InsertTail(TObject* entry, VirtualTranslator translator) {
|
|
XeInsertTailList(this, ObjectListEntry(entry), translator);
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
bool empty(VirtualTranslator vt) const {
|
|
return vt->template TranslateVirtual<X_LIST_ENTRY*>(flink_ptr) == this;
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
TObject* HeadObject(VirtualTranslator vt) {
|
|
return ListEntryObject(vt->template TranslateVirtual<X_LIST_ENTRY*>(flink_ptr));
|
|
}
|
|
|
|
template <typename VirtualTranslator>
|
|
TObject* TailObject(VirtualTranslator vt) {
|
|
return ListEntryObject(vt->template TranslateVirtual<X_LIST_ENTRY*>(blink_ptr));
|
|
}
|
|
};
|
|
|
|
} // namespace rex::system::util
|