Start of DPCs. Queuing them, but not yet dispatching.

This commit is contained in:
Ben Vanik 2014-01-11 21:40:23 -08:00
parent 27d4938cc2
commit c50fbafbd9
8 changed files with 318 additions and 0 deletions

View File

@ -0,0 +1,37 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#include <xenia/kernel/dispatcher.h>
#include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/native_list.h>
using namespace xe;
using namespace xe::kernel;
Dispatcher::Dispatcher(KernelState* kernel_state) :
kernel_state_(kernel_state) {
lock_ = xe_mutex_alloc();
dpc_list_ = new NativeList(kernel_state->memory());
}
Dispatcher::~Dispatcher() {
delete dpc_list_;
xe_mutex_free(lock_);
}
void Dispatcher::Lock() {
xe_mutex_lock(lock_);
}
void Dispatcher::Unlock() {
xe_mutex_unlock(lock_);
}

View File

@ -0,0 +1,52 @@
/**
******************************************************************************
* 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_XBOXKRNL_DISPATCHER_H_
#define XENIA_KERNEL_XBOXKRNL_DISPATCHER_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
class KernelState;
class NativeList;
class Dispatcher {
public:
Dispatcher(KernelState* kernel_state);
virtual ~Dispatcher();
KernelState* kernel_state() const { return kernel_state_; }
void Lock();
void Unlock();
NativeList* dpc_list() const { return dpc_list_; }
private:
private:
KernelState* kernel_state_;
xe_mutex_t* lock_;
NativeList* dpc_list_;
};
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_DISPATCHER_H_

View File

@ -10,6 +10,7 @@
#include <xenia/kernel/kernel_state.h> #include <xenia/kernel/kernel_state.h>
#include <xenia/emulator.h> #include <xenia/emulator.h>
#include <xenia/kernel/dispatcher.h>
#include <xenia/kernel/xam_module.h> #include <xenia/kernel/xam_module.h>
#include <xenia/kernel/xboxkrnl_module.h> #include <xenia/kernel/xboxkrnl_module.h>
#include <xenia/kernel/xboxkrnl_private.h> #include <xenia/kernel/xboxkrnl_private.h>
@ -35,6 +36,8 @@ KernelState::KernelState(Emulator* emulator) :
processor_ = emulator->processor(); processor_ = emulator->processor();
file_system_ = emulator->file_system(); file_system_ = emulator->file_system();
dispatcher_ = new Dispatcher(this);
object_table_ = new ObjectTable(); object_table_ = new ObjectTable();
object_mutex_ = xe_mutex_alloc(10000); object_mutex_ = xe_mutex_alloc(10000);
@ -49,6 +52,8 @@ KernelState::~KernelState() {
xe_mutex_free(object_mutex_); xe_mutex_free(object_mutex_);
delete object_table_; delete object_table_;
delete dispatcher_;
XEASSERT(shared_kernel_state_ == this); XEASSERT(shared_kernel_state_ == this);
shared_kernel_state_ = NULL; shared_kernel_state_ = NULL;
} }

View File

@ -21,6 +21,7 @@
XEDECLARECLASS1(xe, Emulator); XEDECLARECLASS1(xe, Emulator);
XEDECLARECLASS2(xe, cpu, Processor); XEDECLARECLASS2(xe, cpu, Processor);
XEDECLARECLASS2(xe, kernel, Dispatcher);
XEDECLARECLASS2(xe, kernel, XModule); XEDECLARECLASS2(xe, kernel, XModule);
XEDECLARECLASS2(xe, kernel, XThread); XEDECLARECLASS2(xe, kernel, XThread);
XEDECLARECLASS2(xe, kernel, XUserModule); XEDECLARECLASS2(xe, kernel, XUserModule);
@ -43,6 +44,8 @@ public:
cpu::Processor* processor() const { return processor_; } cpu::Processor* processor() const { return processor_; }
fs::FileSystem* file_system() const { return file_system_; } fs::FileSystem* file_system() const { return file_system_; }
Dispatcher* dispatcher() const { return dispatcher_; }
ObjectTable* object_table() const { return object_table_; } ObjectTable* object_table() const { return object_table_; }
XModule* GetModule(const char* name); XModule* GetModule(const char* name);
@ -59,6 +62,8 @@ private:
cpu::Processor* processor_; cpu::Processor* processor_;
fs::FileSystem* file_system_; fs::FileSystem* file_system_;
Dispatcher* dispatcher_;
ObjectTable* object_table_; ObjectTable* object_table_;
xe_mutex_t* object_mutex_; xe_mutex_t* object_mutex_;
std::unordered_map<uint32_t, XThread*> threads_by_id_; std::unordered_map<uint32_t, XThread*> threads_by_id_;

View File

@ -0,0 +1,68 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#include <xenia/kernel/native_list.h>
using namespace xe;
using namespace xe::kernel;
NativeList::NativeList(Memory* memory) :
memory_(memory),
head_(kInvalidPointer) {
}
void NativeList::Insert(uint32_t ptr) {
uint8_t* mem = memory_->membase();
XESETUINT32BE(mem + ptr + 4, head_);
XESETUINT32BE(mem + ptr + 8, 0);
if (head_) {
XESETUINT32BE(mem + head_ + 8, ptr);
}
head_ = ptr;
}
bool NativeList::IsQueued(uint32_t ptr) {
uint8_t* mem = memory_->membase();
uint32_t flink = XEGETUINT32BE(mem + ptr + 4);
uint32_t blink = XEGETUINT32BE(mem + ptr + 8);
return head_ == ptr || flink || blink;
}
void NativeList::Remove(uint32_t ptr) {
uint8_t* mem = memory_->membase();
uint32_t flink = XEGETUINT32BE(mem + ptr + 4);
uint32_t blink = XEGETUINT32BE(mem + ptr + 8);
if (ptr == head_) {
head_ = flink;
if (flink) {
XESETUINT32BE(mem + flink + 8, 0);
}
} else {
if (blink) {
XESETUINT32BE(mem + blink + 4, flink);
}
if (flink) {
XESETUINT32BE(mem + flink + 8, blink);
}
}
XESETUINT32BE(mem + ptr + 4, 0);
XESETUINT32BE(mem + ptr + 8, 0);
}
uint32_t NativeList::Shift() {
if (!head_) {
return 0;
}
uint32_t ptr = head_;
Remove(ptr);
return ptr;
}

View File

@ -0,0 +1,55 @@
/**
******************************************************************************
* 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_XBOXKRNL_NATIVE_LIST_H_
#define XENIA_KERNEL_XBOXKRNL_NATIVE_LIST_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
// 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.
// Entries, as kernel objects, are assumed to have a LIST_ENTRY struct at +4b.
// struct MYOBJ {
// uint32_t stuff;
// LIST_ENTRY list_entry; <-- manipulated
// ...
// }
class NativeList {
public:
NativeList(Memory* memory);
void Insert(uint32_t ptr);
bool IsQueued(uint32_t ptr);
void Remove(uint32_t ptr);
uint32_t Shift();
private:
const uint32_t kInvalidPointer = 0xE0FE0FFF;
private:
Memory* memory_;
uint32_t head_;
};
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_NATIVE_LIST_H_

View File

@ -3,10 +3,14 @@
'sources': [ 'sources': [
'async_request.cc', 'async_request.cc',
'async_request.h', 'async_request.h',
'dispatcher.cc',
'dispatcher.h',
'kernel.h', 'kernel.h',
'kernel_state.cc', 'kernel_state.cc',
'kernel_state.h', 'kernel_state.h',
'modules.h', 'modules.h',
'native_list.cc',
'native_list.h',
'object_table.cc', 'object_table.cc',
'object_table.h', 'object_table.h',
'xam_content.cc', 'xam_content.cc',

View File

@ -9,7 +9,9 @@
#include <xenia/kernel/xboxkrnl_threading.h> #include <xenia/kernel/xboxkrnl_threading.h>
#include <xenia/kernel/dispatcher.h>
#include <xenia/kernel/kernel_state.h> #include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/native_list.h>
#include <xenia/kernel/xboxkrnl_private.h> #include <xenia/kernel/xboxkrnl_private.h>
#include <xenia/kernel/objects/xevent.h> #include <xenia/kernel/objects/xevent.h>
#include <xenia/kernel/objects/xmutant.h> #include <xenia/kernel/objects/xmutant.h>
@ -1321,6 +1323,92 @@ SHIM_CALL KeLeaveCriticalRegion_shim(
} }
SHIM_CALL KeInitializeDpc_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t dpc_ptr = SHIM_GET_ARG_32(0);
uint32_t routine = SHIM_GET_ARG_32(1);
uint32_t context = SHIM_GET_ARG_32(2);
XELOGD(
"KeInitializeDpc(%.8X, %.8X, %.8X)",
dpc_ptr, routine, context);
// KDPC (maybe) 0x18 bytes?
uint32_t type = 0;
uint32_t importance = 0;
uint32_t number = 0;
SHIM_SET_MEM_32(dpc_ptr + 0,
(type << 24) | (importance << 16) | (number));
SHIM_SET_MEM_32(dpc_ptr + 4, 0); // flink
SHIM_SET_MEM_32(dpc_ptr + 8, 0); // blink
SHIM_SET_MEM_32(dpc_ptr + 12, routine);
SHIM_SET_MEM_32(dpc_ptr + 16, context);
SHIM_SET_MEM_32(dpc_ptr + 20, 0); // arg1
SHIM_SET_MEM_32(dpc_ptr + 24, 0); // arg2
}
SHIM_CALL KeInsertQueueDpc_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t dpc_ptr = SHIM_GET_ARG_32(0);
uint32_t arg1 = SHIM_GET_ARG_32(1);
uint32_t arg2 = SHIM_GET_ARG_32(2);
XELOGD(
"KeInsertQueueDpc(%.8X, %.8X, %.8X)",
dpc_ptr, arg1, arg2);
// Lock dispatcher.
auto dispatcher = state->dispatcher();
dispatcher->Lock();
auto dpc_list = dispatcher->dpc_list();
// If already in a queue, abort.
if (dpc_list->IsQueued(dpc_ptr)) {
SHIM_SET_RETURN(0);
dispatcher->Unlock();
return;
}
// Prep DPC.
SHIM_SET_MEM_32(dpc_ptr + 20, arg1);
SHIM_SET_MEM_32(dpc_ptr + 24, arg2);
dpc_list->Insert(dpc_ptr);
dispatcher->Unlock();
SHIM_SET_RETURN(1);
}
SHIM_CALL KeRemoveQueueDpc_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t dpc_ptr = SHIM_GET_ARG_32(0);
XELOGD(
"KeRemoveQueueDpc(%.8X)",
dpc_ptr);
bool result = false;
auto dispatcher = state->dispatcher();
dispatcher->Lock();
auto dpc_list = dispatcher->dpc_list();
if (dpc_list->IsQueued(dpc_ptr)) {
dpc_list->Remove(dpc_ptr);
result = true;
}
dispatcher->Unlock();
SHIM_SET_RETURN(result ? 1 : 0);
}
} // namespace kernel } // namespace kernel
} // namespace xe } // namespace xe
@ -1381,4 +1469,8 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports(
SHIM_SET_MAPPING("xboxkrnl.exe", KeEnterCriticalRegion, state); SHIM_SET_MAPPING("xboxkrnl.exe", KeEnterCriticalRegion, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeLeaveCriticalRegion, state); SHIM_SET_MAPPING("xboxkrnl.exe", KeLeaveCriticalRegion, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeInitializeDpc, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeInsertQueueDpc, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeRemoveQueueDpc, state);
} }