/** ****************************************************************************** * 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. * ****************************************************************************** */ #ifndef XENIA_KERNEL_XOBJECT_H_ #define XENIA_KERNEL_XOBJECT_H_ #include #include #include #include #include "xenia/base/threading.h" #include "xenia/memory.h" #include "xenia/xbox.h" namespace xe { class ByteStream; class Emulator; } // namespace xe namespace xe { namespace kernel { class KernelState; template class object_ref; // http://www.nirsoft.net/kernel_struct/vista/DISPATCHER_HEADER.html typedef struct { struct { uint8_t type; union { uint8_t abandoned; uint8_t absolute; uint8_t npx_irql; uint8_t signalling; }; union { uint8_t size; uint8_t hand; }; union { uint8_t inserted; uint8_t debug_active; uint8_t dpc_active; }; }; xe::be signal_state; xe::be wait_list_flink; xe::be wait_list_blink; } X_DISPATCH_HEADER; static_assert_size(X_DISPATCH_HEADER, 0x10); // http://www.nirsoft.net/kernel_struct/vista/OBJECT_HEADER.html struct X_OBJECT_HEADER { xe::be pointer_count; union { xe::be handle_count; xe::be next_to_free; }; uint8_t name_info_offset; uint8_t handle_info_offset; uint8_t quota_info_offset; uint8_t flags; union { xe::be object_create_info; // X_OBJECT_CREATE_INFORMATION xe::be quota_block_charged; }; xe::be object_type_ptr; // -0x8 POBJECT_TYPE xe::be unk_04; // -0x4 // Object lives after this header. // (There's actually a body field here which is the object itself) }; // http://www.nirsoft.net/kernel_struct/vista/OBJECT_CREATE_INFORMATION.html struct X_OBJECT_CREATE_INFORMATION { xe::be attributes; // 0x0 xe::be root_directory_ptr; // 0x4 xe::be parse_context_ptr; // 0x8 xe::be probe_mode; // 0xC xe::be paged_pool_charge; // 0x10 xe::be non_paged_pool_charge; // 0x14 xe::be security_descriptor_charge; // 0x18 xe::be security_descriptor; // 0x1C xe::be security_qos_ptr; // 0x20 // Security QoS here (SECURITY_QUALITY_OF_SERVICE) too! }; struct X_OBJECT_TYPE { xe::be constructor; // 0x0 xe::be destructor; // 0x4 xe::be unk_08; // 0x8 xe::be unk_0C; // 0xC xe::be unk_10; // 0x10 xe::be unk_14; // 0x14 probably offset from ntobject to keobject xe::be pool_tag; // 0x18 }; class XObject { public: enum Type { kTypeUndefined, kTypeEnumerator, kTypeEvent, kTypeFile, kTypeIOCompletion, kTypeModule, kTypeMutant, kTypeNotifyListener, kTypeSemaphore, kTypeSession, kTypeSocket, kTypeThread, kTypeTimer, }; XObject(KernelState* kernel_state, Type type); virtual ~XObject(); Emulator* emulator() const; KernelState* kernel_state() const; Memory* memory() const; Type type(); // Returns the primary handle of this object. X_HANDLE handle() const { return handles_[0]; } // Returns all associated handles with this object. std::vector handles() const { return handles_; } std::vector& handles() { return handles_; } const std::string& name() const { return name_; } uint32_t guest_object() const { return guest_object_ptr_; } // Has this object been created for use by the host? // Host objects are persisted through reloads/etc. bool host_object() const { return host_object_; } void set_host_object(bool host_object) { host_object_ = host_object; } template T* guest_object() { return memory()->TranslateVirtual(guest_object_ptr_); } void RetainHandle(); bool ReleaseHandle(); void Retain(); void Release(); X_STATUS Delete(); virtual bool Save(ByteStream* stream) { return false; } static object_ref Restore(KernelState* kernel_state, Type type, ByteStream* stream); // Reference() // Dereference() void SetAttributes(uint32_t obj_attributes_ptr); X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable, uint64_t* opt_timeout); static X_STATUS SignalAndWait(XObject* signal_object, XObject* wait_object, uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable, uint64_t* opt_timeout); static X_STATUS WaitMultiple(uint32_t count, XObject** objects, uint32_t wait_type, uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable, uint64_t* opt_timeout); static object_ref GetNativeObject(KernelState* kernel_state, void* native_ptr, int32_t as_type = -1); template static object_ref GetNativeObject(KernelState* kernel_state, void* native_ptr, int32_t as_type = -1); virtual xe::threading::WaitHandle* GetWaitHandle() { return nullptr; } protected: bool SaveObject(ByteStream* stream); bool RestoreObject(ByteStream* stream); // Creates the kernel object for guest code to use. Typically not needed. uint8_t* CreateNative(uint32_t size); void SetNativePointer(uint32_t native_ptr, bool uninitialized = false); template T* CreateNative() { return reinterpret_cast(CreateNative(sizeof(T))); } // Stash native pointer into X_DISPATCH_HEADER static void StashHandle(X_DISPATCH_HEADER* header, uint32_t handle) { header->wait_list_flink = 'XEN\0'; header->wait_list_blink = handle; } static uint32_t TimeoutTicksToMs(int64_t timeout_ticks); KernelState* kernel_state_; // Host objects are persisted through resets/etc. bool host_object_ = false; private: std::atomic pointer_ref_count_; Type type_; std::vector handles_; std::string name_; // May be zero length. // Guest pointer for kernel object. Remember: X_OBJECT_HEADER precedes this // if we allocated it! uint32_t guest_object_ptr_; bool allocated_guest_object_; }; template class object_ref { public: object_ref() noexcept : value_(nullptr) {} object_ref(std::nullptr_t) noexcept // NOLINT(runtime/explicit) : value_(nullptr) {} object_ref& operator=(std::nullptr_t) noexcept { reset(); return (*this); } explicit object_ref(T* value) noexcept : value_(value) { // Assumes retained on call. } explicit object_ref(const object_ref& right) noexcept { reset(right.get()); if (value_) value_->Retain(); } template ::value, void>::type> object_ref(const object_ref& right) noexcept { reset(right.get()); if (value_) value_->Retain(); } object_ref(object_ref&& right) noexcept : value_(right.release()) {} object_ref& operator=(object_ref&& right) noexcept { object_ref(std::move(right)).swap(*this); return (*this); } template object_ref& operator=(object_ref&& right) noexcept { object_ref(std::move(right)).swap(*this); return (*this); } object_ref& operator=(const object_ref& right) noexcept { object_ref(right).swap(*this); // NOLINT(runtime/explicit): misrecognized? return (*this); } template object_ref& operator=(const object_ref& right) noexcept { object_ref(right).swap(*this); // NOLINT(runtime/explicit): misrecognized? return (*this); } void swap(object_ref& right) noexcept { std::swap(value_, right.value_); } ~object_ref() noexcept { if (value_) { value_->Release(); value_ = nullptr; } } typename std::add_lvalue_reference::type operator*() const { return (*get()); } T* operator->() const noexcept { return std::pointer_traits::pointer_to(**this); } T* get() const noexcept { return value_; } template V* get() const noexcept { return reinterpret_cast(value_); } explicit operator bool() const noexcept { return value_ != nullptr; } T* release() noexcept { T* value = value_; value_ = nullptr; return value; } void reset() noexcept { object_ref().swap(*this); } void reset(T* value) noexcept { object_ref(value).swap(*this); } inline bool operator==(const T* right) noexcept { return value_ == right; } private: T* value_ = nullptr; }; template bool operator==(const object_ref<_Ty>& _Left, std::nullptr_t) noexcept { return (_Left.get() == reinterpret_cast<_Ty*>(0)); } template bool operator==(std::nullptr_t, const object_ref<_Ty>& _Right) noexcept { return (reinterpret_cast<_Ty*>(0) == _Right.get()); } template bool operator!=(const object_ref<_Ty>& _Left, std::nullptr_t _Right) noexcept { return (!(_Left == _Right)); } template bool operator!=(std::nullptr_t _Left, const object_ref<_Ty>& _Right) noexcept { return (!(_Left == _Right)); } template object_ref retain_object(T* ptr) { if (ptr) ptr->Retain(); return object_ref(ptr); } template object_ref XObject::GetNativeObject(KernelState* kernel_state, void* native_ptr, int32_t as_type) { return object_ref(reinterpret_cast( GetNativeObject(kernel_state, native_ptr, as_type).release())); } } // namespace kernel } // namespace xe #endif // XENIA_KERNEL_XOBJECT_H_