Start of DPCs. Queuing them, but not yet dispatching.
This commit is contained in:
parent
27d4938cc2
commit
c50fbafbd9
|
@ -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_);
|
||||
}
|
|
@ -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_
|
|
@ -10,6 +10,7 @@
|
|||
#include <xenia/kernel/kernel_state.h>
|
||||
|
||||
#include <xenia/emulator.h>
|
||||
#include <xenia/kernel/dispatcher.h>
|
||||
#include <xenia/kernel/xam_module.h>
|
||||
#include <xenia/kernel/xboxkrnl_module.h>
|
||||
#include <xenia/kernel/xboxkrnl_private.h>
|
||||
|
@ -35,6 +36,8 @@ KernelState::KernelState(Emulator* emulator) :
|
|||
processor_ = emulator->processor();
|
||||
file_system_ = emulator->file_system();
|
||||
|
||||
dispatcher_ = new Dispatcher(this);
|
||||
|
||||
object_table_ = new ObjectTable();
|
||||
object_mutex_ = xe_mutex_alloc(10000);
|
||||
|
||||
|
@ -49,6 +52,8 @@ KernelState::~KernelState() {
|
|||
xe_mutex_free(object_mutex_);
|
||||
delete object_table_;
|
||||
|
||||
delete dispatcher_;
|
||||
|
||||
XEASSERT(shared_kernel_state_ == this);
|
||||
shared_kernel_state_ = NULL;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
XEDECLARECLASS1(xe, Emulator);
|
||||
XEDECLARECLASS2(xe, cpu, Processor);
|
||||
XEDECLARECLASS2(xe, kernel, Dispatcher);
|
||||
XEDECLARECLASS2(xe, kernel, XModule);
|
||||
XEDECLARECLASS2(xe, kernel, XThread);
|
||||
XEDECLARECLASS2(xe, kernel, XUserModule);
|
||||
|
@ -43,6 +44,8 @@ public:
|
|||
cpu::Processor* processor() const { return processor_; }
|
||||
fs::FileSystem* file_system() const { return file_system_; }
|
||||
|
||||
Dispatcher* dispatcher() const { return dispatcher_; }
|
||||
|
||||
ObjectTable* object_table() const { return object_table_; }
|
||||
|
||||
XModule* GetModule(const char* name);
|
||||
|
@ -59,6 +62,8 @@ private:
|
|||
cpu::Processor* processor_;
|
||||
fs::FileSystem* file_system_;
|
||||
|
||||
Dispatcher* dispatcher_;
|
||||
|
||||
ObjectTable* object_table_;
|
||||
xe_mutex_t* object_mutex_;
|
||||
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_
|
|
@ -3,10 +3,14 @@
|
|||
'sources': [
|
||||
'async_request.cc',
|
||||
'async_request.h',
|
||||
'dispatcher.cc',
|
||||
'dispatcher.h',
|
||||
'kernel.h',
|
||||
'kernel_state.cc',
|
||||
'kernel_state.h',
|
||||
'modules.h',
|
||||
'native_list.cc',
|
||||
'native_list.h',
|
||||
'object_table.cc',
|
||||
'object_table.h',
|
||||
'xam_content.cc',
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
|
||||
#include <xenia/kernel/xboxkrnl_threading.h>
|
||||
|
||||
#include <xenia/kernel/dispatcher.h>
|
||||
#include <xenia/kernel/kernel_state.h>
|
||||
#include <xenia/kernel/native_list.h>
|
||||
#include <xenia/kernel/xboxkrnl_private.h>
|
||||
#include <xenia/kernel/objects/xevent.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 xe
|
||||
|
||||
|
@ -1381,4 +1469,8 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports(
|
|||
|
||||
SHIM_SET_MAPPING("xboxkrnl.exe", KeEnterCriticalRegion, 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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue